blob: 831721a67085af81af52f935b8cab56b782ae94d [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;
Daniel Veillarda77cf712003-05-09 23:09:55 +0000103 unsigned int tz_flag :1; /* is tzo explicitely set? */
Daniel Veillard070803b2002-05-03 07:29:38 +0000104 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 Veillardd3b9cd82003-04-09 11:24:17 +0000906 /*
907 * a '-' char could indicate this type is xs:gMonthDay or
908 * a negative time zone offset. Check for xs:gMonthDay first.
909 * Also the first three char's of a negative tzo (-MM:SS) can
910 * appear to be a valid day; so even if the day portion
911 * of the xs:gMonthDay verifies, we must insure it was not
912 * a tzo.
913 */
914 if (*cur == '-') {
915 const xmlChar *rewnd = cur;
916 cur++;
Daniel Veillard070803b2002-05-03 07:29:38 +0000917
Daniel Veillardd3b9cd82003-04-09 11:24:17 +0000918 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
919 if ((ret == 0) && ((*cur == 0) || (*cur != ':'))) {
920
921 /*
922 * we can use the VALID_MDAY macro to validate the month
923 * and day because the leap year test will flag year zero
924 * as a leap year (even though zero is an invalid year).
925 */
926 if (VALID_MDAY((&(dt->value.date)))) {
927
928 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTHDAY);
929
930 goto error;
931 }
932 }
933
934 /*
935 * not xs:gMonthDay so rewind and check if just xs:gMonth
936 * with an optional time zone.
937 */
938 cur = rewnd;
939 }
940
941 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTH);
Daniel Veillard070803b2002-05-03 07:29:38 +0000942
943 goto error;
944 }
945
946 /*
947 * It's a right-truncated date or an xs:time.
948 * Try to parse an xs:time then fallback on right-truncated dates.
949 */
950 if ((*cur >= '0') && (*cur <= '9')) {
951 ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
952 if (ret == 0) {
953 /* it's an xs:time */
954 RETURN_TYPE_IF_VALID(XML_SCHEMAS_TIME);
955 }
956 }
957
958 /* fallback on date parsing */
959 cur = dateTime;
960
961 ret = _xmlSchemaParseGYear(&(dt->value.date), &cur);
962 if (ret != 0)
963 goto error;
964
965 /* is it an xs:gYear? */
966 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEAR);
967
968 if (*cur != '-')
969 goto error;
970 cur++;
971
972 ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
973 if (ret != 0)
974 goto error;
975
976 /* is it an xs:gYearMonth? */
977 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEARMONTH);
978
979 if (*cur != '-')
980 goto error;
981 cur++;
982
983 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
984 if ((ret != 0) || !VALID_DATE((&(dt->value.date))))
985 goto error;
986
987 /* is it an xs:date? */
988 RETURN_TYPE_IF_VALID(XML_SCHEMAS_DATE);
989
990 if (*cur != 'T')
991 goto error;
992 cur++;
993
994 /* it should be an xs:dateTime */
995 ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
996 if (ret != 0)
997 goto error;
998
999 ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur);
1000 if ((ret != 0) || (*cur != 0) || !VALID_DATETIME((&(dt->value.date))))
1001 goto error;
1002
Daniel Veillard455cc072003-03-31 10:13:23 +00001003
Daniel Veillard070803b2002-05-03 07:29:38 +00001004 dt->type = XML_SCHEMAS_DATETIME;
1005
Daniel Veillard455cc072003-03-31 10:13:23 +00001006done:
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001007#if 1
1008 if ((type != XML_SCHEMAS_UNKNOWN) && (type != dt->type))
1009 goto error;
1010#else
1011 /*
1012 * insure the parsed type is equal to or less significant (right
1013 * truncated) than the desired type.
1014 */
1015 if ((type != XML_SCHEMAS_UNKNOWN) && (type != dt->type)) {
1016
1017 /* time only matches time */
1018 if ((type == XML_SCHEMAS_TIME) && (dt->type == XML_SCHEMAS_TIME))
1019 goto error;
1020
1021 if ((type == XML_SCHEMAS_DATETIME) &&
1022 ((dt->type != XML_SCHEMAS_DATE) ||
1023 (dt->type != XML_SCHEMAS_GYEARMONTH) ||
1024 (dt->type != XML_SCHEMAS_GYEAR)))
1025 goto error;
1026
1027 if ((type == XML_SCHEMAS_DATE) &&
1028 ((dt->type != XML_SCHEMAS_GYEAR) ||
1029 (dt->type != XML_SCHEMAS_GYEARMONTH)))
1030 goto error;
1031
1032 if ((type == XML_SCHEMAS_GYEARMONTH) && (dt->type != XML_SCHEMAS_GYEAR))
1033 goto error;
1034
1035 if ((type == XML_SCHEMAS_GMONTHDAY) && (dt->type != XML_SCHEMAS_GMONTH))
1036 goto error;
1037 }
Daniel Veillard455cc072003-03-31 10:13:23 +00001038#endif
1039
Daniel Veillard070803b2002-05-03 07:29:38 +00001040 if (val != NULL)
1041 *val = dt;
Daniel Veillard80b19092003-03-28 13:29:53 +00001042 else
1043 xmlSchemaFreeValue(dt);
Daniel Veillard070803b2002-05-03 07:29:38 +00001044
1045 return 0;
1046
1047error:
1048 if (dt != NULL)
1049 xmlSchemaFreeValue(dt);
1050 return 1;
1051}
1052
1053/**
Daniel Veillard5a872412002-05-22 06:40:27 +00001054 * xmlSchemaValidateDuration:
Daniel Veillard070803b2002-05-03 07:29:38 +00001055 * @type: the predefined type
1056 * @duration: string to analyze
1057 * @val: the return computed value
1058 *
1059 * Check that @duration conforms to the lexical space of the duration type.
1060 * if true a value is computed and returned in @val.
1061 *
1062 * Returns 0 if this validates, a positive error code number otherwise
1063 * and -1 in case of internal or API error.
1064 */
1065static int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00001066xmlSchemaValidateDuration (xmlSchemaTypePtr type ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +00001067 const xmlChar *duration, xmlSchemaValPtr *val) {
Daniel Veillard070803b2002-05-03 07:29:38 +00001068 const xmlChar *cur = duration;
1069 xmlSchemaValPtr dur;
1070 int isneg = 0;
1071 unsigned int seq = 0;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001072 double num;
1073 int num_type = 0; /* -1 = invalid, 0 = int, 1 = floating */
1074 const xmlChar desig[] = {'Y', 'M', 'D', 'H', 'M', 'S'};
1075 const double multi[] = { 0.0, 0.0, 86400.0, 3600.0, 60.0, 1.0, 0.0};
Daniel Veillard070803b2002-05-03 07:29:38 +00001076
1077 if (duration == NULL)
1078 return -1;
1079
1080 if (*cur == '-') {
1081 isneg = 1;
1082 cur++;
1083 }
1084
1085 /* duration must start with 'P' (after sign) */
1086 if (*cur++ != 'P')
1087 return 1;
1088
Daniel Veillard80b19092003-03-28 13:29:53 +00001089 if (*cur == 0)
1090 return 1;
1091
Daniel Veillard070803b2002-05-03 07:29:38 +00001092 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
1093 if (dur == NULL)
1094 return -1;
1095
1096 while (*cur != 0) {
Daniel Veillard070803b2002-05-03 07:29:38 +00001097
1098 /* input string should be empty or invalid date/time item */
1099 if (seq >= sizeof(desig))
1100 goto error;
1101
1102 /* T designator must be present for time items */
1103 if (*cur == 'T') {
1104 if (seq <= 3) {
1105 seq = 3;
1106 cur++;
1107 } else
1108 return 1;
1109 } else if (seq == 3)
1110 goto error;
1111
1112 /* parse the number portion of the item */
1113 PARSE_NUM(num, cur, num_type);
1114
1115 if ((num_type == -1) || (*cur == 0))
1116 goto error;
1117
1118 /* update duration based on item type */
1119 while (seq < sizeof(desig)) {
1120 if (*cur == desig[seq]) {
1121
1122 /* verify numeric type; only seconds can be float */
1123 if ((num_type != 0) && (seq < (sizeof(desig)-1)))
1124 goto error;
1125
1126 switch (seq) {
1127 case 0:
1128 dur->value.dur.mon = (long)num * 12;
1129 break;
1130 case 1:
1131 dur->value.dur.mon += (long)num;
1132 break;
1133 default:
1134 /* convert to seconds using multiplier */
1135 dur->value.dur.sec += num * multi[seq];
1136 seq++;
1137 break;
1138 }
1139
1140 break; /* exit loop */
1141 }
1142 /* no date designators found? */
1143 if (++seq == 3)
1144 goto error;
1145 }
1146 cur++;
1147 }
1148
1149 if (isneg) {
1150 dur->value.dur.mon = -dur->value.dur.mon;
1151 dur->value.dur.day = -dur->value.dur.day;
1152 dur->value.dur.sec = -dur->value.dur.sec;
1153 }
1154
1155 if (val != NULL)
1156 *val = dur;
Daniel Veillard80b19092003-03-28 13:29:53 +00001157 else
1158 xmlSchemaFreeValue(dur);
Daniel Veillard070803b2002-05-03 07:29:38 +00001159
1160 return 0;
1161
1162error:
1163 if (dur != NULL)
1164 xmlSchemaFreeValue(dur);
1165 return 1;
1166}
1167
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001168/**
1169 * xmlSchemaStrip:
1170 * @value: a value
1171 *
1172 * Removes the leading and ending spaces of a string
1173 *
1174 * Returns the new string or NULL if no change was required.
1175 */
1176static xmlChar *
1177xmlSchemaStrip(const xmlChar *value) {
1178 const xmlChar *start = value, *end, *f;
1179
1180 if (value == NULL) return(NULL);
1181 while ((*start != 0) && (IS_BLANK(*start))) start++;
1182 end = start;
1183 while (*end != 0) end++;
1184 f = end;
1185 end--;
1186 while ((end > start) && (IS_BLANK(*end))) end--;
1187 end++;
1188 if ((start == value) && (f == end)) return(NULL);
1189 return(xmlStrndup(start, end - start));
1190}
Daniel Veillard96a4b252003-02-06 08:22:32 +00001191
1192/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001193 * xmlSchemaCollapseString:
1194 * @value: a value
1195 *
1196 * Removes and normalize white spaces in the string
1197 *
1198 * Returns the new string or NULL if no change was required.
1199 */
1200static xmlChar *
1201xmlSchemaCollapseString(const xmlChar *value) {
1202 const xmlChar *start = value, *end, *f;
1203 xmlChar *g;
1204 int col = 0;
1205
1206 if (value == NULL) return(NULL);
1207 while ((*start != 0) && (IS_BLANK(*start))) start++;
1208 end = start;
1209 while (*end != 0) {
1210 if ((*end == ' ') && (IS_BLANK(end[1]))) {
1211 col = end - start;
1212 break;
1213 } else if ((*end == 0xa) || (*end == 0x9) || (*end == 0xd)) {
1214 col = end - start;
1215 break;
1216 }
1217 end++;
1218 }
1219 if (col == 0) {
1220 f = end;
1221 end--;
1222 while ((end > start) && (IS_BLANK(*end))) end--;
1223 end++;
1224 if ((start == value) && (f == end)) return(NULL);
1225 return(xmlStrndup(start, end - start));
1226 }
1227 start = xmlStrdup(start);
1228 if (start == NULL) return(NULL);
1229 g = (xmlChar *) (start + col);
1230 end = g;
1231 while (*end != 0) {
1232 if (IS_BLANK(*end)) {
1233 end++;
1234 while (IS_BLANK(*end)) end++;
1235 if (*end != 0)
1236 *g++ = ' ';
1237 } else
1238 *g++ = *end++;
1239 }
1240 *g = 0;
1241 return((xmlChar *) start);
1242}
1243
1244/**
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001245 * xmlSchemaValAtomicListNode:
1246 * @type: the predefined atomic type for a token in the list
1247 * @value: the list value to check
1248 * @ret: the return computed value
1249 * @node: the node containing the value
1250 *
1251 * Check that a value conforms to the lexical space of the predefined
1252 * list type. if true a value is computed and returned in @ret.
1253 *
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001254 * Returns the number of items if this validates, a negative error code
1255 * number otherwise
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001256 */
1257static int
1258xmlSchemaValAtomicListNode(xmlSchemaTypePtr type, const xmlChar *value,
1259 xmlSchemaValPtr *ret, xmlNodePtr node) {
1260 xmlChar *val, *cur, *endval;
1261 int nb_values = 0;
Daniel Veillard580ced82003-03-21 21:22:48 +00001262 int tmp = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001263
1264 if (value == NULL) {
1265 return(-1);
1266 }
1267 val = xmlStrdup(value);
1268 if (val == NULL) {
1269 return(-1);
1270 }
1271 cur = val;
1272 /*
1273 * Split the list
1274 */
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001275 while (IS_BLANK(*cur)) *cur++ = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001276 while (*cur != 0) {
1277 if (IS_BLANK(*cur)) {
1278 *cur = 0;
1279 cur++;
1280 while (IS_BLANK(*cur)) *cur++ = 0;
1281 } else {
1282 nb_values++;
1283 cur++;
1284 while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
1285 }
1286 }
1287 if (nb_values == 0) {
1288 if (ret != NULL) {
1289 TODO
1290 }
1291 xmlFree(val);
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001292 return(nb_values);
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001293 }
1294 endval = cur;
1295 cur = val;
1296 while ((*cur == 0) && (cur != endval)) cur++;
1297 while (cur != endval) {
1298 tmp = xmlSchemaValPredefTypeNode(type, cur, NULL, node);
1299 if (tmp != 0)
1300 break;
1301 while (*cur != 0) cur++;
1302 while ((*cur == 0) && (cur != endval)) cur++;
1303 }
1304 xmlFree(val);
1305 if (ret != NULL) {
1306 TODO
1307 }
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001308 if (tmp == 0)
1309 return(nb_values);
1310 return(-1);
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001311}
1312
1313/**
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001314 * xmlSchemaParseUInt:
1315 * @str: pointer to the string R/W
1316 * @llo: pointer to the low result
1317 * @lmi: pointer to the mid result
1318 * @lhi: pointer to the high result
1319 *
1320 * Parse an unsigned long into 3 fields.
1321 *
1322 * Returns the number of chars parsed or -1 if overflow of the capacity
1323 */
1324static int
1325xmlSchemaParseUInt(const xmlChar **str, unsigned long *llo,
1326 unsigned long *lmi, unsigned long *lhi) {
1327 unsigned long lo = 0, mi = 0, hi = 0;
1328 const xmlChar *tmp, *cur = *str;
1329 int ret = 0, i = 0;
1330
1331 while (*cur == '0') {
1332 ret++;
1333 cur++;
1334 }
1335 tmp = cur;
1336 while ((*tmp != 0) && (*tmp >= '0') && (*tmp <= '9')) {
1337 i++;tmp++;ret++;
1338 }
1339 if (i > 24) {
1340 *str = tmp;
1341 return(-1);
1342 }
1343 while (i > 16) {
1344 hi = hi * 10 + (*cur++ - '0');
1345 i--;
1346 }
1347 while (i > 8) {
1348 mi = mi * 10 + (*cur++ - '0');
1349 i--;
1350 }
1351 while (i > 0) {
1352 lo = lo * 10 + (*cur++ - '0');
1353 i--;
1354 }
1355
1356 *str = cur;
1357 *llo = lo;
1358 *lmi = mi;
1359 *lhi = hi;
1360 return(ret);
1361}
1362
1363/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001364 * xmlSchemaValAtomicType:
1365 * @type: the predefined type
1366 * @value: the value to check
1367 * @val: the return computed value
1368 * @node: the node containing the value
1369 * flags: flags to control the vlidation
1370 *
1371 * Check that a value conforms to the lexical space of the atomic type.
1372 * if true a value is computed and returned in @val.
1373 *
1374 * Returns 0 if this validates, a positive error code number otherwise
1375 * and -1 in case of internal or API error.
1376 */
1377static int
1378xmlSchemaValAtomicType(xmlSchemaTypePtr type, const xmlChar *value,
1379 xmlSchemaValPtr *val, xmlNodePtr node, int flags) {
1380 xmlSchemaValPtr v;
1381 xmlChar *norm = NULL;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001382 int ret = 0;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001383
1384 if (xmlSchemaTypesInitialized == 0)
1385 return(-1);
1386 if (type == NULL)
1387 return(-1);
1388
1389 if (val != NULL)
1390 *val = NULL;
1391 if ((flags == 0) && (value != NULL)) {
1392 if ((type->flags != XML_SCHEMAS_STRING) &&
1393 (type->flags != XML_SCHEMAS_NORMSTRING)) {
1394 norm = xmlSchemaCollapseString(value);
1395 if (norm != NULL)
1396 value = norm;
1397 }
1398 }
1399
1400 switch (type->flags) {
1401 case XML_SCHEMAS_UNKNOWN:
1402 if (type == xmlSchemaTypeAnyTypeDef)
1403 goto return0;
1404 goto error;
1405 case XML_SCHEMAS_STRING:
1406 goto return0;
1407 case XML_SCHEMAS_NORMSTRING:
1408 TODO
1409 goto return0;
1410 case XML_SCHEMAS_DECIMAL: {
1411 const xmlChar *cur = value, *tmp;
1412 int frac = 0, len, neg = 0;
1413 unsigned long base = 0;
1414 if (cur == NULL)
1415 goto return1;
1416 if (*cur == '+')
1417 cur++;
1418 else if (*cur == '-') {
1419 neg = 1;
1420 cur++;
1421 }
1422 tmp = cur;
1423 while ((*cur >= '0') && (*cur <= '9')) {
1424 base = base * 10 + (*cur - '0');
1425 cur++;
1426 }
1427 len = cur - tmp;
1428 if (*cur == '.') {
1429 cur++;
1430 tmp = cur;
1431 while ((*cur >= '0') && (*cur <= '9')) {
1432 base = base * 10 + (*cur - '0');
1433 cur++;
1434 }
1435 frac = cur - tmp;
1436 }
1437 if (*cur != 0)
1438 goto return1;
1439 if (val != NULL) {
1440 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
1441 if (v != NULL) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001442 v->value.decimal.lo = base;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001443 v->value.decimal.sign = neg;
1444 v->value.decimal.frac = frac;
1445 v->value.decimal.total = frac + len;
1446 *val = v;
1447 }
1448 }
1449 goto return0;
1450 }
1451 case XML_SCHEMAS_TIME:
1452 case XML_SCHEMAS_GDAY:
1453 case XML_SCHEMAS_GMONTH:
1454 case XML_SCHEMAS_GMONTHDAY:
1455 case XML_SCHEMAS_GYEAR:
1456 case XML_SCHEMAS_GYEARMONTH:
1457 case XML_SCHEMAS_DATE:
1458 case XML_SCHEMAS_DATETIME:
Daniel Veillard455cc072003-03-31 10:13:23 +00001459 ret = xmlSchemaValidateDates(type->flags, value, val);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001460 break;
1461 case XML_SCHEMAS_DURATION:
1462 ret = xmlSchemaValidateDuration(type, value, val);
1463 break;
1464 case XML_SCHEMAS_FLOAT:
1465 case XML_SCHEMAS_DOUBLE: {
1466 const xmlChar *cur = value;
1467 int neg = 0;
1468 if (cur == NULL)
1469 goto return1;
1470 if ((cur[0] == 'N') && (cur[1] == 'a') && (cur[2] == 'N')) {
1471 cur += 3;
1472 if (*cur != 0)
1473 goto return1;
1474 if (val != NULL) {
1475 if (type == xmlSchemaTypeFloatDef) {
1476 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1477 if (v != NULL) {
1478 v->value.f = (float) xmlXPathNAN;
1479 } else {
1480 xmlSchemaFreeValue(v);
1481 goto error;
1482 }
1483 } else {
1484 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1485 if (v != NULL) {
1486 v->value.d = xmlXPathNAN;
1487 } else {
1488 xmlSchemaFreeValue(v);
1489 goto error;
1490 }
1491 }
1492 *val = v;
1493 }
1494 goto return0;
1495 }
1496 if (*cur == '-') {
1497 neg = 1;
1498 cur++;
1499 }
1500 if ((cur[0] == 'I') && (cur[1] == 'N') && (cur[2] == 'F')) {
1501 cur += 3;
1502 if (*cur != 0)
1503 goto return1;
1504 if (val != NULL) {
1505 if (type == xmlSchemaTypeFloatDef) {
1506 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1507 if (v != NULL) {
1508 if (neg)
1509 v->value.f = (float) xmlXPathNINF;
1510 else
1511 v->value.f = (float) xmlXPathPINF;
1512 } else {
1513 xmlSchemaFreeValue(v);
1514 goto error;
1515 }
1516 } else {
1517 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1518 if (v != NULL) {
1519 if (neg)
1520 v->value.d = xmlXPathNINF;
1521 else
1522 v->value.d = xmlXPathPINF;
1523 } else {
1524 xmlSchemaFreeValue(v);
1525 goto error;
1526 }
1527 }
1528 *val = v;
1529 }
1530 goto return0;
1531 }
1532 if ((neg == 0) && (*cur == '+'))
1533 cur++;
1534 if ((cur[0] == 0) || (cur[0] == '+') || (cur[0] == '-'))
1535 goto return1;
1536 while ((*cur >= '0') && (*cur <= '9')) {
1537 cur++;
1538 }
1539 if (*cur == '.') {
1540 cur++;
1541 while ((*cur >= '0') && (*cur <= '9'))
1542 cur++;
1543 }
1544 if ((*cur == 'e') || (*cur == 'E')) {
1545 cur++;
1546 if ((*cur == '-') || (*cur == '+'))
1547 cur++;
1548 while ((*cur >= '0') && (*cur <= '9'))
1549 cur++;
1550 }
1551 if (*cur != 0)
1552 goto return1;
1553 if (val != NULL) {
1554 if (type == xmlSchemaTypeFloatDef) {
1555 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1556 if (v != NULL) {
1557 if (sscanf((const char *)value, "%f", &(v->value.f))==1) {
1558 *val = v;
1559 } else {
1560 xmlGenericError(xmlGenericErrorContext,
1561 "failed to scanf float %s\n", value);
1562 xmlSchemaFreeValue(v);
1563 goto return1;
1564 }
1565 } else {
1566 goto error;
1567 }
1568 } else {
1569 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1570 if (v != NULL) {
1571 if (sscanf((const char *)value, "%lf", &(v->value.d))==1) {
1572 *val = v;
1573 } else {
1574 xmlGenericError(xmlGenericErrorContext,
1575 "failed to scanf double %s\n", value);
1576 xmlSchemaFreeValue(v);
1577 goto return1;
1578 }
1579 } else {
1580 goto error;
1581 }
1582 }
1583 }
1584 goto return0;
1585 }
1586 case XML_SCHEMAS_BOOLEAN: {
1587 const xmlChar *cur = value;
1588
1589 if ((cur[0] == '0') && (cur[1] == 0))
1590 ret = 0;
1591 else if ((cur[0] == '1') && (cur[1] == 0))
1592 ret = 1;
1593 else if ((cur[0] == 't') && (cur[1] == 'r') && (cur[2] == 'u') &&
1594 (cur[3] == 'e') && (cur[4] == 0))
1595 ret = 1;
1596 else if ((cur[0] == 'f') && (cur[1] == 'a') && (cur[2] == 'l') &&
1597 (cur[3] == 's') && (cur[4] == 'e') && (cur[5] == 0))
1598 ret = 0;
1599 else
1600 goto return1;
1601 if (val != NULL) {
1602 v = xmlSchemaNewValue(XML_SCHEMAS_BOOLEAN);
1603 if (v != NULL) {
1604 v->value.b = ret;
1605 *val = v;
1606 } else {
1607 goto error;
1608 }
1609 }
1610 goto return0;
1611 }
1612 case XML_SCHEMAS_TOKEN: {
1613 const xmlChar *cur = value;
1614
1615 if (IS_BLANK(*cur))
1616 goto return1;
1617
1618 while (*cur != 0) {
1619 if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) {
1620 goto return1;
1621 } else if (*cur == ' ') {
1622 cur++;
1623 if (*cur == 0)
1624 goto return1;
1625 if (*cur == ' ')
1626 goto return1;
1627 } else {
1628 cur++;
1629 }
1630 }
1631 if (val != NULL) {
1632 v = xmlSchemaNewValue(XML_SCHEMAS_TOKEN);
1633 if (v != NULL) {
1634 v->value.str = xmlStrdup(value);
1635 *val = v;
1636 } else {
1637 goto error;
1638 }
1639 }
1640 goto return0;
1641 }
1642 case XML_SCHEMAS_LANGUAGE:
1643 if (xmlCheckLanguageID(value) == 1) {
1644 if (val != NULL) {
1645 v = xmlSchemaNewValue(XML_SCHEMAS_LANGUAGE);
1646 if (v != NULL) {
1647 v->value.str = xmlStrdup(value);
1648 *val = v;
1649 } else {
1650 goto error;
1651 }
1652 }
1653 goto return0;
1654 }
1655 goto return1;
1656 case XML_SCHEMAS_NMTOKEN:
1657 if (xmlValidateNMToken(value, 1) == 0) {
1658 if (val != NULL) {
1659 v = xmlSchemaNewValue(XML_SCHEMAS_NMTOKEN);
1660 if (v != NULL) {
1661 v->value.str = xmlStrdup(value);
1662 *val = v;
1663 } else {
1664 goto error;
1665 }
1666 }
1667 goto return0;
1668 }
1669 goto return1;
1670 case XML_SCHEMAS_NMTOKENS:
1671 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeNmtokenDef,
1672 value, val, node);
1673 if (ret > 0)
1674 ret = 0;
1675 else
1676 ret = 1;
1677 goto done;
1678 case XML_SCHEMAS_NAME:
1679 ret = xmlValidateName(value, 1);
1680 if ((ret == 0) && (val != NULL)) {
1681 TODO;
1682 }
1683 goto done;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001684 case XML_SCHEMAS_QNAME: {
1685 xmlChar *uri = NULL;
1686 xmlChar *local = NULL;
1687
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001688 ret = xmlValidateQName(value, 1);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001689 if ((ret == 0) && (node != NULL)) {
1690 xmlChar *prefix;
1691 local = xmlSplitQName2(value, &prefix);
1692 if (prefix != NULL) {
1693 xmlNsPtr ns;
1694
1695 ns = xmlSearchNs(node->doc, node, prefix);
1696 if (ns == NULL)
1697 ret = 1;
1698 else if (val != NULL)
1699 uri = xmlStrdup(ns->href);
1700 }
1701 if ((local != NULL) && ((val == NULL) || (ret != 0)))
1702 xmlFree(local);
1703 if (prefix != NULL)
1704 xmlFree(prefix);
1705 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001706 if ((ret == 0) && (val != NULL)) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001707 v = xmlSchemaNewValue(XML_SCHEMAS_QNAME);
1708 if (v != NULL) {
1709 if (local != NULL)
1710 v->value.qname.name = local;
1711 else
1712 v->value.qname.name = xmlStrdup(value);
1713 if (uri != NULL)
1714 v->value.qname.uri = uri;
1715
1716 *val = v;
1717 } else {
1718 if (local != NULL)
1719 xmlFree(local);
1720 if (uri != NULL)
1721 xmlFree(uri);
1722 goto error;
1723 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001724 }
1725 goto done;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001726 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001727 case XML_SCHEMAS_NCNAME:
1728 ret = xmlValidateNCName(value, 1);
1729 if ((ret == 0) && (val != NULL)) {
1730 v = xmlSchemaNewValue(XML_SCHEMAS_NCNAME);
1731 if (v != NULL) {
1732 v->value.str = xmlStrdup(value);
1733 *val = v;
1734 } else {
1735 goto error;
1736 }
1737 }
1738 goto done;
1739 case XML_SCHEMAS_ID:
1740 ret = xmlValidateNCName(value, 1);
1741 if ((ret == 0) && (val != NULL)) {
1742 TODO;
1743 }
1744 if ((ret == 0) && (node != NULL) &&
1745 (node->type == XML_ATTRIBUTE_NODE)) {
1746 xmlAttrPtr attr = (xmlAttrPtr) node;
1747 /*
1748 * NOTE: the IDness might have already be declared in the DTD
1749 */
1750 if (attr->atype != XML_ATTRIBUTE_ID) {
1751 xmlIDPtr res;
1752 xmlChar *strip;
1753
1754 strip = xmlSchemaStrip(value);
1755 if (strip != NULL) {
1756 res = xmlAddID(NULL, node->doc, strip, attr);
1757 xmlFree(strip);
1758 } else
1759 res = xmlAddID(NULL, node->doc, value, attr);
1760 if (res == NULL) {
1761 ret = 2;
1762 } else {
1763 attr->atype = XML_ATTRIBUTE_ID;
1764 }
1765 }
1766 }
1767 goto done;
1768 case XML_SCHEMAS_IDREF:
1769 ret = xmlValidateNCName(value, 1);
1770 if ((ret == 0) && (val != NULL)) {
1771 TODO;
1772 }
1773 if ((ret == 0) && (node != NULL) &&
1774 (node->type == XML_ATTRIBUTE_NODE)) {
1775 xmlAttrPtr attr = (xmlAttrPtr) node;
1776 xmlChar *strip;
1777
1778 strip = xmlSchemaStrip(value);
1779 if (strip != NULL) {
1780 xmlAddRef(NULL, node->doc, strip, attr);
1781 xmlFree(strip);
1782 } else
1783 xmlAddRef(NULL, node->doc, value, attr);
1784 attr->atype = XML_ATTRIBUTE_IDREF;
1785 }
1786 goto done;
1787 case XML_SCHEMAS_IDREFS:
1788 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeIdrefDef,
1789 value, val, node);
1790 if (ret < 0)
1791 ret = 2;
1792 else
1793 ret = 0;
1794 if ((ret == 0) && (node != NULL) &&
1795 (node->type == XML_ATTRIBUTE_NODE)) {
1796 xmlAttrPtr attr = (xmlAttrPtr) node;
1797
1798 attr->atype = XML_ATTRIBUTE_IDREFS;
1799 }
1800 goto done;
1801 case XML_SCHEMAS_ENTITY: {
1802 xmlChar *strip;
1803 ret = xmlValidateNCName(value, 1);
1804 if ((node == NULL) || (node->doc == NULL))
1805 ret = 3;
1806 if (ret == 0) {
1807 xmlEntityPtr ent;
1808
1809 strip = xmlSchemaStrip(value);
1810 if (strip != NULL) {
1811 ent = xmlGetDocEntity(node->doc, strip);
1812 xmlFree(strip);
1813 } else {
1814 ent = xmlGetDocEntity(node->doc, value);
1815 }
1816 if ((ent == NULL) ||
1817 (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY))
1818 ret = 4;
1819 }
1820 if ((ret == 0) && (val != NULL)) {
1821 TODO;
1822 }
1823 if ((ret == 0) && (node != NULL) &&
1824 (node->type == XML_ATTRIBUTE_NODE)) {
1825 xmlAttrPtr attr = (xmlAttrPtr) node;
1826
1827 attr->atype = XML_ATTRIBUTE_ENTITY;
1828 }
1829 goto done;
1830 }
1831 case XML_SCHEMAS_ENTITIES:
1832 if ((node == NULL) || (node->doc == NULL))
1833 goto return3;
1834 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeEntityDef,
1835 value, val, node);
1836 if (ret <= 0)
1837 ret = 1;
1838 else
1839 ret = 0;
1840 if ((ret == 0) && (node != NULL) &&
1841 (node->type == XML_ATTRIBUTE_NODE)) {
1842 xmlAttrPtr attr = (xmlAttrPtr) node;
1843
1844 attr->atype = XML_ATTRIBUTE_ENTITIES;
1845 }
1846 goto done;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001847 case XML_SCHEMAS_NOTATION: {
1848 xmlChar *uri = NULL;
1849 xmlChar *local = NULL;
1850
1851 ret = xmlValidateQName(value, 1);
1852 if ((ret == 0) && (node != NULL)) {
1853 xmlChar *prefix;
1854 local = xmlSplitQName2(value, &prefix);
1855 if (prefix != NULL) {
1856 xmlNsPtr ns;
1857
1858 ns = xmlSearchNs(node->doc, node, prefix);
1859 if (ns == NULL)
1860 ret = 1;
1861 else if (val != NULL)
1862 uri = xmlStrdup(ns->href);
1863 }
1864 if ((local != NULL) && ((val == NULL) || (ret != 0)))
1865 xmlFree(local);
1866 if (prefix != NULL)
1867 xmlFree(prefix);
1868 }
1869 if ((node == NULL) || (node->doc == NULL))
1870 ret = 3;
1871 if (ret == 0) {
1872 ret = xmlValidateNotationUse(NULL, node->doc, value);
1873 if (ret == 1)
1874 ret = 0;
1875 else
1876 ret = 1;
1877 }
1878 if ((ret == 0) && (val != NULL)) {
1879 v = xmlSchemaNewValue(XML_SCHEMAS_NOTATION);
1880 if (v != NULL) {
1881 if (local != NULL)
1882 v->value.qname.name = local;
1883 else
1884 v->value.qname.name = xmlStrdup(value);
1885 if (uri != NULL)
1886 v->value.qname.uri = uri;
1887
1888 *val = v;
1889 } else {
1890 if (local != NULL)
1891 xmlFree(local);
1892 if (uri != NULL)
1893 xmlFree(uri);
1894 goto error;
1895 }
1896 }
1897 goto done;
1898 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001899 case XML_SCHEMAS_ANYURI: {
1900 xmlURIPtr uri;
1901
1902 uri = xmlParseURI((const char *) value);
1903 if (uri == NULL)
1904 goto return1;
1905 if (val != NULL) {
1906 TODO;
1907 }
1908 xmlFreeURI(uri);
1909 goto return0;
1910 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001911 case XML_SCHEMAS_INTEGER:
1912 case XML_SCHEMAS_PINTEGER:
1913 case XML_SCHEMAS_NPINTEGER:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001914 case XML_SCHEMAS_NINTEGER:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001915 case XML_SCHEMAS_NNINTEGER: {
1916 const xmlChar *cur = value;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001917 unsigned long lo, mi, hi;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001918 int sign = 0;
1919 if (cur == NULL)
1920 goto return1;
1921 if (*cur == '-') {
1922 sign = 1;
1923 cur++;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001924 } else if (*cur == '+')
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001925 cur++;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001926 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
1927 if (ret == 0)
1928 goto return1;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001929 if (*cur != 0)
1930 goto return1;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001931 if (type->flags == XML_SCHEMAS_NPINTEGER) {
1932 if ((sign == 0) &&
1933 ((hi != 0) || (mi != 0) || (lo != 0)))
1934 goto return1;
1935 } else if (type->flags == XML_SCHEMAS_PINTEGER) {
1936 if (sign == 1)
1937 goto return1;
1938 if ((hi == 0) && (mi == 0) && (lo == 0))
1939 goto return1;
1940 } else if (type->flags == XML_SCHEMAS_NINTEGER) {
1941 if (sign == 0)
1942 goto return1;
1943 if ((hi == 0) && (mi == 0) && (lo == 0))
1944 goto return1;
1945 } else if (type->flags == XML_SCHEMAS_NNINTEGER) {
1946 if ((sign == 1) &&
1947 ((hi != 0) || (mi != 0) || (lo != 0)))
1948 goto return1;
1949 }
1950 /*
1951 * We can store a value only if no overflow occured
1952 */
1953 if ((ret > 0) && (val != NULL)) {
1954 v = xmlSchemaNewValue(type->flags);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001955 if (v != NULL) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001956 v->value.decimal.lo = lo;
1957 v->value.decimal.mi = lo;
1958 v->value.decimal.hi = lo;
1959 v->value.decimal.sign = sign;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001960 v->value.decimal.frac = 0;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001961 v->value.decimal.total = cur - value;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001962 *val = v;
1963 }
1964 }
1965 goto return0;
1966 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001967 case XML_SCHEMAS_LONG:
1968 case XML_SCHEMAS_BYTE:
1969 case XML_SCHEMAS_SHORT:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001970 case XML_SCHEMAS_INT: {
1971 const xmlChar *cur = value;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001972 unsigned long lo, mi, hi;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001973 int total = 0;
1974 int sign = 0;
1975 if (cur == NULL)
1976 goto return1;
1977 if (*cur == '-') {
1978 sign = 1;
1979 cur++;
1980 } else if (*cur == '+')
1981 cur++;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001982 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
1983 if (ret <= 0)
1984 goto return1;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001985 if (*cur != 0)
1986 goto return1;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001987 if (type->flags == XML_SCHEMAS_LONG) {
1988 if (hi >= 922) {
1989 if (hi > 922)
1990 goto return1;
1991 if (mi >= 33720368) {
1992 if (mi > 33720368)
1993 goto return1;
1994 if ((sign == 0) && (lo > 54775807))
1995 goto return1;
1996 if ((sign == 1) && (lo > 54775808))
1997 goto return1;
1998 }
1999 }
2000 } else if (type->flags == XML_SCHEMAS_INT) {
2001 if (hi != 0)
2002 goto return1;
2003 if (mi >= 21) {
2004 if (mi > 21)
2005 goto return1;
2006 if ((sign == 0) && (lo > 47483647))
2007 goto return1;
2008 if ((sign == 1) && (lo > 47483648))
2009 goto return1;
2010 }
2011 } else if (type->flags == XML_SCHEMAS_SHORT) {
2012 if ((mi != 0) || (hi != 0))
2013 goto return1;
2014 if ((sign == 1) && (lo > 32768))
2015 goto return1;
2016 if ((sign == 0) && (lo > 32767))
2017 goto return1;
2018 } else if (type->flags == XML_SCHEMAS_BYTE) {
2019 if ((mi != 0) || (hi != 0))
2020 goto return1;
2021 if ((sign == 1) && (lo > 128))
2022 goto return1;
2023 if ((sign == 0) && (lo > 127))
2024 goto return1;
2025 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002026 if (val != NULL) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002027 v = xmlSchemaNewValue(type->flags);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002028 if (v != NULL) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002029 v->value.decimal.lo = lo;
2030 v->value.decimal.mi = lo;
2031 v->value.decimal.hi = lo;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002032 v->value.decimal.sign = sign;
2033 v->value.decimal.frac = 0;
2034 v->value.decimal.total = total;
2035 *val = v;
2036 }
2037 }
2038 goto return0;
2039 }
2040 case XML_SCHEMAS_UINT:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002041 case XML_SCHEMAS_ULONG:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002042 case XML_SCHEMAS_USHORT:
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002043 case XML_SCHEMAS_UBYTE: {
2044 const xmlChar *cur = value;
2045 unsigned long lo, mi, hi;
2046 int total = 0;
2047 if (cur == NULL)
2048 goto return1;
2049 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2050 if (ret <= 0)
2051 goto return1;
2052 if (*cur != 0)
2053 goto return1;
2054 if (type->flags == XML_SCHEMAS_ULONG) {
2055 if (hi >= 1844) {
2056 if (hi > 1844)
2057 goto return1;
2058 if (mi >= 67440737) {
2059 if (mi > 67440737)
2060 goto return1;
2061 if (lo > 9551615)
2062 goto return1;
2063 }
2064 }
2065 } else if (type->flags == XML_SCHEMAS_UINT) {
2066 if (hi != 0)
2067 goto return1;
2068 if (mi >= 42) {
2069 if (mi > 42)
2070 goto return1;
2071 if (lo > 94967295)
2072 goto return1;
2073 }
2074 } else if (type->flags == XML_SCHEMAS_USHORT) {
2075 if ((mi != 0) || (hi != 0))
2076 goto return1;
2077 if (lo > 65535)
2078 goto return1;
2079 } else if (type->flags == XML_SCHEMAS_UBYTE) {
2080 if ((mi != 0) || (hi != 0))
2081 goto return1;
2082 if (lo > 255)
2083 goto return1;
2084 }
2085 if (val != NULL) {
2086 v = xmlSchemaNewValue(type->flags);
2087 if (v != NULL) {
2088 v->value.decimal.lo = lo;
2089 v->value.decimal.mi = mi;
2090 v->value.decimal.hi = hi;
2091 v->value.decimal.sign = 0;
2092 v->value.decimal.frac = 0;
2093 v->value.decimal.total = total;
2094 *val = v;
2095 }
2096 }
2097 goto return0;
2098 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002099 }
2100
2101done:
2102 if (norm != NULL) xmlFree(norm);
2103 return(ret);
2104return3:
2105 if (norm != NULL) xmlFree(norm);
2106 return(3);
2107return1:
2108 if (norm != NULL) xmlFree(norm);
2109 return(1);
2110return0:
2111 if (norm != NULL) xmlFree(norm);
2112 return(0);
2113error:
2114 if (norm != NULL) xmlFree(norm);
2115 return(-1);
2116}
2117
2118/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002119 * xmlSchemaValPredefTypeNode:
Daniel Veillard4255d502002-04-16 15:50:10 +00002120 * @type: the predefined type
2121 * @value: the value to check
2122 * @val: the return computed value
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002123 * @node: the node containing the value
Daniel Veillard4255d502002-04-16 15:50:10 +00002124 *
2125 * Check that a value conforms to the lexical space of the predefined type.
2126 * if true a value is computed and returned in @val.
2127 *
2128 * Returns 0 if this validates, a positive error code number otherwise
2129 * and -1 in case of internal or API error.
2130 */
2131int
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002132xmlSchemaValPredefTypeNode(xmlSchemaTypePtr type, const xmlChar *value,
2133 xmlSchemaValPtr *val, xmlNodePtr node) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002134 return(xmlSchemaValAtomicType(type, value, val, node, 0));
Daniel Veillard4255d502002-04-16 15:50:10 +00002135}
2136
2137/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002138 * xmlSchemaValidatePredefinedType:
2139 * @type: the predefined type
2140 * @value: the value to check
2141 * @val: the return computed value
2142 *
2143 * Check that a value conforms to the lexical space of the predefined type.
2144 * if true a value is computed and returned in @val.
2145 *
2146 * Returns 0 if this validates, a positive error code number otherwise
2147 * and -1 in case of internal or API error.
2148 */
2149int
2150xmlSchemaValidatePredefinedType(xmlSchemaTypePtr type, const xmlChar *value,
2151 xmlSchemaValPtr *val) {
2152 return(xmlSchemaValPredefTypeNode(type, value, val, NULL));
2153}
2154
2155/**
Daniel Veillard4255d502002-04-16 15:50:10 +00002156 * xmlSchemaCompareDecimals:
2157 * @x: a first decimal value
2158 * @y: a second decimal value
2159 *
2160 * Compare 2 decimals
2161 *
2162 * Returns -1 if x < y, 0 if x == y, 1 if x > y and -2 in case of error
2163 */
2164static int
2165xmlSchemaCompareDecimals(xmlSchemaValPtr x, xmlSchemaValPtr y)
2166{
2167 xmlSchemaValPtr swp;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002168 int order = 1, p;
Daniel Veillard4255d502002-04-16 15:50:10 +00002169 unsigned long tmp;
2170
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002171 if ((x->value.decimal.sign) &&
2172 ((x->value.decimal.lo != 0) ||
2173 (x->value.decimal.mi != 0) ||
2174 (x->value.decimal.hi != 0))) {
2175 if ((y->value.decimal.sign) &&
2176 ((y->value.decimal.lo != 0) ||
2177 (y->value.decimal.mi != 0) ||
2178 (y->value.decimal.hi != 0)))
Daniel Veillard80b19092003-03-28 13:29:53 +00002179 order = -1;
2180 else
2181 return (-1);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002182 } else if ((y->value.decimal.sign) &&
2183 ((y->value.decimal.lo != 0) ||
2184 (y->value.decimal.mi != 0) ||
2185 (y->value.decimal.hi != 0))) {
Daniel Veillard4255d502002-04-16 15:50:10 +00002186 return (1);
Daniel Veillard80b19092003-03-28 13:29:53 +00002187 }
Daniel Veillard4255d502002-04-16 15:50:10 +00002188 if (x->value.decimal.frac == y->value.decimal.frac) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002189 if (x->value.decimal.hi < y->value.decimal.hi)
2190 return (-order);
2191 if (x->value.decimal.hi < y->value.decimal.hi)
2192 return (order);
2193 if (x->value.decimal.mi < y->value.decimal.mi)
2194 return (-order);
2195 if (x->value.decimal.mi < y->value.decimal.mi)
2196 return (order);
2197 if (x->value.decimal.lo < y->value.decimal.lo)
Daniel Veillard80b19092003-03-28 13:29:53 +00002198 return (-order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002199 if (x->value.decimal.lo > y->value.decimal.lo)
Daniel Veillard80b19092003-03-28 13:29:53 +00002200 return(order);
2201 return(0);
Daniel Veillard4255d502002-04-16 15:50:10 +00002202 }
2203 if (y->value.decimal.frac > x->value.decimal.frac) {
2204 swp = y;
2205 y = x;
2206 x = swp;
2207 order = -order;
2208 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002209 p = powten[x->value.decimal.frac - y->value.decimal.frac];
2210 tmp = x->value.decimal.lo / p;
2211 if (tmp > y->value.decimal.lo)
Daniel Veillard4255d502002-04-16 15:50:10 +00002212 return (order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002213 if (tmp < y->value.decimal.lo)
Daniel Veillard4255d502002-04-16 15:50:10 +00002214 return (-order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002215 tmp = y->value.decimal.lo * p;
2216 if (x->value.decimal.lo < tmp)
Daniel Veillard4255d502002-04-16 15:50:10 +00002217 return (-order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002218 if (x->value.decimal.lo == tmp)
Daniel Veillard4255d502002-04-16 15:50:10 +00002219 return (0);
2220 return (order);
2221}
2222
2223/**
Daniel Veillard070803b2002-05-03 07:29:38 +00002224 * xmlSchemaCompareDurations:
2225 * @x: a first duration value
2226 * @y: a second duration value
2227 *
2228 * Compare 2 durations
2229 *
2230 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
2231 * case of error
2232 */
2233static int
2234xmlSchemaCompareDurations(xmlSchemaValPtr x, xmlSchemaValPtr y)
2235{
2236 long carry, mon, day;
2237 double sec;
Daniel Veillard80b19092003-03-28 13:29:53 +00002238 int invert = 1;
2239 long xmon, xday, myear, minday, maxday;
Daniel Veillard070803b2002-05-03 07:29:38 +00002240 static const long dayRange [2][12] = {
2241 { 0, 28, 59, 89, 120, 150, 181, 212, 242, 273, 303, 334, },
2242 { 0, 31, 62, 92, 123, 153, 184, 215, 245, 276, 306, 337} };
2243
2244 if ((x == NULL) || (y == NULL))
Daniel Veillard5a872412002-05-22 06:40:27 +00002245 return -2;
Daniel Veillard070803b2002-05-03 07:29:38 +00002246
2247 /* months */
2248 mon = x->value.dur.mon - y->value.dur.mon;
2249
2250 /* seconds */
2251 sec = x->value.dur.sec - y->value.dur.sec;
2252 carry = (long)sec / SECS_PER_DAY;
2253 sec -= (double)(carry * SECS_PER_DAY);
2254
2255 /* days */
2256 day = x->value.dur.day - y->value.dur.day + carry;
2257
2258 /* easy test */
2259 if (mon == 0) {
2260 if (day == 0)
2261 if (sec == 0.0)
2262 return 0;
2263 else if (sec < 0.0)
2264 return -1;
2265 else
2266 return 1;
2267 else if (day < 0)
2268 return -1;
2269 else
2270 return 1;
2271 }
2272
2273 if (mon > 0) {
2274 if ((day >= 0) && (sec >= 0.0))
2275 return 1;
2276 else {
2277 xmon = mon;
2278 xday = -day;
2279 }
2280 } else if ((day <= 0) && (sec <= 0.0)) {
2281 return -1;
2282 } else {
Daniel Veillard80b19092003-03-28 13:29:53 +00002283 invert = -1;
Daniel Veillard070803b2002-05-03 07:29:38 +00002284 xmon = -mon;
2285 xday = day;
2286 }
2287
2288 myear = xmon / 12;
Daniel Veillard80b19092003-03-28 13:29:53 +00002289 if (myear == 0) {
2290 minday = 0;
2291 maxday = 0;
2292 } else {
2293 maxday = 366 * ((myear + 3) / 4) +
2294 365 * ((myear - 1) % 4);
2295 minday = maxday - 1;
2296 }
2297
Daniel Veillard070803b2002-05-03 07:29:38 +00002298 xmon = xmon % 12;
2299 minday += dayRange[0][xmon];
2300 maxday += dayRange[1][xmon];
2301
Daniel Veillard80b19092003-03-28 13:29:53 +00002302 if ((maxday == minday) && (maxday == xday))
2303 return(0); /* can this really happen ? */
Daniel Veillard070803b2002-05-03 07:29:38 +00002304 if (maxday < xday)
Daniel Veillard80b19092003-03-28 13:29:53 +00002305 return(-invert);
2306 if (minday > xday)
2307 return(invert);
Daniel Veillard070803b2002-05-03 07:29:38 +00002308
2309 /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00002310 return 2;
2311}
2312
2313/*
2314 * macros for adding date/times and durations
2315 */
2316#define FQUOTIENT(a,b) (floor(((double)a/(double)b)))
2317#define MODULO(a,b) (a - FQUOTIENT(a,b) * b)
2318#define FQUOTIENT_RANGE(a,low,high) (FQUOTIENT((a-low),(high-low)))
2319#define MODULO_RANGE(a,low,high) ((MODULO((a-low),(high-low)))+low)
2320
2321/**
2322 * _xmlSchemaDateAdd:
2323 * @dt: an #xmlSchemaValPtr
2324 * @dur: an #xmlSchemaValPtr of type #XS_DURATION
2325 *
2326 * Compute a new date/time from @dt and @dur. This function assumes @dt
2327 * is either #XML_SCHEMAS_DATETIME, #XML_SCHEMAS_DATE, #XML_SCHEMAS_GYEARMONTH,
2328 * or #XML_SCHEMAS_GYEAR.
2329 *
2330 * Returns date/time pointer or NULL.
2331 */
2332static xmlSchemaValPtr
2333_xmlSchemaDateAdd (xmlSchemaValPtr dt, xmlSchemaValPtr dur)
2334{
2335 xmlSchemaValPtr ret;
2336 long carry, tempdays, temp;
2337 xmlSchemaValDatePtr r, d;
2338 xmlSchemaValDurationPtr u;
2339
2340 if ((dt == NULL) || (dur == NULL))
2341 return NULL;
2342
2343 ret = xmlSchemaNewValue(dt->type);
2344 if (ret == NULL)
2345 return NULL;
2346
2347 r = &(ret->value.date);
2348 d = &(dt->value.date);
2349 u = &(dur->value.dur);
2350
2351 /* normalization */
2352 if (d->mon == 0)
2353 d->mon = 1;
2354
2355 /* normalize for time zone offset */
2356 u->sec -= (d->tzo * 60);
2357 d->tzo = 0;
2358
2359 /* normalization */
2360 if (d->day == 0)
2361 d->day = 1;
2362
2363 /* month */
2364 carry = d->mon + u->mon;
2365 r->mon = MODULO_RANGE(carry, 1, 13);
2366 carry = FQUOTIENT_RANGE(carry, 1, 13);
2367
2368 /* year (may be modified later) */
2369 r->year = d->year + carry;
2370 if (r->year == 0) {
2371 if (d->year > 0)
2372 r->year--;
2373 else
2374 r->year++;
2375 }
2376
2377 /* time zone */
2378 r->tzo = d->tzo;
2379 r->tz_flag = d->tz_flag;
2380
2381 /* seconds */
2382 r->sec = d->sec + u->sec;
2383 carry = FQUOTIENT((long)r->sec, 60);
2384 if (r->sec != 0.0) {
2385 r->sec = MODULO(r->sec, 60.0);
2386 }
2387
2388 /* minute */
2389 carry += d->min;
2390 r->min = MODULO(carry, 60);
2391 carry = FQUOTIENT(carry, 60);
2392
2393 /* hours */
2394 carry += d->hour;
2395 r->hour = MODULO(carry, 24);
2396 carry = FQUOTIENT(carry, 24);
2397
2398 /*
2399 * days
2400 * Note we use tempdays because the temporary values may need more
2401 * than 5 bits
2402 */
2403 if ((VALID_YEAR(r->year)) && (VALID_MONTH(r->mon)) &&
2404 (d->day > MAX_DAYINMONTH(r->year, r->mon)))
2405 tempdays = MAX_DAYINMONTH(r->year, r->mon);
2406 else if (d->day < 1)
2407 tempdays = 1;
2408 else
2409 tempdays = d->day;
2410
2411 tempdays += u->day + carry;
2412
2413 while (1) {
2414 if (tempdays < 1) {
2415 long tmon = MODULO_RANGE(r->mon-1, 1, 13);
2416 long tyr = r->year + FQUOTIENT_RANGE(r->mon-1, 1, 13);
2417 if (tyr == 0)
2418 tyr--;
2419 tempdays += MAX_DAYINMONTH(tyr, tmon);
2420 carry = -1;
2421 } else if (tempdays > MAX_DAYINMONTH(r->year, r->mon)) {
2422 tempdays = tempdays - MAX_DAYINMONTH(r->year, r->mon);
2423 carry = 1;
2424 } else
2425 break;
2426
2427 temp = r->mon + carry;
2428 r->mon = MODULO_RANGE(temp, 1, 13);
2429 r->year = r->year + FQUOTIENT_RANGE(temp, 1, 13);
2430 if (r->year == 0) {
2431 if (temp < 1)
2432 r->year--;
2433 else
2434 r->year++;
2435 }
2436 }
2437
2438 r->day = tempdays;
2439
2440 /*
2441 * adjust the date/time type to the date values
2442 */
2443 if (ret->type != XML_SCHEMAS_DATETIME) {
2444 if ((r->hour) || (r->min) || (r->sec))
2445 ret->type = XML_SCHEMAS_DATETIME;
2446 else if (ret->type != XML_SCHEMAS_DATE) {
2447 if ((r->mon != 1) && (r->day != 1))
2448 ret->type = XML_SCHEMAS_DATE;
2449 else if ((ret->type != XML_SCHEMAS_GYEARMONTH) && (r->mon != 1))
2450 ret->type = XML_SCHEMAS_GYEARMONTH;
2451 }
2452 }
2453
2454 return ret;
2455}
2456
2457/**
2458 * xmlSchemaDupVal:
2459 * @v: value to duplicate
2460 *
2461 * returns a duplicated value.
2462 */
2463static xmlSchemaValPtr
2464xmlSchemaDupVal (xmlSchemaValPtr v)
2465{
2466 xmlSchemaValPtr ret = xmlSchemaNewValue(v->type);
2467 if (ret == NULL)
2468 return ret;
2469
2470 memcpy(ret, v, sizeof(xmlSchemaVal));
2471 return ret;
2472}
2473
2474/**
2475 * xmlSchemaDateNormalize:
2476 * @dt: an #xmlSchemaValPtr
2477 *
2478 * Normalize @dt to GMT time.
2479 *
2480 */
2481static xmlSchemaValPtr
2482xmlSchemaDateNormalize (xmlSchemaValPtr dt, double offset)
2483{
2484 xmlSchemaValPtr dur, ret;
2485
2486 if (dt == NULL)
2487 return NULL;
2488
2489 if (((dt->type != XML_SCHEMAS_TIME) &&
2490 (dt->type != XML_SCHEMAS_DATETIME)) || (dt->value.date.tzo == 0))
2491 return xmlSchemaDupVal(dt);
2492
2493 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
2494 if (dur == NULL)
2495 return NULL;
2496
2497 dur->value.date.sec -= offset;
2498
2499 ret = _xmlSchemaDateAdd(dt, dur);
2500 if (ret == NULL)
2501 return NULL;
2502
2503 xmlSchemaFreeValue(dur);
2504
2505 /* ret->value.date.tzo = 0; */
2506 return ret;
2507}
2508
2509/**
2510 * _xmlSchemaDateCastYMToDays:
2511 * @dt: an #xmlSchemaValPtr
2512 *
2513 * Convert mon and year of @dt to total number of days. Take the
2514 * number of years since (or before) 1 AD and add the number of leap
2515 * years. This is a function because negative
2516 * years must be handled a little differently and there is no zero year.
2517 *
2518 * Returns number of days.
2519 */
2520static long
2521_xmlSchemaDateCastYMToDays (const xmlSchemaValPtr dt)
2522{
2523 long ret;
2524
2525 if (dt->value.date.year < 0)
2526 ret = (dt->value.date.year * 365) +
2527 (((dt->value.date.year+1)/4)-((dt->value.date.year+1)/100)+
2528 ((dt->value.date.year+1)/400)) +
2529 DAY_IN_YEAR(0, dt->value.date.mon, dt->value.date.year);
2530 else
2531 ret = ((dt->value.date.year-1) * 365) +
2532 (((dt->value.date.year-1)/4)-((dt->value.date.year-1)/100)+
2533 ((dt->value.date.year-1)/400)) +
2534 DAY_IN_YEAR(0, dt->value.date.mon, dt->value.date.year);
2535
2536 return ret;
2537}
2538
2539/**
2540 * TIME_TO_NUMBER:
2541 * @dt: an #xmlSchemaValPtr
2542 *
2543 * Calculates the number of seconds in the time portion of @dt.
2544 *
2545 * Returns seconds.
2546 */
2547#define TIME_TO_NUMBER(dt) \
2548 ((double)((dt->value.date.hour * SECS_PER_HOUR) + \
Daniel Veillardb3721c22003-03-31 11:22:25 +00002549 (dt->value.date.min * SECS_PER_MIN) + \
2550 (dt->value.date.tzo * SECS_PER_MIN)) + \
2551 dt->value.date.sec)
Daniel Veillard5a872412002-05-22 06:40:27 +00002552
2553/**
2554 * xmlSchemaCompareDates:
2555 * @x: a first date/time value
2556 * @y: a second date/time value
2557 *
2558 * Compare 2 date/times
2559 *
2560 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
2561 * case of error
2562 */
2563static int
2564xmlSchemaCompareDates (xmlSchemaValPtr x, xmlSchemaValPtr y)
2565{
2566 unsigned char xmask, ymask, xor_mask, and_mask;
2567 xmlSchemaValPtr p1, p2, q1, q2;
2568 long p1d, p2d, q1d, q2d;
2569
2570 if ((x == NULL) || (y == NULL))
2571 return -2;
2572
2573 if (x->value.date.tz_flag) {
2574
2575 if (!y->value.date.tz_flag) {
2576 p1 = xmlSchemaDateNormalize(x, 0);
2577 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
2578 /* normalize y + 14:00 */
2579 q1 = xmlSchemaDateNormalize(y, (14 * SECS_PER_HOUR));
2580
2581 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002582 if (p1d < q1d) {
2583 xmlSchemaFreeValue(p1);
2584 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002585 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002586 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00002587 double sec;
2588
2589 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00002590 if (sec < 0.0) {
2591 xmlSchemaFreeValue(p1);
2592 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002593 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002594 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00002595 /* normalize y - 14:00 */
2596 q2 = xmlSchemaDateNormalize(y, -(14 * SECS_PER_HOUR));
2597 q2d = _xmlSchemaDateCastYMToDays(q2) + q2->value.date.day;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002598 xmlSchemaFreeValue(p1);
2599 xmlSchemaFreeValue(q1);
2600 xmlSchemaFreeValue(q2);
Daniel Veillard5a872412002-05-22 06:40:27 +00002601 if (p1d > q2d)
2602 return 1;
2603 else if (p1d == q2d) {
2604 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q2);
2605 if (sec > 0.0)
2606 return 1;
2607 else
2608 return 2; /* indeterminate */
2609 }
2610 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00002611 } else {
2612 xmlSchemaFreeValue(p1);
2613 xmlSchemaFreeValue(q1);
2614 }
Daniel Veillard5a872412002-05-22 06:40:27 +00002615 }
2616 } else if (y->value.date.tz_flag) {
2617 q1 = xmlSchemaDateNormalize(y, 0);
2618 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
2619
2620 /* normalize x - 14:00 */
2621 p1 = xmlSchemaDateNormalize(x, -(14 * SECS_PER_HOUR));
2622 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
2623
Daniel Veillardfdc91562002-07-01 21:52:03 +00002624 if (p1d < q1d) {
2625 xmlSchemaFreeValue(p1);
2626 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002627 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002628 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00002629 double sec;
2630
2631 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00002632 if (sec < 0.0) {
2633 xmlSchemaFreeValue(p1);
2634 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002635 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002636 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00002637 /* normalize x + 14:00 */
2638 p2 = xmlSchemaDateNormalize(x, (14 * SECS_PER_HOUR));
2639 p2d = _xmlSchemaDateCastYMToDays(p2) + p2->value.date.day;
2640
Daniel Veillard6560a422003-03-27 21:25:38 +00002641 if (p2d > q1d) {
2642 xmlSchemaFreeValue(p1);
2643 xmlSchemaFreeValue(q1);
2644 xmlSchemaFreeValue(p2);
Daniel Veillard5a872412002-05-22 06:40:27 +00002645 return 1;
Daniel Veillard6560a422003-03-27 21:25:38 +00002646 } else if (p2d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00002647 sec = TIME_TO_NUMBER(p2) - TIME_TO_NUMBER(q1);
Daniel Veillard6560a422003-03-27 21:25:38 +00002648 xmlSchemaFreeValue(p1);
2649 xmlSchemaFreeValue(q1);
2650 xmlSchemaFreeValue(p2);
Daniel Veillard5a872412002-05-22 06:40:27 +00002651 if (sec > 0.0)
2652 return 1;
2653 else
2654 return 2; /* indeterminate */
2655 }
Daniel Veillard6560a422003-03-27 21:25:38 +00002656 xmlSchemaFreeValue(p1);
2657 xmlSchemaFreeValue(q1);
2658 xmlSchemaFreeValue(p2);
Daniel Veillard5a872412002-05-22 06:40:27 +00002659 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00002660 } else {
2661 xmlSchemaFreeValue(p1);
2662 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002663 }
2664 }
2665
2666 /*
2667 * if the same type then calculate the difference
2668 */
2669 if (x->type == y->type) {
2670 q1 = xmlSchemaDateNormalize(y, 0);
2671 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
2672
2673 p1 = xmlSchemaDateNormalize(x, 0);
2674 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
2675
Daniel Veillardfdc91562002-07-01 21:52:03 +00002676 if (p1d < q1d) {
2677 xmlSchemaFreeValue(p1);
2678 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002679 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002680 } else if (p1d > q1d) {
2681 xmlSchemaFreeValue(p1);
2682 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002683 return 1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002684 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00002685 double sec;
2686
2687 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00002688 xmlSchemaFreeValue(p1);
2689 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002690 if (sec < 0.0)
2691 return -1;
2692 else if (sec > 0.0)
2693 return 1;
2694
2695 }
2696 return 0;
2697 }
2698
2699 switch (x->type) {
2700 case XML_SCHEMAS_DATETIME:
2701 xmask = 0xf;
2702 break;
2703 case XML_SCHEMAS_DATE:
2704 xmask = 0x7;
2705 break;
2706 case XML_SCHEMAS_GYEAR:
2707 xmask = 0x1;
2708 break;
2709 case XML_SCHEMAS_GMONTH:
2710 xmask = 0x2;
2711 break;
2712 case XML_SCHEMAS_GDAY:
2713 xmask = 0x3;
2714 break;
2715 case XML_SCHEMAS_GYEARMONTH:
2716 xmask = 0x3;
2717 break;
2718 case XML_SCHEMAS_GMONTHDAY:
2719 xmask = 0x6;
2720 break;
2721 case XML_SCHEMAS_TIME:
2722 xmask = 0x8;
2723 break;
2724 default:
2725 xmask = 0;
2726 break;
2727 }
2728
2729 switch (y->type) {
2730 case XML_SCHEMAS_DATETIME:
2731 ymask = 0xf;
2732 break;
2733 case XML_SCHEMAS_DATE:
2734 ymask = 0x7;
2735 break;
2736 case XML_SCHEMAS_GYEAR:
2737 ymask = 0x1;
2738 break;
2739 case XML_SCHEMAS_GMONTH:
2740 ymask = 0x2;
2741 break;
2742 case XML_SCHEMAS_GDAY:
2743 ymask = 0x3;
2744 break;
2745 case XML_SCHEMAS_GYEARMONTH:
2746 ymask = 0x3;
2747 break;
2748 case XML_SCHEMAS_GMONTHDAY:
2749 ymask = 0x6;
2750 break;
2751 case XML_SCHEMAS_TIME:
2752 ymask = 0x8;
2753 break;
2754 default:
2755 ymask = 0;
2756 break;
2757 }
2758
2759 xor_mask = xmask ^ ymask; /* mark type differences */
2760 and_mask = xmask & ymask; /* mark field specification */
2761
2762 /* year */
2763 if (xor_mask & 1)
2764 return 2; /* indeterminate */
2765 else if (and_mask & 1) {
2766 if (x->value.date.year < y->value.date.year)
2767 return -1;
2768 else if (x->value.date.year > y->value.date.year)
2769 return 1;
2770 }
2771
2772 /* month */
2773 if (xor_mask & 2)
2774 return 2; /* indeterminate */
2775 else if (and_mask & 2) {
2776 if (x->value.date.mon < y->value.date.mon)
2777 return -1;
2778 else if (x->value.date.mon > y->value.date.mon)
2779 return 1;
2780 }
2781
2782 /* day */
2783 if (xor_mask & 4)
2784 return 2; /* indeterminate */
2785 else if (and_mask & 4) {
2786 if (x->value.date.day < y->value.date.day)
2787 return -1;
2788 else if (x->value.date.day > y->value.date.day)
2789 return 1;
2790 }
2791
2792 /* time */
2793 if (xor_mask & 8)
2794 return 2; /* indeterminate */
2795 else if (and_mask & 8) {
2796 if (x->value.date.hour < y->value.date.hour)
2797 return -1;
2798 else if (x->value.date.hour > y->value.date.hour)
2799 return 1;
2800 else if (x->value.date.min < y->value.date.min)
2801 return -1;
2802 else if (x->value.date.min > y->value.date.min)
2803 return 1;
2804 else if (x->value.date.sec < y->value.date.sec)
2805 return -1;
2806 else if (x->value.date.sec > y->value.date.sec)
2807 return 1;
2808 }
2809
Daniel Veillard070803b2002-05-03 07:29:38 +00002810 return 0;
2811}
2812
2813/**
Daniel Veillardc4c21552003-03-29 10:53:38 +00002814 * xmlSchemaCompareNormStrings:
2815 * @x: a first string value
2816 * @y: a second string value
2817 *
2818 * Compare 2 string for their normalized values.
2819 *
2820 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
2821 * case of error
2822 */
2823static int
2824xmlSchemaCompareNormStrings(xmlSchemaValPtr x, xmlSchemaValPtr y) {
2825 const xmlChar *utf1;
2826 const xmlChar *utf2;
2827 int tmp;
2828
2829 if ((x == NULL) || (y == NULL))
2830 return(-2);
2831 utf1 = x->value.str;
2832 utf2 = y->value.str;
2833
2834 while (IS_BLANK(*utf1)) utf1++;
2835 while (IS_BLANK(*utf2)) utf2++;
2836 while ((*utf1 != 0) && (*utf2 != 0)) {
2837 if (IS_BLANK(*utf1)) {
2838 if (!IS_BLANK(*utf2)) {
2839 tmp = *utf1 - *utf2;
2840 return(tmp);
2841 }
2842 while (IS_BLANK(*utf1)) utf1++;
2843 while (IS_BLANK(*utf2)) utf2++;
2844 } else {
2845 tmp = *utf1++ - *utf2++;
2846 if (tmp < 0)
2847 return(-1);
2848 if (tmp > 0)
2849 return(1);
2850 }
2851 }
2852 if (*utf1 != 0) {
2853 while (IS_BLANK(*utf1)) utf1++;
2854 if (*utf1 != 0)
2855 return(1);
2856 }
2857 if (*utf2 != 0) {
2858 while (IS_BLANK(*utf2)) utf2++;
2859 if (*utf2 != 0)
2860 return(-1);
2861 }
2862 return(0);
2863}
2864
2865/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002866 * xmlSchemaCompareFloats:
2867 * @x: a first float or double value
2868 * @y: a second float or double value
2869 *
2870 * Compare 2 values
2871 *
2872 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
2873 * case of error
2874 */
2875static int
2876xmlSchemaCompareFloats(xmlSchemaValPtr x, xmlSchemaValPtr y) {
2877 double d1, d2;
2878
2879 if ((x == NULL) || (y == NULL))
2880 return(-2);
2881
2882 /*
2883 * Cast everything to doubles.
2884 */
2885 if (x->type == XML_SCHEMAS_DOUBLE)
2886 d1 = x->value.d;
2887 else if (x->type == XML_SCHEMAS_FLOAT)
2888 d1 = x->value.f;
2889 else
2890 return(-2);
2891
2892 if (y->type == XML_SCHEMAS_DOUBLE)
2893 d2 = y->value.d;
2894 else if (y->type == XML_SCHEMAS_FLOAT)
2895 d2 = y->value.f;
2896 else
2897 return(-2);
2898
2899 /*
2900 * Check for special cases.
2901 */
2902 if (xmlXPathIsNaN(d1)) {
2903 if (xmlXPathIsNaN(d2))
2904 return(0);
2905 return(1);
2906 }
2907 if (xmlXPathIsNaN(d2))
2908 return(-1);
2909 if (d1 == xmlXPathPINF) {
2910 if (d2 == xmlXPathPINF)
2911 return(0);
2912 return(1);
2913 }
2914 if (d2 == xmlXPathPINF)
2915 return(-1);
2916 if (d1 == xmlXPathNINF) {
2917 if (d2 == xmlXPathNINF)
2918 return(0);
2919 return(-1);
2920 }
2921 if (d2 == xmlXPathNINF)
2922 return(1);
2923
2924 /*
2925 * basic tests, the last one we should have equality, but
2926 * portability is more important than speed and handling
2927 * NaN or Inf in a portable way is always a challenge, so ...
2928 */
2929 if (d1 < d2)
2930 return(-1);
2931 if (d1 > d2)
2932 return(1);
2933 if (d1 == d2)
2934 return(0);
2935 return(2);
2936}
2937
2938/**
Daniel Veillard4255d502002-04-16 15:50:10 +00002939 * xmlSchemaCompareValues:
2940 * @x: a first value
2941 * @y: a second value
2942 *
2943 * Compare 2 values
2944 *
Daniel Veillard5a872412002-05-22 06:40:27 +00002945 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
2946 * case of error
Daniel Veillard4255d502002-04-16 15:50:10 +00002947 */
Daniel Veillard80b19092003-03-28 13:29:53 +00002948int
Daniel Veillard4255d502002-04-16 15:50:10 +00002949xmlSchemaCompareValues(xmlSchemaValPtr x, xmlSchemaValPtr y) {
2950 if ((x == NULL) || (y == NULL))
2951 return(-2);
2952
2953 switch (x->type) {
Daniel Veillard80b19092003-03-28 13:29:53 +00002954 case XML_SCHEMAS_UNKNOWN:
2955 return(-2);
2956 case XML_SCHEMAS_INTEGER:
2957 case XML_SCHEMAS_NPINTEGER:
2958 case XML_SCHEMAS_NINTEGER:
2959 case XML_SCHEMAS_NNINTEGER:
2960 case XML_SCHEMAS_PINTEGER:
2961 case XML_SCHEMAS_INT:
2962 case XML_SCHEMAS_UINT:
2963 case XML_SCHEMAS_LONG:
2964 case XML_SCHEMAS_ULONG:
2965 case XML_SCHEMAS_SHORT:
2966 case XML_SCHEMAS_USHORT:
2967 case XML_SCHEMAS_BYTE:
2968 case XML_SCHEMAS_UBYTE:
Daniel Veillard4255d502002-04-16 15:50:10 +00002969 case XML_SCHEMAS_DECIMAL:
Daniel Veillard80b19092003-03-28 13:29:53 +00002970 if (y->type == x->type)
2971 return(xmlSchemaCompareDecimals(x, y));
2972 if ((y->type == XML_SCHEMAS_DECIMAL) ||
2973 (y->type == XML_SCHEMAS_INTEGER) ||
2974 (y->type == XML_SCHEMAS_NPINTEGER) ||
2975 (y->type == XML_SCHEMAS_NINTEGER) ||
2976 (y->type == XML_SCHEMAS_NNINTEGER) ||
2977 (y->type == XML_SCHEMAS_PINTEGER) ||
2978 (y->type == XML_SCHEMAS_INT) ||
2979 (y->type == XML_SCHEMAS_UINT) ||
2980 (y->type == XML_SCHEMAS_LONG) ||
2981 (y->type == XML_SCHEMAS_ULONG) ||
2982 (y->type == XML_SCHEMAS_SHORT) ||
2983 (y->type == XML_SCHEMAS_USHORT) ||
2984 (y->type == XML_SCHEMAS_BYTE) ||
2985 (y->type == XML_SCHEMAS_UBYTE))
Daniel Veillard4255d502002-04-16 15:50:10 +00002986 return(xmlSchemaCompareDecimals(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00002987 return(-2);
Daniel Veillard070803b2002-05-03 07:29:38 +00002988 case XML_SCHEMAS_DURATION:
2989 if (y->type == XML_SCHEMAS_DURATION)
2990 return(xmlSchemaCompareDurations(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00002991 return(-2);
2992 case XML_SCHEMAS_TIME:
2993 case XML_SCHEMAS_GDAY:
2994 case XML_SCHEMAS_GMONTH:
2995 case XML_SCHEMAS_GMONTHDAY:
2996 case XML_SCHEMAS_GYEAR:
2997 case XML_SCHEMAS_GYEARMONTH:
2998 case XML_SCHEMAS_DATE:
2999 case XML_SCHEMAS_DATETIME:
3000 if ((y->type == XML_SCHEMAS_DATETIME) ||
3001 (y->type == XML_SCHEMAS_TIME) ||
3002 (y->type == XML_SCHEMAS_GDAY) ||
3003 (y->type == XML_SCHEMAS_GMONTH) ||
3004 (y->type == XML_SCHEMAS_GMONTHDAY) ||
3005 (y->type == XML_SCHEMAS_GYEAR) ||
3006 (y->type == XML_SCHEMAS_DATE) ||
3007 (y->type == XML_SCHEMAS_GYEARMONTH))
3008 return (xmlSchemaCompareDates(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00003009 return (-2);
Daniel Veillard80b19092003-03-28 13:29:53 +00003010 case XML_SCHEMAS_NORMSTRING:
Daniel Veillard80b19092003-03-28 13:29:53 +00003011 case XML_SCHEMAS_TOKEN:
3012 case XML_SCHEMAS_LANGUAGE:
3013 case XML_SCHEMAS_NMTOKEN:
Daniel Veillard80b19092003-03-28 13:29:53 +00003014 case XML_SCHEMAS_NAME:
Daniel Veillard80b19092003-03-28 13:29:53 +00003015 case XML_SCHEMAS_NCNAME:
3016 case XML_SCHEMAS_ID:
3017 case XML_SCHEMAS_IDREF:
Daniel Veillard80b19092003-03-28 13:29:53 +00003018 case XML_SCHEMAS_ENTITY:
Daniel Veillard80b19092003-03-28 13:29:53 +00003019 case XML_SCHEMAS_NOTATION:
3020 case XML_SCHEMAS_ANYURI:
Daniel Veillardc4c21552003-03-29 10:53:38 +00003021 if ((y->type == XML_SCHEMAS_NORMSTRING) ||
3022 (y->type == XML_SCHEMAS_TOKEN) ||
3023 (y->type == XML_SCHEMAS_LANGUAGE) ||
3024 (y->type == XML_SCHEMAS_NMTOKEN) ||
3025 (y->type == XML_SCHEMAS_NAME) ||
3026 (y->type == XML_SCHEMAS_QNAME) ||
3027 (y->type == XML_SCHEMAS_NCNAME) ||
3028 (y->type == XML_SCHEMAS_ID) ||
3029 (y->type == XML_SCHEMAS_IDREF) ||
3030 (y->type == XML_SCHEMAS_ENTITY) ||
3031 (y->type == XML_SCHEMAS_NOTATION) ||
3032 (y->type == XML_SCHEMAS_ANYURI))
3033 return (xmlSchemaCompareNormStrings(x, y));
3034 return (-2);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003035 case XML_SCHEMAS_QNAME:
3036 if (y->type == XML_SCHEMAS_QNAME) {
3037 if ((xmlStrEqual(x->value.qname.name, y->value.qname.name)) &&
3038 (xmlStrEqual(x->value.qname.uri, y->value.qname.uri)))
3039 return(0);
3040 return(2);
3041 }
3042 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00003043 case XML_SCHEMAS_FLOAT:
3044 case XML_SCHEMAS_DOUBLE:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003045 if ((y->type == XML_SCHEMAS_FLOAT) ||
3046 (y->type == XML_SCHEMAS_DOUBLE))
3047 return (xmlSchemaCompareFloats(x, y));
3048 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00003049 case XML_SCHEMAS_BOOLEAN:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003050 if (y->type == XML_SCHEMAS_BOOLEAN) {
3051 if (x->value.b == y->value.b)
3052 return(0);
3053 if (x->value.b == 0)
3054 return(-1);
3055 return(1);
3056 }
3057 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00003058 case XML_SCHEMAS_STRING:
3059 case XML_SCHEMAS_IDREFS:
3060 case XML_SCHEMAS_ENTITIES:
3061 case XML_SCHEMAS_NMTOKENS:
3062 TODO
3063 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00003064 }
Daniel Veillard5a872412002-05-22 06:40:27 +00003065 return -2;
Daniel Veillard4255d502002-04-16 15:50:10 +00003066}
3067
3068/**
Daniel Veillardc4c21552003-03-29 10:53:38 +00003069 * xmlSchemaNormLen:
3070 * @value: a string
3071 *
3072 * Computes the UTF8 length of the normalized value of the string
3073 *
3074 * Returns the length or -1 in case of error.
3075 */
3076static int
3077xmlSchemaNormLen(const xmlChar *value) {
3078 const xmlChar *utf;
3079 int ret = 0;
3080
3081 if (value == NULL)
3082 return(-1);
3083 utf = value;
3084 while (IS_BLANK(*utf)) utf++;
3085 while (*utf != 0) {
3086 if (utf[0] & 0x80) {
3087 if ((utf[1] & 0xc0) != 0x80)
3088 return(-1);
3089 if ((utf[0] & 0xe0) == 0xe0) {
3090 if ((utf[2] & 0xc0) != 0x80)
3091 return(-1);
3092 if ((utf[0] & 0xf0) == 0xf0) {
3093 if ((utf[0] & 0xf8) != 0xf0 || (utf[3] & 0xc0) != 0x80)
3094 return(-1);
3095 utf += 4;
3096 } else {
3097 utf += 3;
3098 }
3099 } else {
3100 utf += 2;
3101 }
3102 } else if (IS_BLANK(*utf)) {
3103 while (IS_BLANK(*utf)) utf++;
3104 if (*utf == 0)
3105 break;
3106 } else {
3107 utf++;
3108 }
3109 ret++;
3110 }
3111 return(ret);
3112}
3113
3114/**
Daniel Veillard4255d502002-04-16 15:50:10 +00003115 * xmlSchemaValidateFacet:
Daniel Veillard01c13b52002-12-10 15:19:08 +00003116 * @base: the base type
Daniel Veillard4255d502002-04-16 15:50:10 +00003117 * @facet: the facet to check
3118 * @value: the lexical repr of the value to validate
3119 * @val: the precomputed value
3120 *
3121 * Check a value against a facet condition
3122 *
3123 * Returns 0 if the element is schemas valid, a positive error code
3124 * number otherwise and -1 in case of internal or API error.
3125 */
3126int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00003127xmlSchemaValidateFacet(xmlSchemaTypePtr base ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +00003128 xmlSchemaFacetPtr facet,
Daniel Veillard4255d502002-04-16 15:50:10 +00003129 const xmlChar *value, xmlSchemaValPtr val)
3130{
3131 int ret;
3132
3133 switch (facet->type) {
3134 case XML_SCHEMA_FACET_PATTERN:
3135 ret = xmlRegexpExec(facet->regexp, value);
3136 if (ret == 1)
3137 return(0);
3138 if (ret == 0) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003139 /* TODO error code */
Daniel Veillard4255d502002-04-16 15:50:10 +00003140 return(1);
3141 }
3142 return(ret);
3143 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
3144 ret = xmlSchemaCompareValues(val, facet->val);
3145 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003146 /* TODO error code */
Daniel Veillard4255d502002-04-16 15:50:10 +00003147 return(-1);
3148 }
3149 if (ret == -1)
3150 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00003151 /* error code */
Daniel Veillard4255d502002-04-16 15:50:10 +00003152 return(1);
Daniel Veillard070803b2002-05-03 07:29:38 +00003153 case XML_SCHEMA_FACET_MAXINCLUSIVE:
3154 ret = xmlSchemaCompareValues(val, facet->val);
3155 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003156 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00003157 return(-1);
3158 }
3159 if ((ret == -1) || (ret == 0))
3160 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00003161 /* error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00003162 return(1);
3163 case XML_SCHEMA_FACET_MINEXCLUSIVE:
3164 ret = xmlSchemaCompareValues(val, facet->val);
3165 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003166 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00003167 return(-1);
3168 }
3169 if (ret == 1)
3170 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00003171 /* error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00003172 return(1);
3173 case XML_SCHEMA_FACET_MININCLUSIVE:
3174 ret = xmlSchemaCompareValues(val, facet->val);
3175 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003176 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00003177 return(-1);
3178 }
3179 if ((ret == 1) || (ret == 0))
3180 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00003181 /* error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00003182 return(1);
Daniel Veillard8651f532002-04-17 09:06:27 +00003183 case XML_SCHEMA_FACET_WHITESPACE:
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003184 /* TODO whitespaces */
Daniel Veillard8651f532002-04-17 09:06:27 +00003185 return(0);
Daniel Veillard88c58912002-04-23 07:12:20 +00003186 case XML_SCHEMA_FACET_ENUMERATION:
3187 if ((facet->value != NULL) &&
3188 (xmlStrEqual(facet->value, value)))
3189 return(0);
3190 return(1);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003191 case XML_SCHEMA_FACET_LENGTH:
3192 case XML_SCHEMA_FACET_MAXLENGTH:
3193 case XML_SCHEMA_FACET_MINLENGTH: {
3194 unsigned int len = 0;
3195
3196 if ((facet->val == NULL) ||
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003197 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
3198 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003199 (facet->val->value.decimal.frac != 0)) {
3200 return(-1);
3201 }
3202 switch (base->flags) {
Daniel Veillardc4c21552003-03-29 10:53:38 +00003203 case XML_SCHEMAS_IDREF:
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003204 case XML_SCHEMAS_NORMSTRING:
3205 case XML_SCHEMAS_TOKEN:
3206 case XML_SCHEMAS_LANGUAGE:
3207 case XML_SCHEMAS_NMTOKEN:
3208 case XML_SCHEMAS_NAME:
3209 case XML_SCHEMAS_NCNAME:
3210 case XML_SCHEMAS_ID:
Daniel Veillardc4c21552003-03-29 10:53:38 +00003211 len = xmlSchemaNormLen(value);
3212 break;
3213 case XML_SCHEMAS_STRING:
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003214 len = xmlUTF8Strlen(value);
3215 break;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003216 default:
3217 TODO
3218 }
3219 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003220 if (len != facet->val->value.decimal.lo)
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003221 return(1);
3222 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003223 if (len < facet->val->value.decimal.lo)
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003224 return(1);
3225 } else {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003226 if (len > facet->val->value.decimal.lo)
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003227 return(1);
3228 }
3229 break;
3230 }
Daniel Veillard4255d502002-04-16 15:50:10 +00003231 default:
3232 TODO
3233 }
3234 return(0);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003235
Daniel Veillard4255d502002-04-16 15:50:10 +00003236}
3237
3238#endif /* LIBXML_SCHEMAS_ENABLED */