blob: 32463624dacc51ef6a3864c2488507cfb1ec0649 [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
Daniel Veillardd0cf7f62004-11-09 16:17:02 +000034#ifndef LIBXML_XPATH_ENABLED
35extern double xmlXPathNAN;
36extern double xmlXPathPINF;
37extern double xmlXPathNINF;
38#endif
39
Daniel Veillard4255d502002-04-16 15:50:10 +000040#define TODO \
41 xmlGenericError(xmlGenericErrorContext, \
42 "Unimplemented block at %s:%d\n", \
43 __FILE__, __LINE__);
44
45#define XML_SCHEMAS_NAMESPACE_NAME \
46 (const xmlChar *)"http://www.w3.org/2001/XMLSchema"
47
Daniel Veillard4255d502002-04-16 15:50:10 +000048
Daniel Veillard5f704af2003-03-05 10:01:43 +000049static unsigned long powten[10] = {
Daniel Veillard4255d502002-04-16 15:50:10 +000050 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000L,
51 100000000L, 1000000000L
52};
53
Daniel Veillard01fa6152004-06-29 17:04:39 +000054
Daniel Veillard070803b2002-05-03 07:29:38 +000055/* Date value */
56typedef struct _xmlSchemaValDate xmlSchemaValDate;
57typedef xmlSchemaValDate *xmlSchemaValDatePtr;
58struct _xmlSchemaValDate {
59 long year;
60 unsigned int mon :4; /* 1 <= mon <= 12 */
61 unsigned int day :5; /* 1 <= day <= 31 */
62 unsigned int hour :5; /* 0 <= hour <= 23 */
63 unsigned int min :6; /* 0 <= min <= 59 */
64 double sec;
Daniel Veillarda77cf712003-05-09 23:09:55 +000065 unsigned int tz_flag :1; /* is tzo explicitely set? */
Daniel Veillard070803b2002-05-03 07:29:38 +000066 int tzo :11; /* -1440 <= tzo <= 1440 */
67};
68
69/* Duration value */
70typedef struct _xmlSchemaValDuration xmlSchemaValDuration;
71typedef xmlSchemaValDuration *xmlSchemaValDurationPtr;
72struct _xmlSchemaValDuration {
73 long mon; /* mon stores years also */
74 long day;
75 double sec; /* sec stores min and hour also */
76};
77
Daniel Veillard4255d502002-04-16 15:50:10 +000078typedef struct _xmlSchemaValDecimal xmlSchemaValDecimal;
79typedef xmlSchemaValDecimal *xmlSchemaValDecimalPtr;
80struct _xmlSchemaValDecimal {
81 /* would use long long but not portable */
Daniel Veillarde637c4a2003-03-30 21:10:09 +000082 unsigned long lo;
83 unsigned long mi;
84 unsigned long hi;
Daniel Veillard4255d502002-04-16 15:50:10 +000085 unsigned int extra;
Daniel Veillard5a872412002-05-22 06:40:27 +000086 unsigned int sign:1;
William M. Brackc1939562003-08-05 15:52:22 +000087 unsigned int frac:7;
88 unsigned int total:8;
Daniel Veillard4255d502002-04-16 15:50:10 +000089};
90
Daniel Veillarde637c4a2003-03-30 21:10:09 +000091typedef struct _xmlSchemaValQName xmlSchemaValQName;
92typedef xmlSchemaValQName *xmlSchemaValQNamePtr;
93struct _xmlSchemaValQName {
94 xmlChar *name;
95 xmlChar *uri;
96};
97
Daniel Veillard70bcb0e2003-08-08 14:00:28 +000098typedef struct _xmlSchemaValHex xmlSchemaValHex;
99typedef xmlSchemaValHex *xmlSchemaValHexPtr;
100struct _xmlSchemaValHex {
101 xmlChar *str;
102 unsigned int total;
103};
104
Daniel Veillard1ac24d32003-08-27 14:15:15 +0000105typedef struct _xmlSchemaValBase64 xmlSchemaValBase64;
106typedef xmlSchemaValBase64 *xmlSchemaValBase64Ptr;
107struct _xmlSchemaValBase64 {
108 xmlChar *str;
109 unsigned int total;
110};
111
Daniel Veillard4255d502002-04-16 15:50:10 +0000112struct _xmlSchemaVal {
113 xmlSchemaValType type;
114 union {
Daniel Veillard5a872412002-05-22 06:40:27 +0000115 xmlSchemaValDecimal decimal;
Daniel Veillard070803b2002-05-03 07:29:38 +0000116 xmlSchemaValDate date;
117 xmlSchemaValDuration dur;
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000118 xmlSchemaValQName qname;
Daniel Veillard70bcb0e2003-08-08 14:00:28 +0000119 xmlSchemaValHex hex;
Daniel Veillard1ac24d32003-08-27 14:15:15 +0000120 xmlSchemaValBase64 base64;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000121 float f;
122 double d;
Daniel Veillardc5a70f22003-02-06 23:41:59 +0000123 int b;
Daniel Veillardc4c21552003-03-29 10:53:38 +0000124 xmlChar *str;
Daniel Veillard4255d502002-04-16 15:50:10 +0000125 } value;
126};
127
128static int xmlSchemaTypesInitialized = 0;
129static xmlHashTablePtr xmlSchemaTypesBank = NULL;
130
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000131/*
132 * Basic types
133 */
Daniel Veillard4255d502002-04-16 15:50:10 +0000134static xmlSchemaTypePtr xmlSchemaTypeStringDef = NULL;
135static xmlSchemaTypePtr xmlSchemaTypeAnyTypeDef = NULL;
136static xmlSchemaTypePtr xmlSchemaTypeAnySimpleTypeDef = NULL;
137static xmlSchemaTypePtr xmlSchemaTypeDecimalDef = NULL;
Daniel Veillard070803b2002-05-03 07:29:38 +0000138static xmlSchemaTypePtr xmlSchemaTypeDatetimeDef = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +0000139static xmlSchemaTypePtr xmlSchemaTypeDateDef = NULL;
Daniel Veillard070803b2002-05-03 07:29:38 +0000140static xmlSchemaTypePtr xmlSchemaTypeTimeDef = NULL;
141static xmlSchemaTypePtr xmlSchemaTypeGYearDef = NULL;
142static xmlSchemaTypePtr xmlSchemaTypeGYearMonthDef = NULL;
143static xmlSchemaTypePtr xmlSchemaTypeGDayDef = NULL;
144static xmlSchemaTypePtr xmlSchemaTypeGMonthDayDef = NULL;
145static xmlSchemaTypePtr xmlSchemaTypeGMonthDef = NULL;
146static xmlSchemaTypePtr xmlSchemaTypeDurationDef = NULL;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000147static xmlSchemaTypePtr xmlSchemaTypeFloatDef = NULL;
Daniel Veillardc5a70f22003-02-06 23:41:59 +0000148static xmlSchemaTypePtr xmlSchemaTypeBooleanDef = NULL;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000149static xmlSchemaTypePtr xmlSchemaTypeDoubleDef = NULL;
Daniel Veillard560c2a42003-07-06 21:13:49 +0000150static xmlSchemaTypePtr xmlSchemaTypeHexBinaryDef = NULL;
Daniel Veillard1ac24d32003-08-27 14:15:15 +0000151static xmlSchemaTypePtr xmlSchemaTypeBase64BinaryDef = NULL;
Daniel Veillarde5b110b2003-02-04 14:43:39 +0000152static xmlSchemaTypePtr xmlSchemaTypeAnyURIDef = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +0000153
154/*
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000155 * Derived types
156 */
157static xmlSchemaTypePtr xmlSchemaTypePositiveIntegerDef = NULL;
158static xmlSchemaTypePtr xmlSchemaTypeNonPositiveIntegerDef = NULL;
159static xmlSchemaTypePtr xmlSchemaTypeNegativeIntegerDef = NULL;
160static xmlSchemaTypePtr xmlSchemaTypeNonNegativeIntegerDef = NULL;
161static xmlSchemaTypePtr xmlSchemaTypeIntegerDef = NULL;
162static xmlSchemaTypePtr xmlSchemaTypeLongDef = NULL;
163static xmlSchemaTypePtr xmlSchemaTypeIntDef = NULL;
164static xmlSchemaTypePtr xmlSchemaTypeShortDef = NULL;
165static xmlSchemaTypePtr xmlSchemaTypeByteDef = NULL;
166static xmlSchemaTypePtr xmlSchemaTypeUnsignedLongDef = NULL;
167static xmlSchemaTypePtr xmlSchemaTypeUnsignedIntDef = NULL;
168static xmlSchemaTypePtr xmlSchemaTypeUnsignedShortDef = NULL;
169static xmlSchemaTypePtr xmlSchemaTypeUnsignedByteDef = NULL;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000170static xmlSchemaTypePtr xmlSchemaTypeNormStringDef = NULL;
171static xmlSchemaTypePtr xmlSchemaTypeTokenDef = NULL;
172static xmlSchemaTypePtr xmlSchemaTypeLanguageDef = NULL;
173static xmlSchemaTypePtr xmlSchemaTypeNameDef = NULL;
174static xmlSchemaTypePtr xmlSchemaTypeQNameDef = NULL;
Daniel Veillarde5b110b2003-02-04 14:43:39 +0000175static xmlSchemaTypePtr xmlSchemaTypeNCNameDef = NULL;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000176static xmlSchemaTypePtr xmlSchemaTypeIdDef = NULL;
177static xmlSchemaTypePtr xmlSchemaTypeIdrefDef = NULL;
178static xmlSchemaTypePtr xmlSchemaTypeIdrefsDef = NULL;
Daniel Veillarda1a9d042003-03-18 16:53:17 +0000179static xmlSchemaTypePtr xmlSchemaTypeEntityDef = NULL;
180static xmlSchemaTypePtr xmlSchemaTypeEntitiesDef = NULL;
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000181static xmlSchemaTypePtr xmlSchemaTypeNotationDef = NULL;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000182static xmlSchemaTypePtr xmlSchemaTypeNmtokenDef = NULL;
183static xmlSchemaTypePtr xmlSchemaTypeNmtokensDef = NULL;
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000184
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000185/************************************************************************
186 * *
187 * Datatype error handlers *
188 * *
189 ************************************************************************/
190/**
191 * xmlSchemaTypeErrMemory:
192 * @extra: extra informations
193 *
194 * Handle an out of memory condition
195 */
196static void
197xmlSchemaTypeErrMemory(xmlNodePtr node, const char *extra)
198{
199 __xmlSimpleError(XML_FROM_DATATYPE, XML_ERR_NO_MEMORY, node, NULL, extra);
200}
201
202/************************************************************************
203 * *
204 * Base types support *
205 * *
206 ************************************************************************/
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000207/*
Daniel Veillard4255d502002-04-16 15:50:10 +0000208 * xmlSchemaInitBasicType:
209 * @name: the type name
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000210 * @type: the value type associated
Daniel Veillard4255d502002-04-16 15:50:10 +0000211 *
Daniel Veillard01fa6152004-06-29 17:04:39 +0000212 * Initialize one primitive built-in type
Daniel Veillard4255d502002-04-16 15:50:10 +0000213 */
214static xmlSchemaTypePtr
Daniel Veillard01fa6152004-06-29 17:04:39 +0000215xmlSchemaInitBasicType(const char *name, xmlSchemaValType type,
216 xmlSchemaTypePtr baseType) {
Daniel Veillard4255d502002-04-16 15:50:10 +0000217 xmlSchemaTypePtr ret;
218
219 ret = (xmlSchemaTypePtr) xmlMalloc(sizeof(xmlSchemaType));
220 if (ret == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000221 xmlSchemaTypeErrMemory(NULL, "could not initialize basic types");
Daniel Veillard4255d502002-04-16 15:50:10 +0000222 return(NULL);
223 }
224 memset(ret, 0, sizeof(xmlSchemaType));
Daniel Veillardbe9c6322003-11-22 20:37:51 +0000225 ret->name = (const xmlChar *)name;
Daniel Veillard4255d502002-04-16 15:50:10 +0000226 ret->type = XML_SCHEMA_TYPE_BASIC;
Daniel Veillard01fa6152004-06-29 17:04:39 +0000227 ret->baseType = baseType;
228 /*
229 * Hack to reflect the variety.
230 */
231 if ((type == XML_SCHEMAS_IDREFS) ||
232 (type == XML_SCHEMAS_NMTOKENS) ||
233 (type == XML_SCHEMAS_ENTITIES))
234 ret->flags |= XML_SCHEMAS_TYPE_VARIETY_LIST;
William M. Brack2f2a6632004-08-20 23:09:47 +0000235 else if ((type != XML_SCHEMAS_ANYTYPE) &&
236 (type != XML_SCHEMAS_ANYSIMPLETYPE))
Daniel Veillard01fa6152004-06-29 17:04:39 +0000237 ret->flags |= XML_SCHEMAS_TYPE_VARIETY_ATOMIC;
Daniel Veillard4255d502002-04-16 15:50:10 +0000238 ret->contentType = XML_SCHEMA_CONTENT_BASIC;
Daniel Veillard01fa6152004-06-29 17:04:39 +0000239 switch (type) {
240 case XML_SCHEMAS_STRING:
241 case XML_SCHEMAS_DECIMAL:
242 case XML_SCHEMAS_DATE:
243 case XML_SCHEMAS_DATETIME:
244 case XML_SCHEMAS_TIME:
245 case XML_SCHEMAS_GYEAR:
246 case XML_SCHEMAS_GYEARMONTH:
247 case XML_SCHEMAS_GMONTH:
248 case XML_SCHEMAS_GMONTHDAY:
249 case XML_SCHEMAS_GDAY:
250 case XML_SCHEMAS_DURATION:
251 case XML_SCHEMAS_FLOAT:
252 case XML_SCHEMAS_DOUBLE:
253 case XML_SCHEMAS_BOOLEAN:
254 case XML_SCHEMAS_ANYURI:
255 case XML_SCHEMAS_HEXBINARY:
256 case XML_SCHEMAS_BASE64BINARY:
257 case XML_SCHEMAS_QNAME:
258 case XML_SCHEMAS_NOTATION:
259 ret->flags |= XML_SCHEMAS_TYPE_BUILTIN_PRIMITIVE;
William M. Brack96d2eff2004-06-30 11:48:47 +0000260 default:
261 break;
Daniel Veillard01fa6152004-06-29 17:04:39 +0000262 }
263
Daniel Veillard4255d502002-04-16 15:50:10 +0000264 xmlHashAddEntry2(xmlSchemaTypesBank, ret->name,
265 XML_SCHEMAS_NAMESPACE_NAME, ret);
Daniel Veillard01fa6152004-06-29 17:04:39 +0000266 ret->builtInType = type;
Daniel Veillard4255d502002-04-16 15:50:10 +0000267 return(ret);
268}
269
270/*
271 * xmlSchemaInitTypes:
272 *
273 * Initialize the default XML Schemas type library
274 */
275void
Daniel Veillard6560a422003-03-27 21:25:38 +0000276xmlSchemaInitTypes(void)
277{
Daniel Veillard4255d502002-04-16 15:50:10 +0000278 if (xmlSchemaTypesInitialized != 0)
Daniel Veillard6560a422003-03-27 21:25:38 +0000279 return;
Daniel Veillard4255d502002-04-16 15:50:10 +0000280 xmlSchemaTypesBank = xmlHashCreate(40);
Daniel Veillard6560a422003-03-27 21:25:38 +0000281
Daniel Veillard01fa6152004-06-29 17:04:39 +0000282
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000283 /*
Daniel Veillard01fa6152004-06-29 17:04:39 +0000284 * 3.4.7 Built-in Complex Type Definition
285 */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000286 xmlSchemaTypeAnyTypeDef = xmlSchemaInitBasicType("anyType",
William M. Brack2f2a6632004-08-20 23:09:47 +0000287 XML_SCHEMAS_ANYTYPE,
Daniel Veillard01fa6152004-06-29 17:04:39 +0000288 NULL);
289 xmlSchemaTypeAnyTypeDef->baseType = xmlSchemaTypeAnyTypeDef;
290 xmlSchemaTypeAnyTypeDef->contentType = XML_SCHEMA_CONTENT_MIXED;
291 {
292 xmlSchemaWildcardPtr wild;
293
294 wild = (xmlSchemaWildcardPtr) xmlMalloc(sizeof(xmlSchemaWildcard));
295 if (wild == NULL) {
William M. Brack2f2a6632004-08-20 23:09:47 +0000296 xmlSchemaTypeErrMemory(NULL, "could not create an attribute wildcard on anyType");
Daniel Veillard01fa6152004-06-29 17:04:39 +0000297 return;
298 }
299 memset(wild, 0, sizeof(xmlSchemaWildcard));
300 wild->any = 1;
301 wild->processContents = XML_SCHEMAS_ANY_LAX;
302 wild->minOccurs = 1;
303 wild->maxOccurs = 1;
304 xmlSchemaTypeAnyTypeDef->attributeWildcard = wild;
305 }
306 xmlSchemaTypeAnySimpleTypeDef = xmlSchemaInitBasicType("anySimpleType",
William M. Brack2f2a6632004-08-20 23:09:47 +0000307 XML_SCHEMAS_ANYSIMPLETYPE,
Daniel Veillard01fa6152004-06-29 17:04:39 +0000308 xmlSchemaTypeAnyTypeDef);
309 /*
310 * primitive datatypes
311 */
312 xmlSchemaTypeStringDef = xmlSchemaInitBasicType("string",
313 XML_SCHEMAS_STRING,
314 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000315 xmlSchemaTypeDecimalDef = xmlSchemaInitBasicType("decimal",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000316 XML_SCHEMAS_DECIMAL,
317 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000318 xmlSchemaTypeDateDef = xmlSchemaInitBasicType("date",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000319 XML_SCHEMAS_DATE,
320 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000321 xmlSchemaTypeDatetimeDef = xmlSchemaInitBasicType("dateTime",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000322 XML_SCHEMAS_DATETIME,
323 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000324 xmlSchemaTypeTimeDef = xmlSchemaInitBasicType("time",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000325 XML_SCHEMAS_TIME,
326 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000327 xmlSchemaTypeGYearDef = xmlSchemaInitBasicType("gYear",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000328 XML_SCHEMAS_GYEAR,
329 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000330 xmlSchemaTypeGYearMonthDef = xmlSchemaInitBasicType("gYearMonth",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000331 XML_SCHEMAS_GYEARMONTH,
332 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000333 xmlSchemaTypeGMonthDef = xmlSchemaInitBasicType("gMonth",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000334 XML_SCHEMAS_GMONTH,
335 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000336 xmlSchemaTypeGMonthDayDef = xmlSchemaInitBasicType("gMonthDay",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000337 XML_SCHEMAS_GMONTHDAY,
338 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000339 xmlSchemaTypeGDayDef = xmlSchemaInitBasicType("gDay",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000340 XML_SCHEMAS_GDAY,
341 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000342 xmlSchemaTypeDurationDef = xmlSchemaInitBasicType("duration",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000343 XML_SCHEMAS_DURATION,
344 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000345 xmlSchemaTypeFloatDef = xmlSchemaInitBasicType("float",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000346 XML_SCHEMAS_FLOAT,
347 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000348 xmlSchemaTypeDoubleDef = xmlSchemaInitBasicType("double",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000349 XML_SCHEMAS_DOUBLE,
350 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000351 xmlSchemaTypeBooleanDef = xmlSchemaInitBasicType("boolean",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000352 XML_SCHEMAS_BOOLEAN,
353 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000354 xmlSchemaTypeAnyURIDef = xmlSchemaInitBasicType("anyURI",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000355 XML_SCHEMAS_ANYURI,
356 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard560c2a42003-07-06 21:13:49 +0000357 xmlSchemaTypeHexBinaryDef = xmlSchemaInitBasicType("hexBinary",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000358 XML_SCHEMAS_HEXBINARY,
359 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard1ac24d32003-08-27 14:15:15 +0000360 xmlSchemaTypeBase64BinaryDef
Daniel Veillard01fa6152004-06-29 17:04:39 +0000361 = xmlSchemaInitBasicType("base64Binary", XML_SCHEMAS_BASE64BINARY,
362 xmlSchemaTypeAnySimpleTypeDef);
363 xmlSchemaTypeNotationDef = xmlSchemaInitBasicType("NOTATION",
364 XML_SCHEMAS_NOTATION,
365 xmlSchemaTypeAnySimpleTypeDef);
366 xmlSchemaTypeQNameDef = xmlSchemaInitBasicType("QName",
367 XML_SCHEMAS_QNAME,
368 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard4255d502002-04-16 15:50:10 +0000369
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000370 /*
371 * derived datatypes
372 */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000373 xmlSchemaTypeIntegerDef = xmlSchemaInitBasicType("integer",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000374 XML_SCHEMAS_INTEGER,
375 xmlSchemaTypeDecimalDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000376 xmlSchemaTypeNonPositiveIntegerDef =
377 xmlSchemaInitBasicType("nonPositiveInteger",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000378 XML_SCHEMAS_NPINTEGER,
379 xmlSchemaTypeIntegerDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000380 xmlSchemaTypeNegativeIntegerDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000381 xmlSchemaInitBasicType("negativeInteger", XML_SCHEMAS_NINTEGER,
382 xmlSchemaTypeNonPositiveIntegerDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000383 xmlSchemaTypeLongDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000384 xmlSchemaInitBasicType("long", XML_SCHEMAS_LONG,
385 xmlSchemaTypeIntegerDef);
386 xmlSchemaTypeIntDef = xmlSchemaInitBasicType("int", XML_SCHEMAS_INT,
387 xmlSchemaTypeLongDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000388 xmlSchemaTypeShortDef = xmlSchemaInitBasicType("short",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000389 XML_SCHEMAS_SHORT,
390 xmlSchemaTypeIntDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000391 xmlSchemaTypeByteDef = xmlSchemaInitBasicType("byte",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000392 XML_SCHEMAS_BYTE,
393 xmlSchemaTypeShortDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000394 xmlSchemaTypeNonNegativeIntegerDef =
395 xmlSchemaInitBasicType("nonNegativeInteger",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000396 XML_SCHEMAS_NNINTEGER,
397 xmlSchemaTypeIntegerDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000398 xmlSchemaTypeUnsignedLongDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000399 xmlSchemaInitBasicType("unsignedLong", XML_SCHEMAS_ULONG,
400 xmlSchemaTypeNonNegativeIntegerDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000401 xmlSchemaTypeUnsignedIntDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000402 xmlSchemaInitBasicType("unsignedInt", XML_SCHEMAS_UINT,
403 xmlSchemaTypeUnsignedLongDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000404 xmlSchemaTypeUnsignedShortDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000405 xmlSchemaInitBasicType("unsignedShort", XML_SCHEMAS_USHORT,
406 xmlSchemaTypeUnsignedIntDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000407 xmlSchemaTypeUnsignedByteDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000408 xmlSchemaInitBasicType("unsignedByte", XML_SCHEMAS_UBYTE,
409 xmlSchemaTypeUnsignedShortDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000410 xmlSchemaTypePositiveIntegerDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000411 xmlSchemaInitBasicType("positiveInteger", XML_SCHEMAS_PINTEGER,
412 xmlSchemaTypeNonNegativeIntegerDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000413 xmlSchemaTypeNormStringDef = xmlSchemaInitBasicType("normalizedString",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000414 XML_SCHEMAS_NORMSTRING,
415 xmlSchemaTypeStringDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000416 xmlSchemaTypeTokenDef = xmlSchemaInitBasicType("token",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000417 XML_SCHEMAS_TOKEN,
418 xmlSchemaTypeNormStringDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000419 xmlSchemaTypeLanguageDef = xmlSchemaInitBasicType("language",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000420 XML_SCHEMAS_LANGUAGE,
421 xmlSchemaTypeTokenDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000422 xmlSchemaTypeNameDef = xmlSchemaInitBasicType("Name",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000423 XML_SCHEMAS_NAME,
424 xmlSchemaTypeTokenDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000425 xmlSchemaTypeNmtokenDef = xmlSchemaInitBasicType("NMTOKEN",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000426 XML_SCHEMAS_NMTOKEN,
427 xmlSchemaTypeTokenDef);
428 xmlSchemaTypeNCNameDef = xmlSchemaInitBasicType("NCName",
429 XML_SCHEMAS_NCNAME,
430 xmlSchemaTypeNameDef);
431 xmlSchemaTypeIdDef = xmlSchemaInitBasicType("ID", XML_SCHEMAS_ID,
432 xmlSchemaTypeNCNameDef);
433 xmlSchemaTypeIdrefDef = xmlSchemaInitBasicType("IDREF",
434 XML_SCHEMAS_IDREF,
435 xmlSchemaTypeNCNameDef);
436 xmlSchemaTypeIdrefsDef = xmlSchemaInitBasicType("IDREFS",
437 XML_SCHEMAS_IDREFS,
438 xmlSchemaTypeIdrefDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000439 xmlSchemaTypeNmtokensDef = xmlSchemaInitBasicType("NMTOKENS",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000440 XML_SCHEMAS_NMTOKENS,
441 xmlSchemaTypeNmtokenDef);
442 xmlSchemaTypeEntityDef = xmlSchemaInitBasicType("ENTITY",
443 XML_SCHEMAS_ENTITY,
444 xmlSchemaTypeNCNameDef);
445 xmlSchemaTypeEntitiesDef = xmlSchemaInitBasicType("ENTITIES",
446 XML_SCHEMAS_ENTITIES,
447 xmlSchemaTypeNCNameDef);
Daniel Veillard4255d502002-04-16 15:50:10 +0000448 xmlSchemaTypesInitialized = 1;
449}
450
451/**
452 * xmlSchemaCleanupTypes:
453 *
454 * Cleanup the default XML Schemas type library
455 */
456void
457xmlSchemaCleanupTypes(void) {
458 if (xmlSchemaTypesInitialized == 0)
459 return;
Daniel Veillard01fa6152004-06-29 17:04:39 +0000460 xmlSchemaFreeWildcard(xmlSchemaTypeAnyTypeDef->attributeWildcard);
Daniel Veillard4255d502002-04-16 15:50:10 +0000461 xmlHashFree(xmlSchemaTypesBank, (xmlHashDeallocator) xmlSchemaFreeType);
462 xmlSchemaTypesInitialized = 0;
463}
464
465/**
Daniel Veillard6927b102004-10-27 17:29:04 +0000466 * xmlSchemaIsBuiltInTypeFacet:
Daniel Veillard01fa6152004-06-29 17:04:39 +0000467 * @type: the built-in type
468 * @facetType: the facet type
469 *
470 * Evaluates if a specific facet can be
471 * used in conjunction with a type.
472 *
473 * Returns 1 if the facet can be used with the given built-in type,
474 * 0 otherwise and -1 in case the type is not a built-in type.
475 */
476int
477xmlSchemaIsBuiltInTypeFacet(xmlSchemaTypePtr type, int facetType)
478{
Daniel Veillardce682bc2004-11-05 17:22:25 +0000479 if (type == NULL)
480 return (-1);
Daniel Veillard01fa6152004-06-29 17:04:39 +0000481 if (type->type != XML_SCHEMA_TYPE_BASIC)
482 return (-1);
483 switch (type->builtInType) {
484 case XML_SCHEMAS_BOOLEAN:
485 if ((facetType == XML_SCHEMA_FACET_PATTERN) ||
486 (facetType == XML_SCHEMA_FACET_WHITESPACE))
487 return (1);
488 else
489 return (0);
490 case XML_SCHEMAS_STRING:
491 case XML_SCHEMAS_NOTATION:
492 case XML_SCHEMAS_QNAME:
493 case XML_SCHEMAS_ANYURI:
494 case XML_SCHEMAS_BASE64BINARY:
495 case XML_SCHEMAS_HEXBINARY:
496 if ((facetType == XML_SCHEMA_FACET_LENGTH) ||
497 (facetType == XML_SCHEMA_FACET_MINLENGTH) ||
498 (facetType == XML_SCHEMA_FACET_MAXLENGTH) ||
499 (facetType == XML_SCHEMA_FACET_PATTERN) ||
500 (facetType == XML_SCHEMA_FACET_ENUMERATION) ||
501 (facetType == XML_SCHEMA_FACET_WHITESPACE))
502 return (1);
503 else
504 return (0);
505 case XML_SCHEMAS_DECIMAL:
506 if ((facetType == XML_SCHEMA_FACET_TOTALDIGITS) ||
507 (facetType == XML_SCHEMA_FACET_FRACTIONDIGITS) ||
508 (facetType == XML_SCHEMA_FACET_PATTERN) ||
509 (facetType == XML_SCHEMA_FACET_WHITESPACE) ||
510 (facetType == XML_SCHEMA_FACET_ENUMERATION) ||
511 (facetType == XML_SCHEMA_FACET_MAXINCLUSIVE) ||
512 (facetType == XML_SCHEMA_FACET_MAXEXCLUSIVE) ||
513 (facetType == XML_SCHEMA_FACET_MININCLUSIVE) ||
514 (facetType == XML_SCHEMA_FACET_MINEXCLUSIVE))
515 return (1);
516 else
517 return (0);
518 case XML_SCHEMAS_TIME:
519 case XML_SCHEMAS_GDAY:
520 case XML_SCHEMAS_GMONTH:
521 case XML_SCHEMAS_GMONTHDAY:
522 case XML_SCHEMAS_GYEAR:
523 case XML_SCHEMAS_GYEARMONTH:
524 case XML_SCHEMAS_DATE:
525 case XML_SCHEMAS_DATETIME:
526 case XML_SCHEMAS_DURATION:
527 case XML_SCHEMAS_FLOAT:
528 case XML_SCHEMAS_DOUBLE:
529 if ((facetType == XML_SCHEMA_FACET_PATTERN) ||
530 (facetType == XML_SCHEMA_FACET_ENUMERATION) ||
531 (facetType == XML_SCHEMA_FACET_WHITESPACE) ||
532 (facetType == XML_SCHEMA_FACET_MAXINCLUSIVE) ||
533 (facetType == XML_SCHEMA_FACET_MAXEXCLUSIVE) ||
534 (facetType == XML_SCHEMA_FACET_MININCLUSIVE) ||
535 (facetType == XML_SCHEMA_FACET_MINEXCLUSIVE))
536 return (1);
537 else
538 return (0);
539 default:
Daniel Veillardc7e3cc42004-09-28 12:33:52 +0000540 break;
Daniel Veillard01fa6152004-06-29 17:04:39 +0000541 }
542 return (0);
543}
544
545/**
546 * xmlSchemaGetBuiltInType:
547 * @type: the type of the built in type
548 *
549 * Gives you the type struct for a built-in
550 * type by its type id.
551 *
552 * Returns the type if found, NULL otherwise.
553 */
554xmlSchemaTypePtr
555xmlSchemaGetBuiltInType(xmlSchemaValType type)
556{
557 if (xmlSchemaTypesInitialized == 0)
558 xmlSchemaInitTypes();
559 switch (type) {
560
561 case XML_SCHEMAS_ANYSIMPLETYPE:
562 return (xmlSchemaTypeAnySimpleTypeDef);
563 case XML_SCHEMAS_STRING:
564 return (xmlSchemaTypeStringDef);
565 case XML_SCHEMAS_NORMSTRING:
566 return (xmlSchemaTypeNormStringDef);
567 case XML_SCHEMAS_DECIMAL:
568 return (xmlSchemaTypeDecimalDef);
569 case XML_SCHEMAS_TIME:
570 return (xmlSchemaTypeTimeDef);
571 case XML_SCHEMAS_GDAY:
572 return (xmlSchemaTypeGDayDef);
573 case XML_SCHEMAS_GMONTH:
574 return (xmlSchemaTypeGMonthDef);
575 case XML_SCHEMAS_GMONTHDAY:
576 return (xmlSchemaTypeGMonthDayDef);
577 case XML_SCHEMAS_GYEAR:
578 return (xmlSchemaTypeGYearDef);
579 case XML_SCHEMAS_GYEARMONTH:
580 return (xmlSchemaTypeGYearMonthDef);
581 case XML_SCHEMAS_DATE:
582 return (xmlSchemaTypeDateDef);
583 case XML_SCHEMAS_DATETIME:
584 return (xmlSchemaTypeDatetimeDef);
585 case XML_SCHEMAS_DURATION:
586 return (xmlSchemaTypeDurationDef);
587 case XML_SCHEMAS_FLOAT:
588 return (xmlSchemaTypeFloatDef);
589 case XML_SCHEMAS_DOUBLE:
590 return (xmlSchemaTypeDoubleDef);
591 case XML_SCHEMAS_BOOLEAN:
592 return (xmlSchemaTypeBooleanDef);
593 case XML_SCHEMAS_TOKEN:
594 return (xmlSchemaTypeTokenDef);
595 case XML_SCHEMAS_LANGUAGE:
596 return (xmlSchemaTypeLanguageDef);
597 case XML_SCHEMAS_NMTOKEN:
598 return (xmlSchemaTypeNmtokenDef);
599 case XML_SCHEMAS_NMTOKENS:
600 return (xmlSchemaTypeNmtokensDef);
601 case XML_SCHEMAS_NAME:
602 return (xmlSchemaTypeNameDef);
603 case XML_SCHEMAS_QNAME:
604 return (xmlSchemaTypeQNameDef);
605 case XML_SCHEMAS_NCNAME:
606 return (xmlSchemaTypeNCNameDef);
607 case XML_SCHEMAS_ID:
608 return (xmlSchemaTypeIdDef);
609 case XML_SCHEMAS_IDREF:
610 return (xmlSchemaTypeIdrefDef);
611 case XML_SCHEMAS_IDREFS:
612 return (xmlSchemaTypeIdrefsDef);
613 case XML_SCHEMAS_ENTITY:
614 return (xmlSchemaTypeEntityDef);
615 case XML_SCHEMAS_ENTITIES:
616 return (xmlSchemaTypeEntitiesDef);
617 case XML_SCHEMAS_NOTATION:
618 return (xmlSchemaTypeNotationDef);
619 case XML_SCHEMAS_ANYURI:
620 return (xmlSchemaTypeAnyURIDef);
621 case XML_SCHEMAS_INTEGER:
622 return (xmlSchemaTypeIntegerDef);
623 case XML_SCHEMAS_NPINTEGER:
624 return (xmlSchemaTypeNonPositiveIntegerDef);
625 case XML_SCHEMAS_NINTEGER:
626 return (xmlSchemaTypeNegativeIntegerDef);
627 case XML_SCHEMAS_NNINTEGER:
628 return (xmlSchemaTypeNonNegativeIntegerDef);
629 case XML_SCHEMAS_PINTEGER:
630 return (xmlSchemaTypePositiveIntegerDef);
631 case XML_SCHEMAS_INT:
632 return (xmlSchemaTypeIntDef);
633 case XML_SCHEMAS_UINT:
634 return (xmlSchemaTypeUnsignedIntDef);
635 case XML_SCHEMAS_LONG:
636 return (xmlSchemaTypeLongDef);
637 case XML_SCHEMAS_ULONG:
638 return (xmlSchemaTypeUnsignedLongDef);
639 case XML_SCHEMAS_SHORT:
640 return (xmlSchemaTypeShortDef);
641 case XML_SCHEMAS_USHORT:
642 return (xmlSchemaTypeUnsignedShortDef);
643 case XML_SCHEMAS_BYTE:
644 return (xmlSchemaTypeByteDef);
645 case XML_SCHEMAS_UBYTE:
646 return (xmlSchemaTypeUnsignedByteDef);
647 case XML_SCHEMAS_HEXBINARY:
648 return (xmlSchemaTypeHexBinaryDef);
649 case XML_SCHEMAS_BASE64BINARY:
650 return (xmlSchemaTypeBase64BinaryDef);
651 case XML_SCHEMAS_ANYTYPE:
652 return (xmlSchemaTypeAnyTypeDef);
653 default:
654 return (NULL);
655 }
656}
657
658/**
Daniel Veillard4255d502002-04-16 15:50:10 +0000659 * xmlSchemaNewValue:
660 * @type: the value type
661 *
662 * Allocate a new simple type value
663 *
664 * Returns a pointer to the new value or NULL in case of error
665 */
666static xmlSchemaValPtr
667xmlSchemaNewValue(xmlSchemaValType type) {
668 xmlSchemaValPtr value;
669
670 value = (xmlSchemaValPtr) xmlMalloc(sizeof(xmlSchemaVal));
671 if (value == NULL) {
672 return(NULL);
673 }
674 memset(value, 0, sizeof(xmlSchemaVal));
675 value->type = type;
676 return(value);
677}
678
679/**
680 * xmlSchemaFreeValue:
681 * @value: the value to free
682 *
683 * Cleanup the default XML Schemas type library
684 */
685void
686xmlSchemaFreeValue(xmlSchemaValPtr value) {
687 if (value == NULL)
688 return;
Daniel Veillardc4c21552003-03-29 10:53:38 +0000689 switch (value->type) {
690 case XML_SCHEMAS_STRING:
691 case XML_SCHEMAS_NORMSTRING:
692 case XML_SCHEMAS_TOKEN:
693 case XML_SCHEMAS_LANGUAGE:
694 case XML_SCHEMAS_NMTOKEN:
695 case XML_SCHEMAS_NMTOKENS:
696 case XML_SCHEMAS_NAME:
Daniel Veillardc4c21552003-03-29 10:53:38 +0000697 case XML_SCHEMAS_NCNAME:
698 case XML_SCHEMAS_ID:
699 case XML_SCHEMAS_IDREF:
700 case XML_SCHEMAS_IDREFS:
701 case XML_SCHEMAS_ENTITY:
702 case XML_SCHEMAS_ENTITIES:
703 case XML_SCHEMAS_NOTATION:
704 case XML_SCHEMAS_ANYURI:
705 if (value->value.str != NULL)
706 xmlFree(value->value.str);
707 break;
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000708 case XML_SCHEMAS_QNAME:
709 if (value->value.qname.uri != NULL)
710 xmlFree(value->value.qname.uri);
711 if (value->value.qname.name != NULL)
712 xmlFree(value->value.qname.name);
713 break;
Daniel Veillard70bcb0e2003-08-08 14:00:28 +0000714 case XML_SCHEMAS_HEXBINARY:
715 if (value->value.hex.str != NULL)
716 xmlFree(value->value.hex.str);
717 break;
Daniel Veillard1ac24d32003-08-27 14:15:15 +0000718 case XML_SCHEMAS_BASE64BINARY:
719 if (value->value.base64.str != NULL)
720 xmlFree(value->value.base64.str);
721 break;
Daniel Veillardc4c21552003-03-29 10:53:38 +0000722 default:
723 break;
724 }
Daniel Veillard4255d502002-04-16 15:50:10 +0000725 xmlFree(value);
726}
727
728/**
729 * xmlSchemaGetPredefinedType:
730 * @name: the type name
731 * @ns: the URI of the namespace usually "http://www.w3.org/2001/XMLSchema"
732 *
733 * Lookup a type in the default XML Schemas type library
734 *
735 * Returns the type if found, NULL otherwise
736 */
737xmlSchemaTypePtr
738xmlSchemaGetPredefinedType(const xmlChar *name, const xmlChar *ns) {
739 if (xmlSchemaTypesInitialized == 0)
740 xmlSchemaInitTypes();
741 if (name == NULL)
742 return(NULL);
743 return((xmlSchemaTypePtr) xmlHashLookup2(xmlSchemaTypesBank, name, ns));
744}
Daniel Veillard070803b2002-05-03 07:29:38 +0000745
Daniel Veillard01fa6152004-06-29 17:04:39 +0000746/**
747 * xmlSchemaGetBuiltInListSimpleTypeItemType:
748 * @type: the built-in simple type.
749 *
Daniel Veillard6927b102004-10-27 17:29:04 +0000750 * Lookup function
751 *
Daniel Veillardc0826a72004-08-10 14:17:33 +0000752 * Returns the item type of @type as defined by the built-in datatype
753 * hierarchy of XML Schema Part 2: Datatypes, or NULL in case of an error.
Daniel Veillard01fa6152004-06-29 17:04:39 +0000754 */
755xmlSchemaTypePtr
756xmlSchemaGetBuiltInListSimpleTypeItemType(xmlSchemaTypePtr type)
757{
Daniel Veillard42595322004-11-08 10:52:06 +0000758 if ((type == NULL) || (type->type != XML_SCHEMA_TYPE_BASIC))
Daniel Veillard01fa6152004-06-29 17:04:39 +0000759 return (NULL);
760 switch (type->builtInType) {
761 case XML_SCHEMAS_NMTOKENS:
762 return (xmlSchemaTypeNmtokenDef );
763 case XML_SCHEMAS_IDREFS:
764 return (xmlSchemaTypeIdrefDef);
765 case XML_SCHEMAS_ENTITIES:
766 return (xmlSchemaTypeEntityDef);
767 default:
768 return (NULL);
769 }
770}
771
Daniel Veillard070803b2002-05-03 07:29:38 +0000772/****************************************************************
773 * *
774 * Convenience macros and functions *
775 * *
776 ****************************************************************/
777
778#define IS_TZO_CHAR(c) \
779 ((c == 0) || (c == 'Z') || (c == '+') || (c == '-'))
780
781#define VALID_YEAR(yr) (yr != 0)
782#define VALID_MONTH(mon) ((mon >= 1) && (mon <= 12))
783/* VALID_DAY should only be used when month is unknown */
784#define VALID_DAY(day) ((day >= 1) && (day <= 31))
785#define VALID_HOUR(hr) ((hr >= 0) && (hr <= 23))
786#define VALID_MIN(min) ((min >= 0) && (min <= 59))
787#define VALID_SEC(sec) ((sec >= 0) && (sec < 60))
788#define VALID_TZO(tzo) ((tzo > -1440) && (tzo < 1440))
789#define IS_LEAP(y) \
790 (((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0))
791
Daniel Veillardebe25d42004-03-25 09:35:49 +0000792static const unsigned int daysInMonth[12] =
Daniel Veillard070803b2002-05-03 07:29:38 +0000793 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
Daniel Veillardebe25d42004-03-25 09:35:49 +0000794static const unsigned int daysInMonthLeap[12] =
Daniel Veillard070803b2002-05-03 07:29:38 +0000795 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
796
Daniel Veillard5a872412002-05-22 06:40:27 +0000797#define MAX_DAYINMONTH(yr,mon) \
798 (IS_LEAP(yr) ? daysInMonthLeap[mon - 1] : daysInMonth[mon - 1])
799
Daniel Veillard070803b2002-05-03 07:29:38 +0000800#define VALID_MDAY(dt) \
801 (IS_LEAP(dt->year) ? \
802 (dt->day <= daysInMonthLeap[dt->mon - 1]) : \
803 (dt->day <= daysInMonth[dt->mon - 1]))
804
805#define VALID_DATE(dt) \
806 (VALID_YEAR(dt->year) && VALID_MONTH(dt->mon) && VALID_MDAY(dt))
807
808#define VALID_TIME(dt) \
809 (VALID_HOUR(dt->hour) && VALID_MIN(dt->min) && \
810 VALID_SEC(dt->sec) && VALID_TZO(dt->tzo))
811
812#define VALID_DATETIME(dt) \
813 (VALID_DATE(dt) && VALID_TIME(dt))
814
815#define SECS_PER_MIN (60)
816#define SECS_PER_HOUR (60 * SECS_PER_MIN)
817#define SECS_PER_DAY (24 * SECS_PER_HOUR)
818
Daniel Veillard5a872412002-05-22 06:40:27 +0000819static const long dayInYearByMonth[12] =
820 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
821static const long dayInLeapYearByMonth[12] =
822 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 };
823
824#define DAY_IN_YEAR(day, month, year) \
825 ((IS_LEAP(year) ? \
826 dayInLeapYearByMonth[month - 1] : \
827 dayInYearByMonth[month - 1]) + day)
828
829#ifdef DEBUG
830#define DEBUG_DATE(dt) \
831 xmlGenericError(xmlGenericErrorContext, \
832 "type=%o %04ld-%02u-%02uT%02u:%02u:%03f", \
833 dt->type,dt->value.date.year,dt->value.date.mon, \
834 dt->value.date.day,dt->value.date.hour,dt->value.date.min, \
835 dt->value.date.sec); \
836 if (dt->value.date.tz_flag) \
837 if (dt->value.date.tzo != 0) \
838 xmlGenericError(xmlGenericErrorContext, \
839 "%+05d\n",dt->value.date.tzo); \
840 else \
841 xmlGenericError(xmlGenericErrorContext, "Z\n"); \
842 else \
843 xmlGenericError(xmlGenericErrorContext,"\n")
844#else
845#define DEBUG_DATE(dt)
846#endif
847
Daniel Veillard070803b2002-05-03 07:29:38 +0000848/**
849 * _xmlSchemaParseGYear:
850 * @dt: pointer to a date structure
851 * @str: pointer to the string to analyze
852 *
853 * Parses a xs:gYear without time zone and fills in the appropriate
854 * field of the @dt structure. @str is updated to point just after the
855 * xs:gYear. It is supposed that @dt->year is big enough to contain
856 * the year.
857 *
858 * Returns 0 or the error code
859 */
860static int
861_xmlSchemaParseGYear (xmlSchemaValDatePtr dt, const xmlChar **str) {
862 const xmlChar *cur = *str, *firstChar;
863 int isneg = 0, digcnt = 0;
864
865 if (((*cur < '0') || (*cur > '9')) &&
866 (*cur != '-') && (*cur != '+'))
867 return -1;
868
869 if (*cur == '-') {
870 isneg = 1;
871 cur++;
872 }
873
874 firstChar = cur;
875
876 while ((*cur >= '0') && (*cur <= '9')) {
877 dt->year = dt->year * 10 + (*cur - '0');
878 cur++;
879 digcnt++;
880 }
881
882 /* year must be at least 4 digits (CCYY); over 4
883 * digits cannot have a leading zero. */
884 if ((digcnt < 4) || ((digcnt > 4) && (*firstChar == '0')))
885 return 1;
886
887 if (isneg)
888 dt->year = - dt->year;
889
890 if (!VALID_YEAR(dt->year))
891 return 2;
892
893 *str = cur;
894 return 0;
895}
896
897/**
898 * PARSE_2_DIGITS:
899 * @num: the integer to fill in
900 * @cur: an #xmlChar *
901 * @invalid: an integer
902 *
903 * Parses a 2-digits integer and updates @num with the value. @cur is
904 * updated to point just after the integer.
905 * In case of error, @invalid is set to %TRUE, values of @num and
906 * @cur are undefined.
907 */
908#define PARSE_2_DIGITS(num, cur, invalid) \
909 if ((cur[0] < '0') || (cur[0] > '9') || \
910 (cur[1] < '0') || (cur[1] > '9')) \
911 invalid = 1; \
912 else \
913 num = (cur[0] - '0') * 10 + (cur[1] - '0'); \
914 cur += 2;
915
916/**
917 * PARSE_FLOAT:
918 * @num: the double to fill in
919 * @cur: an #xmlChar *
920 * @invalid: an integer
921 *
922 * Parses a float and updates @num with the value. @cur is
923 * updated to point just after the float. The float must have a
924 * 2-digits integer part and may or may not have a decimal part.
925 * In case of error, @invalid is set to %TRUE, values of @num and
926 * @cur are undefined.
927 */
928#define PARSE_FLOAT(num, cur, invalid) \
929 PARSE_2_DIGITS(num, cur, invalid); \
930 if (!invalid && (*cur == '.')) { \
931 double mult = 1; \
932 cur++; \
933 if ((*cur < '0') || (*cur > '9')) \
934 invalid = 1; \
935 while ((*cur >= '0') && (*cur <= '9')) { \
936 mult /= 10; \
937 num += (*cur - '0') * mult; \
938 cur++; \
939 } \
940 }
941
942/**
943 * _xmlSchemaParseGMonth:
944 * @dt: pointer to a date structure
945 * @str: pointer to the string to analyze
946 *
947 * Parses a xs:gMonth without time zone and fills in the appropriate
948 * field of the @dt structure. @str is updated to point just after the
949 * xs:gMonth.
950 *
951 * Returns 0 or the error code
952 */
953static int
954_xmlSchemaParseGMonth (xmlSchemaValDatePtr dt, const xmlChar **str) {
955 const xmlChar *cur = *str;
956 int ret = 0;
957
958 PARSE_2_DIGITS(dt->mon, cur, ret);
959 if (ret != 0)
960 return ret;
961
962 if (!VALID_MONTH(dt->mon))
963 return 2;
964
965 *str = cur;
966 return 0;
967}
968
969/**
970 * _xmlSchemaParseGDay:
971 * @dt: pointer to a date structure
972 * @str: pointer to the string to analyze
973 *
974 * Parses a xs:gDay without time zone and fills in the appropriate
975 * field of the @dt structure. @str is updated to point just after the
976 * xs:gDay.
977 *
978 * Returns 0 or the error code
979 */
980static int
981_xmlSchemaParseGDay (xmlSchemaValDatePtr dt, const xmlChar **str) {
982 const xmlChar *cur = *str;
983 int ret = 0;
984
985 PARSE_2_DIGITS(dt->day, cur, ret);
986 if (ret != 0)
987 return ret;
988
989 if (!VALID_DAY(dt->day))
990 return 2;
991
992 *str = cur;
993 return 0;
994}
995
996/**
997 * _xmlSchemaParseTime:
998 * @dt: pointer to a date structure
999 * @str: pointer to the string to analyze
1000 *
1001 * Parses a xs:time without time zone and fills in the appropriate
1002 * fields of the @dt structure. @str is updated to point just after the
1003 * xs:time.
1004 * In case of error, values of @dt fields are undefined.
1005 *
1006 * Returns 0 or the error code
1007 */
1008static int
1009_xmlSchemaParseTime (xmlSchemaValDatePtr dt, const xmlChar **str) {
1010 const xmlChar *cur = *str;
1011 unsigned int hour = 0; /* use temp var in case str is not xs:time */
1012 int ret = 0;
1013
1014 PARSE_2_DIGITS(hour, cur, ret);
1015 if (ret != 0)
1016 return ret;
1017
1018 if (*cur != ':')
1019 return 1;
1020 cur++;
1021
1022 /* the ':' insures this string is xs:time */
1023 dt->hour = hour;
1024
1025 PARSE_2_DIGITS(dt->min, cur, ret);
1026 if (ret != 0)
1027 return ret;
1028
1029 if (*cur != ':')
1030 return 1;
1031 cur++;
1032
1033 PARSE_FLOAT(dt->sec, cur, ret);
1034 if (ret != 0)
1035 return ret;
1036
1037 if (!VALID_TIME(dt))
1038 return 2;
1039
1040 *str = cur;
1041 return 0;
1042}
1043
1044/**
1045 * _xmlSchemaParseTimeZone:
1046 * @dt: pointer to a date structure
1047 * @str: pointer to the string to analyze
1048 *
1049 * Parses a time zone without time zone and fills in the appropriate
1050 * field of the @dt structure. @str is updated to point just after the
1051 * time zone.
1052 *
1053 * Returns 0 or the error code
1054 */
1055static int
1056_xmlSchemaParseTimeZone (xmlSchemaValDatePtr dt, const xmlChar **str) {
1057 const xmlChar *cur = *str;
1058 int ret = 0;
1059
1060 if (str == NULL)
1061 return -1;
1062
1063 switch (*cur) {
1064 case 0:
1065 dt->tz_flag = 0;
1066 dt->tzo = 0;
1067 break;
1068
1069 case 'Z':
1070 dt->tz_flag = 1;
1071 dt->tzo = 0;
1072 cur++;
1073 break;
1074
1075 case '+':
1076 case '-': {
1077 int isneg = 0, tmp = 0;
1078 isneg = (*cur == '-');
1079
1080 cur++;
1081
1082 PARSE_2_DIGITS(tmp, cur, ret);
1083 if (ret != 0)
1084 return ret;
1085 if (!VALID_HOUR(tmp))
1086 return 2;
1087
1088 if (*cur != ':')
1089 return 1;
1090 cur++;
1091
1092 dt->tzo = tmp * 60;
1093
1094 PARSE_2_DIGITS(tmp, cur, ret);
1095 if (ret != 0)
1096 return ret;
1097 if (!VALID_MIN(tmp))
1098 return 2;
1099
1100 dt->tzo += tmp;
1101 if (isneg)
1102 dt->tzo = - dt->tzo;
1103
1104 if (!VALID_TZO(dt->tzo))
1105 return 2;
1106
Daniel Veillard5a872412002-05-22 06:40:27 +00001107 dt->tz_flag = 1;
Daniel Veillard070803b2002-05-03 07:29:38 +00001108 break;
1109 }
1110 default:
1111 return 1;
1112 }
1113
1114 *str = cur;
1115 return 0;
1116}
1117
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001118/**
1119 * _xmlSchemaBase64Decode:
1120 * @ch: a character
1121 *
1122 * Converts a base64 encoded character to its base 64 value.
1123 *
1124 * Returns 0-63 (value), 64 (pad), or -1 (not recognized)
1125 */
1126static int
1127_xmlSchemaBase64Decode (const xmlChar ch) {
1128 if (('A' <= ch) && (ch <= 'Z')) return ch - 'A';
1129 if (('a' <= ch) && (ch <= 'z')) return ch - 'a' + 26;
1130 if (('0' <= ch) && (ch <= '9')) return ch - '0' + 52;
1131 if ('+' == ch) return 62;
1132 if ('/' == ch) return 63;
1133 if ('=' == ch) return 64;
1134 return -1;
1135}
1136
Daniel Veillard070803b2002-05-03 07:29:38 +00001137/****************************************************************
1138 * *
1139 * XML Schema Dates/Times Datatypes Handling *
1140 * *
1141 ****************************************************************/
1142
1143/**
1144 * PARSE_DIGITS:
1145 * @num: the integer to fill in
1146 * @cur: an #xmlChar *
1147 * @num_type: an integer flag
1148 *
1149 * Parses a digits integer and updates @num with the value. @cur is
1150 * updated to point just after the integer.
1151 * In case of error, @num_type is set to -1, values of @num and
1152 * @cur are undefined.
1153 */
1154#define PARSE_DIGITS(num, cur, num_type) \
1155 if ((*cur < '0') || (*cur > '9')) \
1156 num_type = -1; \
1157 else \
1158 while ((*cur >= '0') && (*cur <= '9')) { \
1159 num = num * 10 + (*cur - '0'); \
1160 cur++; \
1161 }
1162
1163/**
1164 * PARSE_NUM:
1165 * @num: the double to fill in
1166 * @cur: an #xmlChar *
1167 * @num_type: an integer flag
1168 *
1169 * Parses a float or integer and updates @num with the value. @cur is
1170 * updated to point just after the number. If the number is a float,
1171 * then it must have an integer part and a decimal part; @num_type will
1172 * be set to 1. If there is no decimal part, @num_type is set to zero.
1173 * In case of error, @num_type is set to -1, values of @num and
1174 * @cur are undefined.
1175 */
1176#define PARSE_NUM(num, cur, num_type) \
1177 num = 0; \
1178 PARSE_DIGITS(num, cur, num_type); \
1179 if (!num_type && (*cur == '.')) { \
1180 double mult = 1; \
1181 cur++; \
1182 if ((*cur < '0') || (*cur > '9')) \
1183 num_type = -1; \
1184 else \
1185 num_type = 1; \
1186 while ((*cur >= '0') && (*cur <= '9')) { \
1187 mult /= 10; \
1188 num += (*cur - '0') * mult; \
1189 cur++; \
1190 } \
1191 }
1192
1193/**
Daniel Veillard5a872412002-05-22 06:40:27 +00001194 * xmlSchemaValidateDates:
Daniel Veillard455cc072003-03-31 10:13:23 +00001195 * @type: the expected type or XML_SCHEMAS_UNKNOWN
Daniel Veillard070803b2002-05-03 07:29:38 +00001196 * @dateTime: string to analyze
1197 * @val: the return computed value
1198 *
1199 * Check that @dateTime conforms to the lexical space of one of the date types.
1200 * if true a value is computed and returned in @val.
1201 *
1202 * Returns 0 if this validates, a positive error code number otherwise
1203 * and -1 in case of internal or API error.
1204 */
1205static int
Daniel Veillard455cc072003-03-31 10:13:23 +00001206xmlSchemaValidateDates (xmlSchemaValType type,
Daniel Veillard118aed72002-09-24 14:13:13 +00001207 const xmlChar *dateTime, xmlSchemaValPtr *val) {
Daniel Veillard070803b2002-05-03 07:29:38 +00001208 xmlSchemaValPtr dt;
1209 int ret;
1210 const xmlChar *cur = dateTime;
1211
1212#define RETURN_TYPE_IF_VALID(t) \
1213 if (IS_TZO_CHAR(*cur)) { \
1214 ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur); \
1215 if (ret == 0) { \
1216 if (*cur != 0) \
1217 goto error; \
1218 dt->type = t; \
Daniel Veillard455cc072003-03-31 10:13:23 +00001219 goto done; \
Daniel Veillard070803b2002-05-03 07:29:38 +00001220 } \
1221 }
1222
1223 if (dateTime == NULL)
1224 return -1;
1225
1226 if ((*cur != '-') && (*cur < '0') && (*cur > '9'))
1227 return 1;
1228
1229 dt = xmlSchemaNewValue(XML_SCHEMAS_UNKNOWN);
1230 if (dt == NULL)
1231 return -1;
1232
1233 if ((cur[0] == '-') && (cur[1] == '-')) {
1234 /*
1235 * It's an incomplete date (xs:gMonthDay, xs:gMonth or
1236 * xs:gDay)
1237 */
1238 cur += 2;
1239
1240 /* is it an xs:gDay? */
1241 if (*cur == '-') {
Daniel Veillard455cc072003-03-31 10:13:23 +00001242 if (type == XML_SCHEMAS_GMONTH)
1243 goto error;
Daniel Veillard070803b2002-05-03 07:29:38 +00001244 ++cur;
1245 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
1246 if (ret != 0)
1247 goto error;
1248
1249 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GDAY);
1250
1251 goto error;
1252 }
1253
1254 /*
1255 * it should be an xs:gMonthDay or xs:gMonth
1256 */
1257 ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
1258 if (ret != 0)
1259 goto error;
1260
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001261 /*
1262 * a '-' char could indicate this type is xs:gMonthDay or
1263 * a negative time zone offset. Check for xs:gMonthDay first.
1264 * Also the first three char's of a negative tzo (-MM:SS) can
1265 * appear to be a valid day; so even if the day portion
1266 * of the xs:gMonthDay verifies, we must insure it was not
1267 * a tzo.
1268 */
1269 if (*cur == '-') {
1270 const xmlChar *rewnd = cur;
1271 cur++;
Daniel Veillard070803b2002-05-03 07:29:38 +00001272
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001273 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
1274 if ((ret == 0) && ((*cur == 0) || (*cur != ':'))) {
1275
1276 /*
1277 * we can use the VALID_MDAY macro to validate the month
1278 * and day because the leap year test will flag year zero
1279 * as a leap year (even though zero is an invalid year).
1280 */
1281 if (VALID_MDAY((&(dt->value.date)))) {
1282
1283 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTHDAY);
1284
1285 goto error;
1286 }
1287 }
1288
1289 /*
1290 * not xs:gMonthDay so rewind and check if just xs:gMonth
1291 * with an optional time zone.
1292 */
1293 cur = rewnd;
1294 }
1295
1296 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTH);
Daniel Veillard070803b2002-05-03 07:29:38 +00001297
1298 goto error;
1299 }
1300
1301 /*
1302 * It's a right-truncated date or an xs:time.
1303 * Try to parse an xs:time then fallback on right-truncated dates.
1304 */
1305 if ((*cur >= '0') && (*cur <= '9')) {
1306 ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
1307 if (ret == 0) {
1308 /* it's an xs:time */
1309 RETURN_TYPE_IF_VALID(XML_SCHEMAS_TIME);
1310 }
1311 }
1312
1313 /* fallback on date parsing */
1314 cur = dateTime;
1315
1316 ret = _xmlSchemaParseGYear(&(dt->value.date), &cur);
1317 if (ret != 0)
1318 goto error;
1319
1320 /* is it an xs:gYear? */
1321 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEAR);
1322
1323 if (*cur != '-')
1324 goto error;
1325 cur++;
1326
1327 ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
1328 if (ret != 0)
1329 goto error;
1330
1331 /* is it an xs:gYearMonth? */
1332 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEARMONTH);
1333
1334 if (*cur != '-')
1335 goto error;
1336 cur++;
1337
1338 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
1339 if ((ret != 0) || !VALID_DATE((&(dt->value.date))))
1340 goto error;
1341
1342 /* is it an xs:date? */
1343 RETURN_TYPE_IF_VALID(XML_SCHEMAS_DATE);
1344
1345 if (*cur != 'T')
1346 goto error;
1347 cur++;
1348
1349 /* it should be an xs:dateTime */
1350 ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
1351 if (ret != 0)
1352 goto error;
1353
1354 ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur);
1355 if ((ret != 0) || (*cur != 0) || !VALID_DATETIME((&(dt->value.date))))
1356 goto error;
1357
Daniel Veillard455cc072003-03-31 10:13:23 +00001358
Daniel Veillard070803b2002-05-03 07:29:38 +00001359 dt->type = XML_SCHEMAS_DATETIME;
1360
Daniel Veillard455cc072003-03-31 10:13:23 +00001361done:
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001362#if 1
1363 if ((type != XML_SCHEMAS_UNKNOWN) && (type != dt->type))
1364 goto error;
1365#else
1366 /*
1367 * insure the parsed type is equal to or less significant (right
1368 * truncated) than the desired type.
1369 */
1370 if ((type != XML_SCHEMAS_UNKNOWN) && (type != dt->type)) {
1371
1372 /* time only matches time */
1373 if ((type == XML_SCHEMAS_TIME) && (dt->type == XML_SCHEMAS_TIME))
1374 goto error;
1375
1376 if ((type == XML_SCHEMAS_DATETIME) &&
1377 ((dt->type != XML_SCHEMAS_DATE) ||
1378 (dt->type != XML_SCHEMAS_GYEARMONTH) ||
1379 (dt->type != XML_SCHEMAS_GYEAR)))
1380 goto error;
1381
1382 if ((type == XML_SCHEMAS_DATE) &&
1383 ((dt->type != XML_SCHEMAS_GYEAR) ||
1384 (dt->type != XML_SCHEMAS_GYEARMONTH)))
1385 goto error;
1386
1387 if ((type == XML_SCHEMAS_GYEARMONTH) && (dt->type != XML_SCHEMAS_GYEAR))
1388 goto error;
1389
1390 if ((type == XML_SCHEMAS_GMONTHDAY) && (dt->type != XML_SCHEMAS_GMONTH))
1391 goto error;
1392 }
Daniel Veillard455cc072003-03-31 10:13:23 +00001393#endif
1394
Daniel Veillard070803b2002-05-03 07:29:38 +00001395 if (val != NULL)
1396 *val = dt;
Daniel Veillard80b19092003-03-28 13:29:53 +00001397 else
1398 xmlSchemaFreeValue(dt);
Daniel Veillard070803b2002-05-03 07:29:38 +00001399
1400 return 0;
1401
1402error:
1403 if (dt != NULL)
1404 xmlSchemaFreeValue(dt);
1405 return 1;
1406}
1407
1408/**
Daniel Veillard5a872412002-05-22 06:40:27 +00001409 * xmlSchemaValidateDuration:
Daniel Veillard070803b2002-05-03 07:29:38 +00001410 * @type: the predefined type
1411 * @duration: string to analyze
1412 * @val: the return computed value
1413 *
1414 * Check that @duration conforms to the lexical space of the duration type.
1415 * if true a value is computed and returned in @val.
1416 *
1417 * Returns 0 if this validates, a positive error code number otherwise
1418 * and -1 in case of internal or API error.
1419 */
1420static int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00001421xmlSchemaValidateDuration (xmlSchemaTypePtr type ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +00001422 const xmlChar *duration, xmlSchemaValPtr *val) {
Daniel Veillard070803b2002-05-03 07:29:38 +00001423 const xmlChar *cur = duration;
1424 xmlSchemaValPtr dur;
1425 int isneg = 0;
1426 unsigned int seq = 0;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001427 double num;
1428 int num_type = 0; /* -1 = invalid, 0 = int, 1 = floating */
1429 const xmlChar desig[] = {'Y', 'M', 'D', 'H', 'M', 'S'};
1430 const double multi[] = { 0.0, 0.0, 86400.0, 3600.0, 60.0, 1.0, 0.0};
Daniel Veillard070803b2002-05-03 07:29:38 +00001431
1432 if (duration == NULL)
1433 return -1;
1434
1435 if (*cur == '-') {
1436 isneg = 1;
1437 cur++;
1438 }
1439
1440 /* duration must start with 'P' (after sign) */
1441 if (*cur++ != 'P')
1442 return 1;
1443
Daniel Veillard80b19092003-03-28 13:29:53 +00001444 if (*cur == 0)
1445 return 1;
1446
Daniel Veillard070803b2002-05-03 07:29:38 +00001447 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
1448 if (dur == NULL)
1449 return -1;
1450
1451 while (*cur != 0) {
Daniel Veillard070803b2002-05-03 07:29:38 +00001452
1453 /* input string should be empty or invalid date/time item */
1454 if (seq >= sizeof(desig))
1455 goto error;
1456
1457 /* T designator must be present for time items */
1458 if (*cur == 'T') {
1459 if (seq <= 3) {
1460 seq = 3;
1461 cur++;
1462 } else
1463 return 1;
1464 } else if (seq == 3)
1465 goto error;
1466
1467 /* parse the number portion of the item */
1468 PARSE_NUM(num, cur, num_type);
1469
1470 if ((num_type == -1) || (*cur == 0))
1471 goto error;
1472
1473 /* update duration based on item type */
1474 while (seq < sizeof(desig)) {
1475 if (*cur == desig[seq]) {
1476
1477 /* verify numeric type; only seconds can be float */
1478 if ((num_type != 0) && (seq < (sizeof(desig)-1)))
1479 goto error;
1480
1481 switch (seq) {
1482 case 0:
1483 dur->value.dur.mon = (long)num * 12;
1484 break;
1485 case 1:
1486 dur->value.dur.mon += (long)num;
1487 break;
1488 default:
1489 /* convert to seconds using multiplier */
1490 dur->value.dur.sec += num * multi[seq];
1491 seq++;
1492 break;
1493 }
1494
1495 break; /* exit loop */
1496 }
1497 /* no date designators found? */
1498 if (++seq == 3)
1499 goto error;
1500 }
1501 cur++;
1502 }
1503
1504 if (isneg) {
1505 dur->value.dur.mon = -dur->value.dur.mon;
1506 dur->value.dur.day = -dur->value.dur.day;
1507 dur->value.dur.sec = -dur->value.dur.sec;
1508 }
1509
1510 if (val != NULL)
1511 *val = dur;
Daniel Veillard80b19092003-03-28 13:29:53 +00001512 else
1513 xmlSchemaFreeValue(dur);
Daniel Veillard070803b2002-05-03 07:29:38 +00001514
1515 return 0;
1516
1517error:
1518 if (dur != NULL)
1519 xmlSchemaFreeValue(dur);
1520 return 1;
1521}
1522
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001523/**
1524 * xmlSchemaStrip:
1525 * @value: a value
1526 *
1527 * Removes the leading and ending spaces of a string
1528 *
1529 * Returns the new string or NULL if no change was required.
1530 */
1531static xmlChar *
1532xmlSchemaStrip(const xmlChar *value) {
1533 const xmlChar *start = value, *end, *f;
1534
1535 if (value == NULL) return(NULL);
William M. Brack76e95df2003-10-18 16:20:14 +00001536 while ((*start != 0) && (IS_BLANK_CH(*start))) start++;
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001537 end = start;
1538 while (*end != 0) end++;
1539 f = end;
1540 end--;
William M. Brack76e95df2003-10-18 16:20:14 +00001541 while ((end > start) && (IS_BLANK_CH(*end))) end--;
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001542 end++;
1543 if ((start == value) && (f == end)) return(NULL);
1544 return(xmlStrndup(start, end - start));
1545}
Daniel Veillard96a4b252003-02-06 08:22:32 +00001546
1547/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001548 * xmlSchemaCollapseString:
1549 * @value: a value
1550 *
1551 * Removes and normalize white spaces in the string
1552 *
1553 * Returns the new string or NULL if no change was required.
1554 */
Daniel Veillard01fa6152004-06-29 17:04:39 +00001555xmlChar *
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001556xmlSchemaCollapseString(const xmlChar *value) {
1557 const xmlChar *start = value, *end, *f;
1558 xmlChar *g;
1559 int col = 0;
1560
1561 if (value == NULL) return(NULL);
William M. Brack76e95df2003-10-18 16:20:14 +00001562 while ((*start != 0) && (IS_BLANK_CH(*start))) start++;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001563 end = start;
1564 while (*end != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00001565 if ((*end == ' ') && (IS_BLANK_CH(end[1]))) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001566 col = end - start;
1567 break;
1568 } else if ((*end == 0xa) || (*end == 0x9) || (*end == 0xd)) {
1569 col = end - start;
1570 break;
1571 }
1572 end++;
1573 }
1574 if (col == 0) {
1575 f = end;
1576 end--;
William M. Brack76e95df2003-10-18 16:20:14 +00001577 while ((end > start) && (IS_BLANK_CH(*end))) end--;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001578 end++;
1579 if ((start == value) && (f == end)) return(NULL);
1580 return(xmlStrndup(start, end - start));
1581 }
1582 start = xmlStrdup(start);
1583 if (start == NULL) return(NULL);
1584 g = (xmlChar *) (start + col);
1585 end = g;
1586 while (*end != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00001587 if (IS_BLANK_CH(*end)) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001588 end++;
William M. Brack76e95df2003-10-18 16:20:14 +00001589 while (IS_BLANK_CH(*end)) end++;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001590 if (*end != 0)
1591 *g++ = ' ';
1592 } else
1593 *g++ = *end++;
1594 }
1595 *g = 0;
1596 return((xmlChar *) start);
1597}
1598
1599/**
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001600 * xmlSchemaValAtomicListNode:
1601 * @type: the predefined atomic type for a token in the list
1602 * @value: the list value to check
1603 * @ret: the return computed value
1604 * @node: the node containing the value
1605 *
1606 * Check that a value conforms to the lexical space of the predefined
1607 * list type. if true a value is computed and returned in @ret.
1608 *
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001609 * Returns the number of items if this validates, a negative error code
1610 * number otherwise
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001611 */
1612static int
1613xmlSchemaValAtomicListNode(xmlSchemaTypePtr type, const xmlChar *value,
1614 xmlSchemaValPtr *ret, xmlNodePtr node) {
1615 xmlChar *val, *cur, *endval;
1616 int nb_values = 0;
Daniel Veillard580ced82003-03-21 21:22:48 +00001617 int tmp = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001618
1619 if (value == NULL) {
1620 return(-1);
1621 }
1622 val = xmlStrdup(value);
1623 if (val == NULL) {
1624 return(-1);
1625 }
1626 cur = val;
1627 /*
1628 * Split the list
1629 */
William M. Brack76e95df2003-10-18 16:20:14 +00001630 while (IS_BLANK_CH(*cur)) *cur++ = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001631 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00001632 if (IS_BLANK_CH(*cur)) {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001633 *cur = 0;
1634 cur++;
William M. Brack76e95df2003-10-18 16:20:14 +00001635 while (IS_BLANK_CH(*cur)) *cur++ = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001636 } else {
1637 nb_values++;
1638 cur++;
William M. Brack76e95df2003-10-18 16:20:14 +00001639 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001640 }
1641 }
1642 if (nb_values == 0) {
1643 if (ret != NULL) {
1644 TODO
1645 }
1646 xmlFree(val);
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001647 return(nb_values);
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001648 }
1649 endval = cur;
1650 cur = val;
1651 while ((*cur == 0) && (cur != endval)) cur++;
1652 while (cur != endval) {
1653 tmp = xmlSchemaValPredefTypeNode(type, cur, NULL, node);
1654 if (tmp != 0)
1655 break;
1656 while (*cur != 0) cur++;
1657 while ((*cur == 0) && (cur != endval)) cur++;
1658 }
1659 xmlFree(val);
1660 if (ret != NULL) {
1661 TODO
1662 }
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001663 if (tmp == 0)
1664 return(nb_values);
1665 return(-1);
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001666}
1667
1668/**
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001669 * xmlSchemaParseUInt:
1670 * @str: pointer to the string R/W
1671 * @llo: pointer to the low result
1672 * @lmi: pointer to the mid result
1673 * @lhi: pointer to the high result
1674 *
1675 * Parse an unsigned long into 3 fields.
1676 *
1677 * Returns the number of chars parsed or -1 if overflow of the capacity
1678 */
1679static int
1680xmlSchemaParseUInt(const xmlChar **str, unsigned long *llo,
1681 unsigned long *lmi, unsigned long *lhi) {
1682 unsigned long lo = 0, mi = 0, hi = 0;
1683 const xmlChar *tmp, *cur = *str;
1684 int ret = 0, i = 0;
1685
1686 while (*cur == '0') {
1687 ret++;
1688 cur++;
1689 }
1690 tmp = cur;
1691 while ((*tmp != 0) && (*tmp >= '0') && (*tmp <= '9')) {
1692 i++;tmp++;ret++;
1693 }
1694 if (i > 24) {
1695 *str = tmp;
1696 return(-1);
1697 }
1698 while (i > 16) {
1699 hi = hi * 10 + (*cur++ - '0');
1700 i--;
1701 }
1702 while (i > 8) {
1703 mi = mi * 10 + (*cur++ - '0');
1704 i--;
1705 }
1706 while (i > 0) {
1707 lo = lo * 10 + (*cur++ - '0');
1708 i--;
1709 }
1710
1711 *str = cur;
1712 *llo = lo;
1713 *lmi = mi;
1714 *lhi = hi;
1715 return(ret);
1716}
1717
1718/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001719 * xmlSchemaValAtomicType:
1720 * @type: the predefined type
1721 * @value: the value to check
1722 * @val: the return computed value
1723 * @node: the node containing the value
1724 * flags: flags to control the vlidation
1725 *
1726 * Check that a value conforms to the lexical space of the atomic type.
1727 * if true a value is computed and returned in @val.
Daniel Veillard01fa6152004-06-29 17:04:39 +00001728 * This checks the value space for list types as well (IDREFS, NMTOKENS).
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001729 *
1730 * Returns 0 if this validates, a positive error code number otherwise
1731 * and -1 in case of internal or API error.
1732 */
1733static int
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001734xmlSchemaValAtomicType(xmlSchemaTypePtr type, const xmlChar * value,
1735 xmlSchemaValPtr * val, xmlNodePtr node, int flags)
1736{
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001737 xmlSchemaValPtr v;
1738 xmlChar *norm = NULL;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001739 int ret = 0;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001740
1741 if (xmlSchemaTypesInitialized == 0)
Daniel Veillard01fa6152004-06-29 17:04:39 +00001742 xmlSchemaInitTypes();
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001743 if (type == NULL)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001744 return (-1);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001745
Daniel Veillardeebd6332004-08-26 10:30:44 +00001746 /*
1747 * validating a non existant text node is similar to validating
1748 * an empty one.
1749 */
1750 if (value == NULL)
1751 value = BAD_CAST "";
1752
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001753 if (val != NULL)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001754 *val = NULL;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001755 if ((flags == 0) && (value != NULL)) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00001756 if ((type->builtInType != XML_SCHEMAS_STRING) &&
1757 (type->builtInType != XML_SCHEMAS_NORMSTRING)) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001758 norm = xmlSchemaCollapseString(value);
1759 if (norm != NULL)
1760 value = norm;
1761 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001762 }
1763
Daniel Veillard01fa6152004-06-29 17:04:39 +00001764 switch (type->builtInType) {
William M. Brack2f2a6632004-08-20 23:09:47 +00001765 case XML_SCHEMAS_UNKNOWN:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001766 goto error;
William M. Brack2f2a6632004-08-20 23:09:47 +00001767 case XML_SCHEMAS_ANYTYPE:
1768 case XML_SCHEMAS_ANYSIMPLETYPE:
1769 goto return0;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001770 case XML_SCHEMAS_STRING:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001771 goto return0;
Daniel Veillard1516d5b2004-01-22 07:27:45 +00001772 case XML_SCHEMAS_NORMSTRING:{
1773 const xmlChar *cur = value;
1774
1775 while (*cur != 0) {
1776 if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) {
1777 goto return1;
1778 } else {
1779 cur++;
1780 }
1781 }
1782 if (val != NULL) {
1783 v = xmlSchemaNewValue(XML_SCHEMAS_NORMSTRING);
1784 if (v != NULL) {
1785 v->value.str = xmlStrdup(value);
1786 *val = v;
1787 } else {
1788 goto error;
1789 }
1790 }
1791 goto return0;
1792 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001793 case XML_SCHEMAS_DECIMAL:{
1794 const xmlChar *cur = value, *tmp;
1795 unsigned int frac = 0, len, neg = 0;
1796 unsigned long base = 0;
1797
1798 if (cur == NULL)
1799 goto return1;
1800 if (*cur == '+')
1801 cur++;
1802 else if (*cur == '-') {
1803 neg = 1;
1804 cur++;
1805 }
1806 tmp = cur;
1807 while ((*cur >= '0') && (*cur <= '9')) {
1808 base = base * 10 + (*cur - '0');
1809 cur++;
1810 }
1811 len = cur - tmp;
1812 if (*cur == '.') {
1813 cur++;
1814 tmp = cur;
1815 while ((*cur >= '0') && (*cur <= '9')) {
1816 base = base * 10 + (*cur - '0');
1817 cur++;
1818 }
1819 frac = cur - tmp;
1820 }
1821 if (*cur != 0)
1822 goto return1;
1823 if (val != NULL) {
1824 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
1825 if (v != NULL) {
1826 v->value.decimal.lo = base;
1827 v->value.decimal.sign = neg;
1828 v->value.decimal.frac = frac;
1829 v->value.decimal.total = frac + len;
1830 *val = v;
1831 }
1832 }
1833 goto return0;
1834 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001835 case XML_SCHEMAS_TIME:
1836 case XML_SCHEMAS_GDAY:
1837 case XML_SCHEMAS_GMONTH:
1838 case XML_SCHEMAS_GMONTHDAY:
1839 case XML_SCHEMAS_GYEAR:
1840 case XML_SCHEMAS_GYEARMONTH:
1841 case XML_SCHEMAS_DATE:
1842 case XML_SCHEMAS_DATETIME:
Daniel Veillard01fa6152004-06-29 17:04:39 +00001843 ret = xmlSchemaValidateDates(type->builtInType, value, val);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001844 break;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001845 case XML_SCHEMAS_DURATION:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001846 ret = xmlSchemaValidateDuration(type, value, val);
1847 break;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001848 case XML_SCHEMAS_FLOAT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001849 case XML_SCHEMAS_DOUBLE:{
1850 const xmlChar *cur = value;
1851 int neg = 0;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001852
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001853 if (cur == NULL)
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00001854 goto return1;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001855 if ((cur[0] == 'N') && (cur[1] == 'a') && (cur[2] == 'N')) {
1856 cur += 3;
1857 if (*cur != 0)
1858 goto return1;
1859 if (val != NULL) {
1860 if (type == xmlSchemaTypeFloatDef) {
1861 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1862 if (v != NULL) {
1863 v->value.f = (float) xmlXPathNAN;
1864 } else {
1865 xmlSchemaFreeValue(v);
1866 goto error;
1867 }
1868 } else {
1869 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1870 if (v != NULL) {
1871 v->value.d = xmlXPathNAN;
1872 } else {
1873 xmlSchemaFreeValue(v);
1874 goto error;
1875 }
1876 }
1877 *val = v;
1878 }
1879 goto return0;
1880 }
1881 if (*cur == '-') {
1882 neg = 1;
1883 cur++;
1884 }
1885 if ((cur[0] == 'I') && (cur[1] == 'N') && (cur[2] == 'F')) {
1886 cur += 3;
1887 if (*cur != 0)
1888 goto return1;
1889 if (val != NULL) {
1890 if (type == xmlSchemaTypeFloatDef) {
1891 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1892 if (v != NULL) {
1893 if (neg)
1894 v->value.f = (float) xmlXPathNINF;
1895 else
1896 v->value.f = (float) xmlXPathPINF;
1897 } else {
1898 xmlSchemaFreeValue(v);
1899 goto error;
1900 }
1901 } else {
1902 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1903 if (v != NULL) {
1904 if (neg)
1905 v->value.d = xmlXPathNINF;
1906 else
1907 v->value.d = xmlXPathPINF;
1908 } else {
1909 xmlSchemaFreeValue(v);
1910 goto error;
1911 }
1912 }
1913 *val = v;
1914 }
1915 goto return0;
1916 }
1917 if ((neg == 0) && (*cur == '+'))
1918 cur++;
1919 if ((cur[0] == 0) || (cur[0] == '+') || (cur[0] == '-'))
1920 goto return1;
1921 while ((*cur >= '0') && (*cur <= '9')) {
1922 cur++;
1923 }
1924 if (*cur == '.') {
1925 cur++;
1926 while ((*cur >= '0') && (*cur <= '9'))
1927 cur++;
1928 }
1929 if ((*cur == 'e') || (*cur == 'E')) {
1930 cur++;
1931 if ((*cur == '-') || (*cur == '+'))
1932 cur++;
1933 while ((*cur >= '0') && (*cur <= '9'))
1934 cur++;
1935 }
1936 if (*cur != 0)
1937 goto return1;
1938 if (val != NULL) {
1939 if (type == xmlSchemaTypeFloatDef) {
1940 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1941 if (v != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001942 if (sscanf((const char *) value, "%f",
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001943 &(v->value.f)) == 1) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00001944 *val = v;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001945 } else {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001946 xmlSchemaFreeValue(v);
1947 goto return1;
1948 }
1949 } else {
1950 goto error;
1951 }
1952 } else {
1953 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1954 if (v != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001955 if (sscanf((const char *) value, "%lf",
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001956 &(v->value.d)) == 1) {
1957 *val = v;
1958 } else {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001959 xmlSchemaFreeValue(v);
1960 goto return1;
1961 }
1962 } else {
1963 goto error;
1964 }
1965 }
1966 }
1967 goto return0;
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00001968 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001969 case XML_SCHEMAS_BOOLEAN:{
1970 const xmlChar *cur = value;
1971
1972 if ((cur[0] == '0') && (cur[1] == 0))
1973 ret = 0;
1974 else if ((cur[0] == '1') && (cur[1] == 0))
1975 ret = 1;
1976 else if ((cur[0] == 't') && (cur[1] == 'r')
1977 && (cur[2] == 'u') && (cur[3] == 'e')
1978 && (cur[4] == 0))
1979 ret = 1;
1980 else if ((cur[0] == 'f') && (cur[1] == 'a')
1981 && (cur[2] == 'l') && (cur[3] == 's')
1982 && (cur[4] == 'e') && (cur[5] == 0))
1983 ret = 0;
1984 else
1985 goto return1;
1986 if (val != NULL) {
1987 v = xmlSchemaNewValue(XML_SCHEMAS_BOOLEAN);
1988 if (v != NULL) {
1989 v->value.b = ret;
1990 *val = v;
1991 } else {
1992 goto error;
1993 }
1994 }
1995 goto return0;
1996 }
1997 case XML_SCHEMAS_TOKEN:{
1998 const xmlChar *cur = value;
1999
William M. Brack76e95df2003-10-18 16:20:14 +00002000 if (IS_BLANK_CH(*cur))
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002001 goto return1;
2002
2003 while (*cur != 0) {
2004 if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) {
2005 goto return1;
2006 } else if (*cur == ' ') {
2007 cur++;
2008 if (*cur == 0)
2009 goto return1;
2010 if (*cur == ' ')
2011 goto return1;
2012 } else {
2013 cur++;
2014 }
2015 }
2016 if (val != NULL) {
2017 v = xmlSchemaNewValue(XML_SCHEMAS_TOKEN);
2018 if (v != NULL) {
2019 v->value.str = xmlStrdup(value);
2020 *val = v;
2021 } else {
2022 goto error;
2023 }
2024 }
2025 goto return0;
2026 }
2027 case XML_SCHEMAS_LANGUAGE:
2028 if (xmlCheckLanguageID(value) == 1) {
2029 if (val != NULL) {
2030 v = xmlSchemaNewValue(XML_SCHEMAS_LANGUAGE);
2031 if (v != NULL) {
2032 v->value.str = xmlStrdup(value);
2033 *val = v;
2034 } else {
2035 goto error;
2036 }
2037 }
2038 goto return0;
2039 }
2040 goto return1;
2041 case XML_SCHEMAS_NMTOKEN:
2042 if (xmlValidateNMToken(value, 1) == 0) {
2043 if (val != NULL) {
2044 v = xmlSchemaNewValue(XML_SCHEMAS_NMTOKEN);
2045 if (v != NULL) {
2046 v->value.str = xmlStrdup(value);
2047 *val = v;
2048 } else {
2049 goto error;
2050 }
2051 }
2052 goto return0;
2053 }
2054 goto return1;
2055 case XML_SCHEMAS_NMTOKENS:
2056 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeNmtokenDef,
2057 value, val, node);
2058 if (ret > 0)
2059 ret = 0;
2060 else
2061 ret = 1;
2062 goto done;
2063 case XML_SCHEMAS_NAME:
2064 ret = xmlValidateName(value, 1);
2065 if ((ret == 0) && (val != NULL)) {
2066 TODO;
2067 }
2068 goto done;
2069 case XML_SCHEMAS_QNAME:{
2070 xmlChar *uri = NULL;
2071 xmlChar *local = NULL;
2072
2073 ret = xmlValidateQName(value, 1);
2074 if ((ret == 0) && (node != NULL)) {
2075 xmlChar *prefix;
2076
2077 local = xmlSplitQName2(value, &prefix);
2078 if (prefix != NULL) {
2079 xmlNsPtr ns;
2080
2081 ns = xmlSearchNs(node->doc, node, prefix);
2082 if (ns == NULL)
2083 ret = 1;
2084 else if (val != NULL)
2085 uri = xmlStrdup(ns->href);
2086 }
2087 if ((local != NULL) && ((val == NULL) || (ret != 0)))
2088 xmlFree(local);
2089 if (prefix != NULL)
2090 xmlFree(prefix);
2091 }
2092 if ((ret == 0) && (val != NULL)) {
2093 v = xmlSchemaNewValue(XML_SCHEMAS_QNAME);
2094 if (v != NULL) {
2095 if (local != NULL)
2096 v->value.qname.name = local;
2097 else
2098 v->value.qname.name = xmlStrdup(value);
2099 if (uri != NULL)
2100 v->value.qname.uri = uri;
2101
2102 *val = v;
2103 } else {
2104 if (local != NULL)
2105 xmlFree(local);
2106 if (uri != NULL)
2107 xmlFree(uri);
2108 goto error;
2109 }
2110 }
2111 goto done;
2112 }
2113 case XML_SCHEMAS_NCNAME:
2114 ret = xmlValidateNCName(value, 1);
2115 if ((ret == 0) && (val != NULL)) {
2116 v = xmlSchemaNewValue(XML_SCHEMAS_NCNAME);
2117 if (v != NULL) {
2118 v->value.str = xmlStrdup(value);
2119 *val = v;
2120 } else {
2121 goto error;
2122 }
2123 }
2124 goto done;
2125 case XML_SCHEMAS_ID:
2126 ret = xmlValidateNCName(value, 1);
2127 if ((ret == 0) && (val != NULL)) {
2128 v = xmlSchemaNewValue(XML_SCHEMAS_ID);
2129 if (v != NULL) {
2130 v->value.str = xmlStrdup(value);
2131 *val = v;
2132 } else {
2133 goto error;
2134 }
2135 }
2136 if ((ret == 0) && (node != NULL) &&
2137 (node->type == XML_ATTRIBUTE_NODE)) {
2138 xmlAttrPtr attr = (xmlAttrPtr) node;
2139
2140 /*
2141 * NOTE: the IDness might have already be declared in the DTD
2142 */
2143 if (attr->atype != XML_ATTRIBUTE_ID) {
2144 xmlIDPtr res;
2145 xmlChar *strip;
2146
2147 strip = xmlSchemaStrip(value);
2148 if (strip != NULL) {
2149 res = xmlAddID(NULL, node->doc, strip, attr);
2150 xmlFree(strip);
2151 } else
2152 res = xmlAddID(NULL, node->doc, value, attr);
2153 if (res == NULL) {
2154 ret = 2;
2155 } else {
2156 attr->atype = XML_ATTRIBUTE_ID;
2157 }
2158 }
2159 }
2160 goto done;
2161 case XML_SCHEMAS_IDREF:
2162 ret = xmlValidateNCName(value, 1);
2163 if ((ret == 0) && (val != NULL)) {
2164 TODO;
2165 }
2166 if ((ret == 0) && (node != NULL) &&
2167 (node->type == XML_ATTRIBUTE_NODE)) {
2168 xmlAttrPtr attr = (xmlAttrPtr) node;
2169 xmlChar *strip;
2170
2171 strip = xmlSchemaStrip(value);
2172 if (strip != NULL) {
2173 xmlAddRef(NULL, node->doc, strip, attr);
2174 xmlFree(strip);
2175 } else
2176 xmlAddRef(NULL, node->doc, value, attr);
2177 attr->atype = XML_ATTRIBUTE_IDREF;
2178 }
2179 goto done;
2180 case XML_SCHEMAS_IDREFS:
2181 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeIdrefDef,
2182 value, val, node);
2183 if (ret < 0)
2184 ret = 2;
2185 else
2186 ret = 0;
2187 if ((ret == 0) && (node != NULL) &&
2188 (node->type == XML_ATTRIBUTE_NODE)) {
2189 xmlAttrPtr attr = (xmlAttrPtr) node;
2190
2191 attr->atype = XML_ATTRIBUTE_IDREFS;
2192 }
2193 goto done;
2194 case XML_SCHEMAS_ENTITY:{
2195 xmlChar *strip;
2196
2197 ret = xmlValidateNCName(value, 1);
2198 if ((node == NULL) || (node->doc == NULL))
2199 ret = 3;
2200 if (ret == 0) {
2201 xmlEntityPtr ent;
2202
2203 strip = xmlSchemaStrip(value);
2204 if (strip != NULL) {
2205 ent = xmlGetDocEntity(node->doc, strip);
2206 xmlFree(strip);
2207 } else {
2208 ent = xmlGetDocEntity(node->doc, value);
2209 }
2210 if ((ent == NULL) ||
2211 (ent->etype !=
2212 XML_EXTERNAL_GENERAL_UNPARSED_ENTITY))
2213 ret = 4;
2214 }
2215 if ((ret == 0) && (val != NULL)) {
2216 TODO;
2217 }
2218 if ((ret == 0) && (node != NULL) &&
2219 (node->type == XML_ATTRIBUTE_NODE)) {
2220 xmlAttrPtr attr = (xmlAttrPtr) node;
2221
2222 attr->atype = XML_ATTRIBUTE_ENTITY;
2223 }
2224 goto done;
2225 }
2226 case XML_SCHEMAS_ENTITIES:
2227 if ((node == NULL) || (node->doc == NULL))
2228 goto return3;
2229 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeEntityDef,
2230 value, val, node);
2231 if (ret <= 0)
2232 ret = 1;
2233 else
2234 ret = 0;
2235 if ((ret == 0) && (node != NULL) &&
2236 (node->type == XML_ATTRIBUTE_NODE)) {
2237 xmlAttrPtr attr = (xmlAttrPtr) node;
2238
2239 attr->atype = XML_ATTRIBUTE_ENTITIES;
2240 }
2241 goto done;
2242 case XML_SCHEMAS_NOTATION:{
2243 xmlChar *uri = NULL;
2244 xmlChar *local = NULL;
2245
2246 ret = xmlValidateQName(value, 1);
2247 if ((ret == 0) && (node != NULL)) {
2248 xmlChar *prefix;
2249
2250 local = xmlSplitQName2(value, &prefix);
2251 if (prefix != NULL) {
2252 xmlNsPtr ns;
2253
2254 ns = xmlSearchNs(node->doc, node, prefix);
2255 if (ns == NULL)
2256 ret = 1;
2257 else if (val != NULL)
2258 uri = xmlStrdup(ns->href);
2259 }
2260 if ((local != NULL) && ((val == NULL) || (ret != 0)))
2261 xmlFree(local);
2262 if (prefix != NULL)
2263 xmlFree(prefix);
2264 }
2265 if ((node == NULL) || (node->doc == NULL))
2266 ret = 3;
2267 if (ret == 0) {
2268 ret = xmlValidateNotationUse(NULL, node->doc, value);
2269 if (ret == 1)
2270 ret = 0;
2271 else
2272 ret = 1;
2273 }
2274 if ((ret == 0) && (val != NULL)) {
2275 v = xmlSchemaNewValue(XML_SCHEMAS_NOTATION);
2276 if (v != NULL) {
2277 if (local != NULL)
2278 v->value.qname.name = local;
2279 else
2280 v->value.qname.name = xmlStrdup(value);
2281 if (uri != NULL)
2282 v->value.qname.uri = uri;
2283
2284 *val = v;
2285 } else {
2286 if (local != NULL)
2287 xmlFree(local);
2288 if (uri != NULL)
2289 xmlFree(uri);
2290 goto error;
2291 }
2292 }
2293 goto done;
2294 }
2295 case XML_SCHEMAS_ANYURI:{
Daniel Veillard11c466a2004-03-14 12:20:15 +00002296 if (*value != 0) {
2297 xmlURIPtr uri = xmlParseURI((const char *) value);
2298 if (uri == NULL)
2299 goto return1;
2300 xmlFreeURI(uri);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002301 }
Daniel Veillard11c466a2004-03-14 12:20:15 +00002302
2303 if (val != NULL) {
2304 v = xmlSchemaNewValue(XML_SCHEMAS_ANYURI);
2305 if (v == NULL)
2306 goto error;
2307 v->value.str = xmlStrdup(value);
2308 *val = v;
2309 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002310 goto return0;
2311 }
2312 case XML_SCHEMAS_HEXBINARY:{
2313 const xmlChar *cur = value;
2314 xmlChar *base;
2315 int total, i = 0;
2316
Daniel Veillardf34a20e2004-08-31 08:42:17 +00002317 if (cur == NULL)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002318 goto return1;
2319
2320 while (((*cur >= '0') && (*cur <= '9')) ||
2321 ((*cur >= 'A') && (*cur <= 'F')) ||
2322 ((*cur >= 'a') && (*cur <= 'f'))) {
2323 i++;
2324 cur++;
2325 }
2326
2327 if (*cur != 0)
2328 goto return1;
2329 if ((i % 2) != 0)
2330 goto return1;
2331
2332 if (val != NULL) {
2333
2334 v = xmlSchemaNewValue(XML_SCHEMAS_HEXBINARY);
2335 if (v == NULL)
2336 goto error;
2337
2338 cur = xmlStrdup(value);
2339 if (cur == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002340 xmlSchemaTypeErrMemory(node, "allocating hexbin data");
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002341 xmlFree(v);
2342 goto return1;
2343 }
2344
2345 total = i / 2; /* number of octets */
2346
2347 base = (xmlChar *) cur;
2348 while (i-- > 0) {
2349 if (*base >= 'a')
2350 *base = *base - ('a' - 'A');
2351 base++;
2352 }
2353
2354 v->value.hex.str = (xmlChar *) cur;
2355 v->value.hex.total = total;
2356 *val = v;
2357 }
2358 goto return0;
2359 }
2360 case XML_SCHEMAS_BASE64BINARY:{
2361 /* ISSUE:
2362 *
2363 * Ignore all stray characters? (yes, currently)
2364 * Worry about long lines? (no, currently)
2365 *
2366 * rfc2045.txt:
2367 *
2368 * "The encoded output stream must be represented in lines of
2369 * no more than 76 characters each. All line breaks or other
2370 * characters not found in Table 1 must be ignored by decoding
2371 * software. In base64 data, characters other than those in
2372 * Table 1, line breaks, and other white space probably
2373 * indicate a transmission error, about which a warning
2374 * message or even a message rejection might be appropriate
2375 * under some circumstances." */
2376 const xmlChar *cur = value;
2377 xmlChar *base;
2378 int total, i = 0, pad = 0;
2379
2380 if (cur == NULL)
2381 goto return1;
2382
2383 for (; *cur; ++cur) {
2384 int decc;
2385
2386 decc = _xmlSchemaBase64Decode(*cur);
2387 if (decc < 0) ;
2388 else if (decc < 64)
2389 i++;
2390 else
2391 break;
2392 }
2393 for (; *cur; ++cur) {
2394 int decc;
2395
2396 decc = _xmlSchemaBase64Decode(*cur);
2397 if (decc < 0) ;
2398 else if (decc < 64)
2399 goto return1;
2400 if (decc == 64)
2401 pad++;
2402 }
2403
2404 /* rfc2045.txt: "Special processing is performed if fewer than
2405 * 24 bits are available at the end of the data being encoded.
2406 * A full encoding quantum is always completed at the end of a
2407 * body. When fewer than 24 input bits are available in an
2408 * input group, zero bits are added (on the right) to form an
2409 * integral number of 6-bit groups. Padding at the end of the
2410 * data is performed using the "=" character. Since all
2411 * base64 input is an integral number of octets, only the
2412 * following cases can arise: (1) the final quantum of
2413 * encoding input is an integral multiple of 24 bits; here,
2414 * the final unit of encoded output will be an integral
2415 * multiple ofindent: Standard input:701: Warning:old style
2416 * assignment ambiguity in "=*". Assuming "= *" 4 characters
2417 * with no "=" padding, (2) the final
2418 * quantum of encoding input is exactly 8 bits; here, the
2419 * final unit of encoded output will be two characters
2420 * followed by two "=" padding characters, or (3) the final
2421 * quantum of encoding input is exactly 16 bits; here, the
2422 * final unit of encoded output will be three characters
2423 * followed by one "=" padding character." */
2424
2425 total = 3 * (i / 4);
2426 if (pad == 0) {
2427 if (i % 4 != 0)
2428 goto return1;
2429 } else if (pad == 1) {
2430 int decc;
2431
2432 if (i % 4 != 3)
2433 goto return1;
2434 for (decc = _xmlSchemaBase64Decode(*cur);
2435 (decc < 0) || (decc > 63);
2436 decc = _xmlSchemaBase64Decode(*cur))
2437 --cur;
2438 /* 16bits in 24bits means 2 pad bits: nnnnnn nnmmmm mmmm00*/
2439 /* 00111100 -> 0x3c */
2440 if (decc & ~0x3c)
2441 goto return1;
2442 total += 2;
2443 } else if (pad == 2) {
2444 int decc;
2445
2446 if (i % 4 != 2)
2447 goto return1;
2448 for (decc = _xmlSchemaBase64Decode(*cur);
2449 (decc < 0) || (decc > 63);
2450 decc = _xmlSchemaBase64Decode(*cur))
2451 --cur;
2452 /* 8bits in 12bits means 4 pad bits: nnnnnn nn0000 */
2453 /* 00110000 -> 0x30 */
2454 if (decc & ~0x30)
2455 goto return1;
2456 total += 1;
2457 } else
2458 goto return1;
2459
2460 if (val != NULL) {
2461 v = xmlSchemaNewValue(XML_SCHEMAS_BASE64BINARY);
2462 if (v == NULL)
2463 goto error;
2464 base =
2465 (xmlChar *) xmlMallocAtomic((i + pad + 1) *
2466 sizeof(xmlChar));
2467 if (base == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002468 xmlSchemaTypeErrMemory(node, "allocating base64 data");
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002469 xmlFree(v);
2470 goto return1;
2471 }
2472 v->value.base64.str = base;
2473 for (cur = value; *cur; ++cur)
2474 if (_xmlSchemaBase64Decode(*cur) >= 0) {
2475 *base = *cur;
2476 ++base;
2477 }
2478 *base = 0;
2479 v->value.base64.total = total;
2480 *val = v;
2481 }
2482 goto return0;
2483 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002484 case XML_SCHEMAS_INTEGER:
2485 case XML_SCHEMAS_PINTEGER:
2486 case XML_SCHEMAS_NPINTEGER:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002487 case XML_SCHEMAS_NINTEGER:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002488 case XML_SCHEMAS_NNINTEGER:{
2489 const xmlChar *cur = value;
2490 unsigned long lo, mi, hi;
2491 int sign = 0;
2492
2493 if (cur == NULL)
2494 goto return1;
2495 if (*cur == '-') {
2496 sign = 1;
2497 cur++;
2498 } else if (*cur == '+')
2499 cur++;
2500 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2501 if (ret == 0)
2502 goto return1;
2503 if (*cur != 0)
2504 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002505 if (type->builtInType == XML_SCHEMAS_NPINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002506 if ((sign == 0) &&
2507 ((hi != 0) || (mi != 0) || (lo != 0)))
2508 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002509 } else if (type->builtInType == XML_SCHEMAS_PINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002510 if (sign == 1)
2511 goto return1;
2512 if ((hi == 0) && (mi == 0) && (lo == 0))
2513 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002514 } else if (type->builtInType == XML_SCHEMAS_NINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002515 if (sign == 0)
2516 goto return1;
2517 if ((hi == 0) && (mi == 0) && (lo == 0))
2518 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002519 } else if (type->builtInType == XML_SCHEMAS_NNINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002520 if ((sign == 1) &&
2521 ((hi != 0) || (mi != 0) || (lo != 0)))
2522 goto return1;
2523 }
2524 /*
2525 * We can store a value only if no overflow occured
2526 */
2527 if ((ret > 0) && (val != NULL)) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00002528 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002529 if (v != NULL) {
2530 v->value.decimal.lo = lo;
2531 v->value.decimal.mi = lo;
2532 v->value.decimal.hi = lo;
2533 v->value.decimal.sign = sign;
2534 v->value.decimal.frac = 0;
2535 v->value.decimal.total = cur - value;
2536 *val = v;
2537 }
2538 }
2539 goto return0;
2540 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002541 case XML_SCHEMAS_LONG:
2542 case XML_SCHEMAS_BYTE:
2543 case XML_SCHEMAS_SHORT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002544 case XML_SCHEMAS_INT:{
2545 const xmlChar *cur = value;
2546 unsigned long lo, mi, hi;
2547 int total = 0;
2548 int sign = 0;
2549
2550 if (cur == NULL)
2551 goto return1;
2552 if (*cur == '-') {
2553 sign = 1;
2554 cur++;
2555 } else if (*cur == '+')
2556 cur++;
2557 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2558 if (ret <= 0)
2559 goto return1;
2560 if (*cur != 0)
2561 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002562 if (type->builtInType == XML_SCHEMAS_LONG) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002563 if (hi >= 922) {
2564 if (hi > 922)
2565 goto return1;
2566 if (mi >= 33720368) {
2567 if (mi > 33720368)
2568 goto return1;
2569 if ((sign == 0) && (lo > 54775807))
2570 goto return1;
2571 if ((sign == 1) && (lo > 54775808))
2572 goto return1;
2573 }
2574 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002575 } else if (type->builtInType == XML_SCHEMAS_INT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002576 if (hi != 0)
2577 goto return1;
2578 if (mi >= 21) {
2579 if (mi > 21)
2580 goto return1;
2581 if ((sign == 0) && (lo > 47483647))
2582 goto return1;
2583 if ((sign == 1) && (lo > 47483648))
2584 goto return1;
2585 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002586 } else if (type->builtInType == XML_SCHEMAS_SHORT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002587 if ((mi != 0) || (hi != 0))
2588 goto return1;
2589 if ((sign == 1) && (lo > 32768))
2590 goto return1;
2591 if ((sign == 0) && (lo > 32767))
2592 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002593 } else if (type->builtInType == XML_SCHEMAS_BYTE) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002594 if ((mi != 0) || (hi != 0))
2595 goto return1;
2596 if ((sign == 1) && (lo > 128))
2597 goto return1;
2598 if ((sign == 0) && (lo > 127))
2599 goto return1;
2600 }
2601 if (val != NULL) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00002602 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002603 if (v != NULL) {
2604 v->value.decimal.lo = lo;
2605 v->value.decimal.mi = lo;
2606 v->value.decimal.hi = lo;
2607 v->value.decimal.sign = sign;
2608 v->value.decimal.frac = 0;
2609 v->value.decimal.total = total;
2610 *val = v;
2611 }
2612 }
2613 goto return0;
2614 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002615 case XML_SCHEMAS_UINT:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002616 case XML_SCHEMAS_ULONG:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002617 case XML_SCHEMAS_USHORT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002618 case XML_SCHEMAS_UBYTE:{
2619 const xmlChar *cur = value;
2620 unsigned long lo, mi, hi;
2621 int total = 0;
2622
2623 if (cur == NULL)
2624 goto return1;
2625 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2626 if (ret <= 0)
2627 goto return1;
2628 if (*cur != 0)
2629 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002630 if (type->builtInType == XML_SCHEMAS_ULONG) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002631 if (hi >= 1844) {
2632 if (hi > 1844)
2633 goto return1;
2634 if (mi >= 67440737) {
2635 if (mi > 67440737)
2636 goto return1;
2637 if (lo > 9551615)
2638 goto return1;
2639 }
2640 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002641 } else if (type->builtInType == XML_SCHEMAS_UINT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002642 if (hi != 0)
2643 goto return1;
2644 if (mi >= 42) {
2645 if (mi > 42)
2646 goto return1;
2647 if (lo > 94967295)
2648 goto return1;
2649 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002650 } else if (type->builtInType == XML_SCHEMAS_USHORT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002651 if ((mi != 0) || (hi != 0))
2652 goto return1;
2653 if (lo > 65535)
2654 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002655 } else if (type->builtInType == XML_SCHEMAS_UBYTE) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002656 if ((mi != 0) || (hi != 0))
2657 goto return1;
2658 if (lo > 255)
2659 goto return1;
2660 }
2661 if (val != NULL) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00002662 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002663 if (v != NULL) {
2664 v->value.decimal.lo = lo;
2665 v->value.decimal.mi = mi;
2666 v->value.decimal.hi = hi;
2667 v->value.decimal.sign = 0;
2668 v->value.decimal.frac = 0;
2669 v->value.decimal.total = total;
2670 *val = v;
2671 }
2672 }
2673 goto return0;
2674 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002675 }
2676
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002677 done:
2678 if (norm != NULL)
2679 xmlFree(norm);
2680 return (ret);
2681 return3:
2682 if (norm != NULL)
2683 xmlFree(norm);
2684 return (3);
2685 return1:
2686 if (norm != NULL)
2687 xmlFree(norm);
2688 return (1);
2689 return0:
2690 if (norm != NULL)
2691 xmlFree(norm);
2692 return (0);
2693 error:
2694 if (norm != NULL)
2695 xmlFree(norm);
2696 return (-1);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002697}
2698
2699/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002700 * xmlSchemaValPredefTypeNode:
Daniel Veillard4255d502002-04-16 15:50:10 +00002701 * @type: the predefined type
2702 * @value: the value to check
2703 * @val: the return computed value
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002704 * @node: the node containing the value
Daniel Veillard4255d502002-04-16 15:50:10 +00002705 *
2706 * Check that a value conforms to the lexical space of the predefined type.
2707 * if true a value is computed and returned in @val.
2708 *
2709 * Returns 0 if this validates, a positive error code number otherwise
2710 * and -1 in case of internal or API error.
2711 */
2712int
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002713xmlSchemaValPredefTypeNode(xmlSchemaTypePtr type, const xmlChar *value,
2714 xmlSchemaValPtr *val, xmlNodePtr node) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002715 return(xmlSchemaValAtomicType(type, value, val, node, 0));
Daniel Veillard4255d502002-04-16 15:50:10 +00002716}
2717
2718/**
Daniel Veillardc0826a72004-08-10 14:17:33 +00002719 * xmlSchemaValPredefTypeNodeNoNorm:
2720 * @type: the predefined type
2721 * @value: the value to check
2722 * @val: the return computed value
2723 * @node: the node containing the value
2724 *
2725 * Check that a value conforms to the lexical space of the predefined type.
2726 * if true a value is computed and returned in @val.
2727 * This one does apply any normalization to the value.
2728 *
2729 * Returns 0 if this validates, a positive error code number otherwise
2730 * and -1 in case of internal or API error.
2731 */
2732int
2733xmlSchemaValPredefTypeNodeNoNorm(xmlSchemaTypePtr type, const xmlChar *value,
2734 xmlSchemaValPtr *val, xmlNodePtr node) {
2735 return(xmlSchemaValAtomicType(type, value, val, node, 1));
2736}
2737
2738/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002739 * xmlSchemaValidatePredefinedType:
2740 * @type: the predefined type
2741 * @value: the value to check
2742 * @val: the return computed value
2743 *
2744 * Check that a value conforms to the lexical space of the predefined type.
2745 * if true a value is computed and returned in @val.
2746 *
2747 * Returns 0 if this validates, a positive error code number otherwise
2748 * and -1 in case of internal or API error.
2749 */
2750int
2751xmlSchemaValidatePredefinedType(xmlSchemaTypePtr type, const xmlChar *value,
2752 xmlSchemaValPtr *val) {
2753 return(xmlSchemaValPredefTypeNode(type, value, val, NULL));
2754}
2755
2756/**
Daniel Veillard4255d502002-04-16 15:50:10 +00002757 * xmlSchemaCompareDecimals:
2758 * @x: a first decimal value
2759 * @y: a second decimal value
2760 *
2761 * Compare 2 decimals
2762 *
2763 * Returns -1 if x < y, 0 if x == y, 1 if x > y and -2 in case of error
2764 */
2765static int
2766xmlSchemaCompareDecimals(xmlSchemaValPtr x, xmlSchemaValPtr y)
2767{
2768 xmlSchemaValPtr swp;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002769 int order = 1, p;
Daniel Veillard4255d502002-04-16 15:50:10 +00002770 unsigned long tmp;
2771
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002772 if ((x->value.decimal.sign) &&
2773 ((x->value.decimal.lo != 0) ||
2774 (x->value.decimal.mi != 0) ||
2775 (x->value.decimal.hi != 0))) {
2776 if ((y->value.decimal.sign) &&
2777 ((y->value.decimal.lo != 0) ||
2778 (y->value.decimal.mi != 0) ||
2779 (y->value.decimal.hi != 0)))
Daniel Veillard80b19092003-03-28 13:29:53 +00002780 order = -1;
2781 else
2782 return (-1);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002783 } else if ((y->value.decimal.sign) &&
2784 ((y->value.decimal.lo != 0) ||
2785 (y->value.decimal.mi != 0) ||
2786 (y->value.decimal.hi != 0))) {
Daniel Veillard4255d502002-04-16 15:50:10 +00002787 return (1);
Daniel Veillard80b19092003-03-28 13:29:53 +00002788 }
Daniel Veillard4255d502002-04-16 15:50:10 +00002789 if (x->value.decimal.frac == y->value.decimal.frac) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002790 if (x->value.decimal.hi < y->value.decimal.hi)
2791 return (-order);
Daniel Veillard01fa6152004-06-29 17:04:39 +00002792 if (x->value.decimal.hi > y->value.decimal.hi)
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002793 return (order);
2794 if (x->value.decimal.mi < y->value.decimal.mi)
2795 return (-order);
Daniel Veillard01fa6152004-06-29 17:04:39 +00002796 if (x->value.decimal.mi > y->value.decimal.mi)
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002797 return (order);
2798 if (x->value.decimal.lo < y->value.decimal.lo)
Daniel Veillard80b19092003-03-28 13:29:53 +00002799 return (-order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002800 if (x->value.decimal.lo > y->value.decimal.lo)
Daniel Veillard80b19092003-03-28 13:29:53 +00002801 return(order);
2802 return(0);
Daniel Veillard4255d502002-04-16 15:50:10 +00002803 }
2804 if (y->value.decimal.frac > x->value.decimal.frac) {
2805 swp = y;
2806 y = x;
2807 x = swp;
2808 order = -order;
2809 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002810 p = powten[x->value.decimal.frac - y->value.decimal.frac];
2811 tmp = x->value.decimal.lo / p;
2812 if (tmp > y->value.decimal.lo)
Daniel Veillard4255d502002-04-16 15:50:10 +00002813 return (order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002814 if (tmp < y->value.decimal.lo)
Daniel Veillard4255d502002-04-16 15:50:10 +00002815 return (-order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002816 tmp = y->value.decimal.lo * p;
2817 if (x->value.decimal.lo < tmp)
Daniel Veillard4255d502002-04-16 15:50:10 +00002818 return (-order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002819 if (x->value.decimal.lo == tmp)
Daniel Veillard4255d502002-04-16 15:50:10 +00002820 return (0);
2821 return (order);
2822}
2823
2824/**
Daniel Veillard070803b2002-05-03 07:29:38 +00002825 * xmlSchemaCompareDurations:
2826 * @x: a first duration value
2827 * @y: a second duration value
2828 *
2829 * Compare 2 durations
2830 *
2831 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
2832 * case of error
2833 */
2834static int
2835xmlSchemaCompareDurations(xmlSchemaValPtr x, xmlSchemaValPtr y)
2836{
2837 long carry, mon, day;
2838 double sec;
Daniel Veillard80b19092003-03-28 13:29:53 +00002839 int invert = 1;
2840 long xmon, xday, myear, minday, maxday;
Daniel Veillard070803b2002-05-03 07:29:38 +00002841 static const long dayRange [2][12] = {
2842 { 0, 28, 59, 89, 120, 150, 181, 212, 242, 273, 303, 334, },
2843 { 0, 31, 62, 92, 123, 153, 184, 215, 245, 276, 306, 337} };
2844
2845 if ((x == NULL) || (y == NULL))
Daniel Veillard5a872412002-05-22 06:40:27 +00002846 return -2;
Daniel Veillard070803b2002-05-03 07:29:38 +00002847
2848 /* months */
2849 mon = x->value.dur.mon - y->value.dur.mon;
2850
2851 /* seconds */
2852 sec = x->value.dur.sec - y->value.dur.sec;
2853 carry = (long)sec / SECS_PER_DAY;
2854 sec -= (double)(carry * SECS_PER_DAY);
2855
2856 /* days */
2857 day = x->value.dur.day - y->value.dur.day + carry;
2858
2859 /* easy test */
2860 if (mon == 0) {
2861 if (day == 0)
2862 if (sec == 0.0)
2863 return 0;
2864 else if (sec < 0.0)
2865 return -1;
2866 else
2867 return 1;
2868 else if (day < 0)
2869 return -1;
2870 else
2871 return 1;
2872 }
2873
2874 if (mon > 0) {
2875 if ((day >= 0) && (sec >= 0.0))
2876 return 1;
2877 else {
2878 xmon = mon;
2879 xday = -day;
2880 }
2881 } else if ((day <= 0) && (sec <= 0.0)) {
2882 return -1;
2883 } else {
Daniel Veillard80b19092003-03-28 13:29:53 +00002884 invert = -1;
Daniel Veillard070803b2002-05-03 07:29:38 +00002885 xmon = -mon;
2886 xday = day;
2887 }
2888
2889 myear = xmon / 12;
Daniel Veillard80b19092003-03-28 13:29:53 +00002890 if (myear == 0) {
2891 minday = 0;
2892 maxday = 0;
2893 } else {
2894 maxday = 366 * ((myear + 3) / 4) +
2895 365 * ((myear - 1) % 4);
2896 minday = maxday - 1;
2897 }
2898
Daniel Veillard070803b2002-05-03 07:29:38 +00002899 xmon = xmon % 12;
2900 minday += dayRange[0][xmon];
2901 maxday += dayRange[1][xmon];
2902
Daniel Veillard80b19092003-03-28 13:29:53 +00002903 if ((maxday == minday) && (maxday == xday))
2904 return(0); /* can this really happen ? */
Daniel Veillard070803b2002-05-03 07:29:38 +00002905 if (maxday < xday)
Daniel Veillard80b19092003-03-28 13:29:53 +00002906 return(-invert);
2907 if (minday > xday)
2908 return(invert);
Daniel Veillard070803b2002-05-03 07:29:38 +00002909
2910 /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00002911 return 2;
2912}
2913
2914/*
2915 * macros for adding date/times and durations
2916 */
2917#define FQUOTIENT(a,b) (floor(((double)a/(double)b)))
2918#define MODULO(a,b) (a - FQUOTIENT(a,b) * b)
2919#define FQUOTIENT_RANGE(a,low,high) (FQUOTIENT((a-low),(high-low)))
2920#define MODULO_RANGE(a,low,high) ((MODULO((a-low),(high-low)))+low)
2921
2922/**
Daniel Veillard669adfc2004-05-29 20:12:46 +00002923 * xmlSchemaDupVal:
2924 * @v: the #xmlSchemaValPtr value to duplicate
2925 *
2926 * Makes a copy of @v. The calling program is responsible for freeing
2927 * the returned value.
2928 *
2929 * returns a pointer to a duplicated #xmlSchemaValPtr or NULL if error.
2930 */
2931static xmlSchemaValPtr
2932xmlSchemaDupVal (xmlSchemaValPtr v)
2933{
2934 xmlSchemaValPtr ret = xmlSchemaNewValue(v->type);
2935 if (ret == NULL)
2936 return NULL;
2937
2938 memcpy(ret, v, sizeof(xmlSchemaVal));
2939 return ret;
2940}
2941
2942/**
Daniel Veillard5a872412002-05-22 06:40:27 +00002943 * _xmlSchemaDateAdd:
2944 * @dt: an #xmlSchemaValPtr
2945 * @dur: an #xmlSchemaValPtr of type #XS_DURATION
2946 *
2947 * Compute a new date/time from @dt and @dur. This function assumes @dt
2948 * is either #XML_SCHEMAS_DATETIME, #XML_SCHEMAS_DATE, #XML_SCHEMAS_GYEARMONTH,
Daniel Veillard669adfc2004-05-29 20:12:46 +00002949 * or #XML_SCHEMAS_GYEAR. The returned #xmlSchemaVal is the same type as
2950 * @dt. The calling program is responsible for freeing the returned value.
Daniel Veillard5a872412002-05-22 06:40:27 +00002951 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00002952 * Returns a pointer to a new #xmlSchemaVal or NULL if error.
Daniel Veillard5a872412002-05-22 06:40:27 +00002953 */
2954static xmlSchemaValPtr
2955_xmlSchemaDateAdd (xmlSchemaValPtr dt, xmlSchemaValPtr dur)
2956{
Daniel Veillard669adfc2004-05-29 20:12:46 +00002957 xmlSchemaValPtr ret, tmp;
Daniel Veillard5a872412002-05-22 06:40:27 +00002958 long carry, tempdays, temp;
2959 xmlSchemaValDatePtr r, d;
2960 xmlSchemaValDurationPtr u;
2961
2962 if ((dt == NULL) || (dur == NULL))
2963 return NULL;
2964
2965 ret = xmlSchemaNewValue(dt->type);
2966 if (ret == NULL)
2967 return NULL;
2968
Daniel Veillard669adfc2004-05-29 20:12:46 +00002969 /* make a copy so we don't alter the original value */
2970 tmp = xmlSchemaDupVal(dt);
2971 if (tmp == NULL) {
2972 xmlSchemaFreeValue(ret);
2973 return NULL;
2974 }
2975
Daniel Veillard5a872412002-05-22 06:40:27 +00002976 r = &(ret->value.date);
Daniel Veillard669adfc2004-05-29 20:12:46 +00002977 d = &(tmp->value.date);
Daniel Veillard5a872412002-05-22 06:40:27 +00002978 u = &(dur->value.dur);
2979
2980 /* normalization */
2981 if (d->mon == 0)
2982 d->mon = 1;
2983
2984 /* normalize for time zone offset */
2985 u->sec -= (d->tzo * 60);
2986 d->tzo = 0;
2987
2988 /* normalization */
2989 if (d->day == 0)
2990 d->day = 1;
2991
2992 /* month */
2993 carry = d->mon + u->mon;
Daniel Veillardebe25d42004-03-25 09:35:49 +00002994 r->mon = (unsigned int) MODULO_RANGE(carry, 1, 13);
2995 carry = (long) FQUOTIENT_RANGE(carry, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00002996
2997 /* year (may be modified later) */
2998 r->year = d->year + carry;
2999 if (r->year == 0) {
3000 if (d->year > 0)
3001 r->year--;
3002 else
3003 r->year++;
3004 }
3005
3006 /* time zone */
3007 r->tzo = d->tzo;
3008 r->tz_flag = d->tz_flag;
3009
3010 /* seconds */
3011 r->sec = d->sec + u->sec;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003012 carry = (long) FQUOTIENT((long)r->sec, 60);
Daniel Veillard5a872412002-05-22 06:40:27 +00003013 if (r->sec != 0.0) {
3014 r->sec = MODULO(r->sec, 60.0);
3015 }
3016
3017 /* minute */
3018 carry += d->min;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003019 r->min = (unsigned int) MODULO(carry, 60);
3020 carry = (long) FQUOTIENT(carry, 60);
Daniel Veillard5a872412002-05-22 06:40:27 +00003021
3022 /* hours */
3023 carry += d->hour;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003024 r->hour = (unsigned int) MODULO(carry, 24);
3025 carry = (long)FQUOTIENT(carry, 24);
Daniel Veillard5a872412002-05-22 06:40:27 +00003026
3027 /*
3028 * days
3029 * Note we use tempdays because the temporary values may need more
3030 * than 5 bits
3031 */
3032 if ((VALID_YEAR(r->year)) && (VALID_MONTH(r->mon)) &&
3033 (d->day > MAX_DAYINMONTH(r->year, r->mon)))
3034 tempdays = MAX_DAYINMONTH(r->year, r->mon);
3035 else if (d->day < 1)
3036 tempdays = 1;
3037 else
3038 tempdays = d->day;
3039
3040 tempdays += u->day + carry;
3041
3042 while (1) {
3043 if (tempdays < 1) {
Daniel Veillardebe25d42004-03-25 09:35:49 +00003044 long tmon = (long) MODULO_RANGE(r->mon-1, 1, 13);
3045 long tyr = r->year + (long)FQUOTIENT_RANGE(r->mon-1, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00003046 if (tyr == 0)
3047 tyr--;
3048 tempdays += MAX_DAYINMONTH(tyr, tmon);
3049 carry = -1;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003050 } else if (tempdays > (long) MAX_DAYINMONTH(r->year, r->mon)) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003051 tempdays = tempdays - MAX_DAYINMONTH(r->year, r->mon);
3052 carry = 1;
3053 } else
3054 break;
3055
3056 temp = r->mon + carry;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003057 r->mon = (unsigned int) MODULO_RANGE(temp, 1, 13);
3058 r->year = r->year + (unsigned int) FQUOTIENT_RANGE(temp, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00003059 if (r->year == 0) {
3060 if (temp < 1)
3061 r->year--;
3062 else
3063 r->year++;
3064 }
3065 }
3066
3067 r->day = tempdays;
3068
3069 /*
3070 * adjust the date/time type to the date values
3071 */
3072 if (ret->type != XML_SCHEMAS_DATETIME) {
3073 if ((r->hour) || (r->min) || (r->sec))
3074 ret->type = XML_SCHEMAS_DATETIME;
3075 else if (ret->type != XML_SCHEMAS_DATE) {
3076 if ((r->mon != 1) && (r->day != 1))
3077 ret->type = XML_SCHEMAS_DATE;
3078 else if ((ret->type != XML_SCHEMAS_GYEARMONTH) && (r->mon != 1))
3079 ret->type = XML_SCHEMAS_GYEARMONTH;
3080 }
3081 }
3082
Daniel Veillard669adfc2004-05-29 20:12:46 +00003083 xmlSchemaFreeValue(tmp);
Daniel Veillard5a872412002-05-22 06:40:27 +00003084
Daniel Veillard5a872412002-05-22 06:40:27 +00003085 return ret;
3086}
3087
3088/**
3089 * xmlSchemaDateNormalize:
Daniel Veillard669adfc2004-05-29 20:12:46 +00003090 * @dt: an #xmlSchemaValPtr of a date/time type value.
3091 * @offset: number of seconds to adjust @dt by.
Daniel Veillard5a872412002-05-22 06:40:27 +00003092 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00003093 * Normalize @dt to GMT time. The @offset parameter is subtracted from
3094 * the return value is a time-zone offset is present on @dt.
Daniel Veillard5a872412002-05-22 06:40:27 +00003095 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00003096 * Returns a normalized copy of @dt or NULL if error.
Daniel Veillard5a872412002-05-22 06:40:27 +00003097 */
3098static xmlSchemaValPtr
3099xmlSchemaDateNormalize (xmlSchemaValPtr dt, double offset)
3100{
3101 xmlSchemaValPtr dur, ret;
3102
3103 if (dt == NULL)
3104 return NULL;
3105
3106 if (((dt->type != XML_SCHEMAS_TIME) &&
3107 (dt->type != XML_SCHEMAS_DATETIME)) || (dt->value.date.tzo == 0))
3108 return xmlSchemaDupVal(dt);
3109
3110 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
3111 if (dur == NULL)
3112 return NULL;
3113
3114 dur->value.date.sec -= offset;
3115
3116 ret = _xmlSchemaDateAdd(dt, dur);
3117 if (ret == NULL)
3118 return NULL;
3119
3120 xmlSchemaFreeValue(dur);
3121
3122 /* ret->value.date.tzo = 0; */
3123 return ret;
3124}
3125
3126/**
3127 * _xmlSchemaDateCastYMToDays:
3128 * @dt: an #xmlSchemaValPtr
3129 *
3130 * Convert mon and year of @dt to total number of days. Take the
3131 * number of years since (or before) 1 AD and add the number of leap
3132 * years. This is a function because negative
3133 * years must be handled a little differently and there is no zero year.
3134 *
3135 * Returns number of days.
3136 */
3137static long
3138_xmlSchemaDateCastYMToDays (const xmlSchemaValPtr dt)
3139{
3140 long ret;
Daniel Veillard49e89632004-09-23 16:24:36 +00003141 int mon;
Daniel Veillard5a872412002-05-22 06:40:27 +00003142
Daniel Veillard49e89632004-09-23 16:24:36 +00003143 mon = dt->value.date.mon;
3144 if (mon <= 0) mon = 1; /* normalization */
3145
3146 if (dt->value.date.year <= 0)
Daniel Veillard5a872412002-05-22 06:40:27 +00003147 ret = (dt->value.date.year * 365) +
3148 (((dt->value.date.year+1)/4)-((dt->value.date.year+1)/100)+
3149 ((dt->value.date.year+1)/400)) +
Daniel Veillard49e89632004-09-23 16:24:36 +00003150 DAY_IN_YEAR(0, mon, dt->value.date.year);
Daniel Veillard5a872412002-05-22 06:40:27 +00003151 else
3152 ret = ((dt->value.date.year-1) * 365) +
3153 (((dt->value.date.year-1)/4)-((dt->value.date.year-1)/100)+
3154 ((dt->value.date.year-1)/400)) +
Daniel Veillard49e89632004-09-23 16:24:36 +00003155 DAY_IN_YEAR(0, mon, dt->value.date.year);
Daniel Veillard5a872412002-05-22 06:40:27 +00003156
3157 return ret;
3158}
3159
3160/**
3161 * TIME_TO_NUMBER:
3162 * @dt: an #xmlSchemaValPtr
3163 *
3164 * Calculates the number of seconds in the time portion of @dt.
3165 *
3166 * Returns seconds.
3167 */
3168#define TIME_TO_NUMBER(dt) \
3169 ((double)((dt->value.date.hour * SECS_PER_HOUR) + \
Daniel Veillardb3721c22003-03-31 11:22:25 +00003170 (dt->value.date.min * SECS_PER_MIN) + \
3171 (dt->value.date.tzo * SECS_PER_MIN)) + \
3172 dt->value.date.sec)
Daniel Veillard5a872412002-05-22 06:40:27 +00003173
3174/**
3175 * xmlSchemaCompareDates:
3176 * @x: a first date/time value
3177 * @y: a second date/time value
3178 *
3179 * Compare 2 date/times
3180 *
3181 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3182 * case of error
3183 */
3184static int
3185xmlSchemaCompareDates (xmlSchemaValPtr x, xmlSchemaValPtr y)
3186{
3187 unsigned char xmask, ymask, xor_mask, and_mask;
3188 xmlSchemaValPtr p1, p2, q1, q2;
3189 long p1d, p2d, q1d, q2d;
3190
3191 if ((x == NULL) || (y == NULL))
3192 return -2;
3193
3194 if (x->value.date.tz_flag) {
3195
3196 if (!y->value.date.tz_flag) {
3197 p1 = xmlSchemaDateNormalize(x, 0);
3198 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3199 /* normalize y + 14:00 */
3200 q1 = xmlSchemaDateNormalize(y, (14 * SECS_PER_HOUR));
3201
3202 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003203 if (p1d < q1d) {
3204 xmlSchemaFreeValue(p1);
3205 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003206 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003207 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003208 double sec;
3209
3210 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00003211 if (sec < 0.0) {
3212 xmlSchemaFreeValue(p1);
3213 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003214 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003215 } else {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003216 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003217 /* normalize y - 14:00 */
3218 q2 = xmlSchemaDateNormalize(y, -(14 * SECS_PER_HOUR));
3219 q2d = _xmlSchemaDateCastYMToDays(q2) + q2->value.date.day;
3220 if (p1d > q2d)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003221 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003222 else if (p1d == q2d) {
3223 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q2);
3224 if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003225 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003226 else
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003227 ret = 2; /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00003228 }
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003229 xmlSchemaFreeValue(p1);
3230 xmlSchemaFreeValue(q1);
3231 xmlSchemaFreeValue(q2);
3232 if (ret != 0)
3233 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003234 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00003235 } else {
3236 xmlSchemaFreeValue(p1);
3237 xmlSchemaFreeValue(q1);
3238 }
Daniel Veillard5a872412002-05-22 06:40:27 +00003239 }
3240 } else if (y->value.date.tz_flag) {
3241 q1 = xmlSchemaDateNormalize(y, 0);
3242 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
3243
3244 /* normalize x - 14:00 */
3245 p1 = xmlSchemaDateNormalize(x, -(14 * SECS_PER_HOUR));
3246 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3247
Daniel Veillardfdc91562002-07-01 21:52:03 +00003248 if (p1d < q1d) {
3249 xmlSchemaFreeValue(p1);
3250 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003251 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003252 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003253 double sec;
3254
3255 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00003256 if (sec < 0.0) {
3257 xmlSchemaFreeValue(p1);
3258 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003259 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003260 } else {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003261 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003262 /* normalize x + 14:00 */
3263 p2 = xmlSchemaDateNormalize(x, (14 * SECS_PER_HOUR));
3264 p2d = _xmlSchemaDateCastYMToDays(p2) + p2->value.date.day;
3265
Daniel Veillard6560a422003-03-27 21:25:38 +00003266 if (p2d > q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003267 ret = 1;
Daniel Veillard6560a422003-03-27 21:25:38 +00003268 } else if (p2d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003269 sec = TIME_TO_NUMBER(p2) - TIME_TO_NUMBER(q1);
3270 if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003271 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003272 else
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003273 ret = 2; /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00003274 }
Daniel Veillard6560a422003-03-27 21:25:38 +00003275 xmlSchemaFreeValue(p1);
3276 xmlSchemaFreeValue(q1);
3277 xmlSchemaFreeValue(p2);
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003278 if (ret != 0)
3279 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003280 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00003281 } else {
3282 xmlSchemaFreeValue(p1);
3283 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003284 }
3285 }
3286
3287 /*
3288 * if the same type then calculate the difference
3289 */
3290 if (x->type == y->type) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003291 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003292 q1 = xmlSchemaDateNormalize(y, 0);
3293 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
3294
3295 p1 = xmlSchemaDateNormalize(x, 0);
3296 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3297
Daniel Veillardfdc91562002-07-01 21:52:03 +00003298 if (p1d < q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003299 ret = -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003300 } else if (p1d > q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003301 ret = 1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003302 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00003303 double sec;
3304
3305 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
3306 if (sec < 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003307 ret = -1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003308 else if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003309 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003310
3311 }
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003312 xmlSchemaFreeValue(p1);
3313 xmlSchemaFreeValue(q1);
3314 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003315 }
3316
3317 switch (x->type) {
3318 case XML_SCHEMAS_DATETIME:
3319 xmask = 0xf;
3320 break;
3321 case XML_SCHEMAS_DATE:
3322 xmask = 0x7;
3323 break;
3324 case XML_SCHEMAS_GYEAR:
3325 xmask = 0x1;
3326 break;
3327 case XML_SCHEMAS_GMONTH:
3328 xmask = 0x2;
3329 break;
3330 case XML_SCHEMAS_GDAY:
3331 xmask = 0x3;
3332 break;
3333 case XML_SCHEMAS_GYEARMONTH:
3334 xmask = 0x3;
3335 break;
3336 case XML_SCHEMAS_GMONTHDAY:
3337 xmask = 0x6;
3338 break;
3339 case XML_SCHEMAS_TIME:
3340 xmask = 0x8;
3341 break;
3342 default:
3343 xmask = 0;
3344 break;
3345 }
3346
3347 switch (y->type) {
3348 case XML_SCHEMAS_DATETIME:
3349 ymask = 0xf;
3350 break;
3351 case XML_SCHEMAS_DATE:
3352 ymask = 0x7;
3353 break;
3354 case XML_SCHEMAS_GYEAR:
3355 ymask = 0x1;
3356 break;
3357 case XML_SCHEMAS_GMONTH:
3358 ymask = 0x2;
3359 break;
3360 case XML_SCHEMAS_GDAY:
3361 ymask = 0x3;
3362 break;
3363 case XML_SCHEMAS_GYEARMONTH:
3364 ymask = 0x3;
3365 break;
3366 case XML_SCHEMAS_GMONTHDAY:
3367 ymask = 0x6;
3368 break;
3369 case XML_SCHEMAS_TIME:
3370 ymask = 0x8;
3371 break;
3372 default:
3373 ymask = 0;
3374 break;
3375 }
3376
3377 xor_mask = xmask ^ ymask; /* mark type differences */
3378 and_mask = xmask & ymask; /* mark field specification */
3379
3380 /* year */
3381 if (xor_mask & 1)
3382 return 2; /* indeterminate */
3383 else if (and_mask & 1) {
3384 if (x->value.date.year < y->value.date.year)
3385 return -1;
3386 else if (x->value.date.year > y->value.date.year)
3387 return 1;
3388 }
3389
3390 /* month */
3391 if (xor_mask & 2)
3392 return 2; /* indeterminate */
3393 else if (and_mask & 2) {
3394 if (x->value.date.mon < y->value.date.mon)
3395 return -1;
3396 else if (x->value.date.mon > y->value.date.mon)
3397 return 1;
3398 }
3399
3400 /* day */
3401 if (xor_mask & 4)
3402 return 2; /* indeterminate */
3403 else if (and_mask & 4) {
3404 if (x->value.date.day < y->value.date.day)
3405 return -1;
3406 else if (x->value.date.day > y->value.date.day)
3407 return 1;
3408 }
3409
3410 /* time */
3411 if (xor_mask & 8)
3412 return 2; /* indeterminate */
3413 else if (and_mask & 8) {
3414 if (x->value.date.hour < y->value.date.hour)
3415 return -1;
3416 else if (x->value.date.hour > y->value.date.hour)
3417 return 1;
3418 else if (x->value.date.min < y->value.date.min)
3419 return -1;
3420 else if (x->value.date.min > y->value.date.min)
3421 return 1;
3422 else if (x->value.date.sec < y->value.date.sec)
3423 return -1;
3424 else if (x->value.date.sec > y->value.date.sec)
3425 return 1;
3426 }
3427
Daniel Veillard070803b2002-05-03 07:29:38 +00003428 return 0;
3429}
3430
3431/**
Daniel Veillardc4c21552003-03-29 10:53:38 +00003432 * xmlSchemaCompareNormStrings:
3433 * @x: a first string value
3434 * @y: a second string value
3435 *
3436 * Compare 2 string for their normalized values.
3437 *
3438 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
3439 * case of error
3440 */
3441static int
3442xmlSchemaCompareNormStrings(xmlSchemaValPtr x, xmlSchemaValPtr y) {
3443 const xmlChar *utf1;
3444 const xmlChar *utf2;
3445 int tmp;
3446
3447 if ((x == NULL) || (y == NULL))
3448 return(-2);
3449 utf1 = x->value.str;
3450 utf2 = y->value.str;
3451
William M. Brack76e95df2003-10-18 16:20:14 +00003452 while (IS_BLANK_CH(*utf1)) utf1++;
3453 while (IS_BLANK_CH(*utf2)) utf2++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003454 while ((*utf1 != 0) && (*utf2 != 0)) {
William M. Brack76e95df2003-10-18 16:20:14 +00003455 if (IS_BLANK_CH(*utf1)) {
3456 if (!IS_BLANK_CH(*utf2)) {
Daniel Veillardc4c21552003-03-29 10:53:38 +00003457 tmp = *utf1 - *utf2;
3458 return(tmp);
3459 }
William M. Brack76e95df2003-10-18 16:20:14 +00003460 while (IS_BLANK_CH(*utf1)) utf1++;
3461 while (IS_BLANK_CH(*utf2)) utf2++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003462 } else {
3463 tmp = *utf1++ - *utf2++;
3464 if (tmp < 0)
3465 return(-1);
3466 if (tmp > 0)
3467 return(1);
3468 }
3469 }
3470 if (*utf1 != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00003471 while (IS_BLANK_CH(*utf1)) utf1++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003472 if (*utf1 != 0)
3473 return(1);
3474 }
3475 if (*utf2 != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00003476 while (IS_BLANK_CH(*utf2)) utf2++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003477 if (*utf2 != 0)
3478 return(-1);
3479 }
3480 return(0);
3481}
3482
3483/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003484 * xmlSchemaCompareFloats:
3485 * @x: a first float or double value
3486 * @y: a second float or double value
3487 *
3488 * Compare 2 values
3489 *
3490 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3491 * case of error
3492 */
3493static int
3494xmlSchemaCompareFloats(xmlSchemaValPtr x, xmlSchemaValPtr y) {
3495 double d1, d2;
3496
3497 if ((x == NULL) || (y == NULL))
3498 return(-2);
3499
3500 /*
3501 * Cast everything to doubles.
3502 */
3503 if (x->type == XML_SCHEMAS_DOUBLE)
3504 d1 = x->value.d;
3505 else if (x->type == XML_SCHEMAS_FLOAT)
3506 d1 = x->value.f;
3507 else
3508 return(-2);
3509
3510 if (y->type == XML_SCHEMAS_DOUBLE)
3511 d2 = y->value.d;
3512 else if (y->type == XML_SCHEMAS_FLOAT)
3513 d2 = y->value.f;
3514 else
3515 return(-2);
3516
3517 /*
3518 * Check for special cases.
3519 */
3520 if (xmlXPathIsNaN(d1)) {
3521 if (xmlXPathIsNaN(d2))
3522 return(0);
3523 return(1);
3524 }
3525 if (xmlXPathIsNaN(d2))
3526 return(-1);
3527 if (d1 == xmlXPathPINF) {
3528 if (d2 == xmlXPathPINF)
3529 return(0);
3530 return(1);
3531 }
3532 if (d2 == xmlXPathPINF)
3533 return(-1);
3534 if (d1 == xmlXPathNINF) {
3535 if (d2 == xmlXPathNINF)
3536 return(0);
3537 return(-1);
3538 }
3539 if (d2 == xmlXPathNINF)
3540 return(1);
3541
3542 /*
3543 * basic tests, the last one we should have equality, but
3544 * portability is more important than speed and handling
3545 * NaN or Inf in a portable way is always a challenge, so ...
3546 */
3547 if (d1 < d2)
3548 return(-1);
3549 if (d1 > d2)
3550 return(1);
3551 if (d1 == d2)
3552 return(0);
3553 return(2);
3554}
3555
3556/**
Daniel Veillard4255d502002-04-16 15:50:10 +00003557 * xmlSchemaCompareValues:
3558 * @x: a first value
3559 * @y: a second value
3560 *
3561 * Compare 2 values
3562 *
Daniel Veillard5a872412002-05-22 06:40:27 +00003563 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3564 * case of error
Daniel Veillard4255d502002-04-16 15:50:10 +00003565 */
Daniel Veillard80b19092003-03-28 13:29:53 +00003566int
Daniel Veillard4255d502002-04-16 15:50:10 +00003567xmlSchemaCompareValues(xmlSchemaValPtr x, xmlSchemaValPtr y) {
3568 if ((x == NULL) || (y == NULL))
3569 return(-2);
3570
3571 switch (x->type) {
Daniel Veillard80b19092003-03-28 13:29:53 +00003572 case XML_SCHEMAS_UNKNOWN:
William M. Brack2f2a6632004-08-20 23:09:47 +00003573 case XML_SCHEMAS_ANYTYPE:
3574 case XML_SCHEMAS_ANYSIMPLETYPE:
Daniel Veillard80b19092003-03-28 13:29:53 +00003575 return(-2);
3576 case XML_SCHEMAS_INTEGER:
3577 case XML_SCHEMAS_NPINTEGER:
3578 case XML_SCHEMAS_NINTEGER:
3579 case XML_SCHEMAS_NNINTEGER:
3580 case XML_SCHEMAS_PINTEGER:
3581 case XML_SCHEMAS_INT:
3582 case XML_SCHEMAS_UINT:
3583 case XML_SCHEMAS_LONG:
3584 case XML_SCHEMAS_ULONG:
3585 case XML_SCHEMAS_SHORT:
3586 case XML_SCHEMAS_USHORT:
3587 case XML_SCHEMAS_BYTE:
3588 case XML_SCHEMAS_UBYTE:
Daniel Veillard4255d502002-04-16 15:50:10 +00003589 case XML_SCHEMAS_DECIMAL:
Daniel Veillard80b19092003-03-28 13:29:53 +00003590 if (y->type == x->type)
3591 return(xmlSchemaCompareDecimals(x, y));
3592 if ((y->type == XML_SCHEMAS_DECIMAL) ||
3593 (y->type == XML_SCHEMAS_INTEGER) ||
3594 (y->type == XML_SCHEMAS_NPINTEGER) ||
3595 (y->type == XML_SCHEMAS_NINTEGER) ||
3596 (y->type == XML_SCHEMAS_NNINTEGER) ||
3597 (y->type == XML_SCHEMAS_PINTEGER) ||
3598 (y->type == XML_SCHEMAS_INT) ||
3599 (y->type == XML_SCHEMAS_UINT) ||
3600 (y->type == XML_SCHEMAS_LONG) ||
3601 (y->type == XML_SCHEMAS_ULONG) ||
3602 (y->type == XML_SCHEMAS_SHORT) ||
3603 (y->type == XML_SCHEMAS_USHORT) ||
3604 (y->type == XML_SCHEMAS_BYTE) ||
3605 (y->type == XML_SCHEMAS_UBYTE))
Daniel Veillard4255d502002-04-16 15:50:10 +00003606 return(xmlSchemaCompareDecimals(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00003607 return(-2);
Daniel Veillard070803b2002-05-03 07:29:38 +00003608 case XML_SCHEMAS_DURATION:
3609 if (y->type == XML_SCHEMAS_DURATION)
3610 return(xmlSchemaCompareDurations(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00003611 return(-2);
3612 case XML_SCHEMAS_TIME:
3613 case XML_SCHEMAS_GDAY:
3614 case XML_SCHEMAS_GMONTH:
3615 case XML_SCHEMAS_GMONTHDAY:
3616 case XML_SCHEMAS_GYEAR:
3617 case XML_SCHEMAS_GYEARMONTH:
3618 case XML_SCHEMAS_DATE:
3619 case XML_SCHEMAS_DATETIME:
3620 if ((y->type == XML_SCHEMAS_DATETIME) ||
3621 (y->type == XML_SCHEMAS_TIME) ||
3622 (y->type == XML_SCHEMAS_GDAY) ||
3623 (y->type == XML_SCHEMAS_GMONTH) ||
3624 (y->type == XML_SCHEMAS_GMONTHDAY) ||
3625 (y->type == XML_SCHEMAS_GYEAR) ||
3626 (y->type == XML_SCHEMAS_DATE) ||
3627 (y->type == XML_SCHEMAS_GYEARMONTH))
3628 return (xmlSchemaCompareDates(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00003629 return (-2);
Daniel Veillard80b19092003-03-28 13:29:53 +00003630 case XML_SCHEMAS_NORMSTRING:
Daniel Veillard80b19092003-03-28 13:29:53 +00003631 case XML_SCHEMAS_TOKEN:
3632 case XML_SCHEMAS_LANGUAGE:
3633 case XML_SCHEMAS_NMTOKEN:
Daniel Veillard80b19092003-03-28 13:29:53 +00003634 case XML_SCHEMAS_NAME:
Daniel Veillard80b19092003-03-28 13:29:53 +00003635 case XML_SCHEMAS_NCNAME:
3636 case XML_SCHEMAS_ID:
3637 case XML_SCHEMAS_IDREF:
Daniel Veillard80b19092003-03-28 13:29:53 +00003638 case XML_SCHEMAS_ENTITY:
Daniel Veillard80b19092003-03-28 13:29:53 +00003639 case XML_SCHEMAS_NOTATION:
3640 case XML_SCHEMAS_ANYURI:
Daniel Veillardc4c21552003-03-29 10:53:38 +00003641 if ((y->type == XML_SCHEMAS_NORMSTRING) ||
3642 (y->type == XML_SCHEMAS_TOKEN) ||
3643 (y->type == XML_SCHEMAS_LANGUAGE) ||
3644 (y->type == XML_SCHEMAS_NMTOKEN) ||
3645 (y->type == XML_SCHEMAS_NAME) ||
3646 (y->type == XML_SCHEMAS_QNAME) ||
3647 (y->type == XML_SCHEMAS_NCNAME) ||
3648 (y->type == XML_SCHEMAS_ID) ||
3649 (y->type == XML_SCHEMAS_IDREF) ||
3650 (y->type == XML_SCHEMAS_ENTITY) ||
3651 (y->type == XML_SCHEMAS_NOTATION) ||
3652 (y->type == XML_SCHEMAS_ANYURI))
3653 return (xmlSchemaCompareNormStrings(x, y));
3654 return (-2);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003655 case XML_SCHEMAS_QNAME:
3656 if (y->type == XML_SCHEMAS_QNAME) {
3657 if ((xmlStrEqual(x->value.qname.name, y->value.qname.name)) &&
3658 (xmlStrEqual(x->value.qname.uri, y->value.qname.uri)))
3659 return(0);
3660 return(2);
3661 }
3662 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00003663 case XML_SCHEMAS_FLOAT:
3664 case XML_SCHEMAS_DOUBLE:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003665 if ((y->type == XML_SCHEMAS_FLOAT) ||
3666 (y->type == XML_SCHEMAS_DOUBLE))
3667 return (xmlSchemaCompareFloats(x, y));
3668 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00003669 case XML_SCHEMAS_BOOLEAN:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003670 if (y->type == XML_SCHEMAS_BOOLEAN) {
3671 if (x->value.b == y->value.b)
3672 return(0);
3673 if (x->value.b == 0)
3674 return(-1);
3675 return(1);
3676 }
3677 return (-2);
Daniel Veillard560c2a42003-07-06 21:13:49 +00003678 case XML_SCHEMAS_HEXBINARY:
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00003679 if (y->type == XML_SCHEMAS_HEXBINARY) {
3680 if (x->value.hex.total == y->value.hex.total) {
3681 int ret = xmlStrcmp(x->value.hex.str, y->value.hex.str);
3682 if (ret > 0)
3683 return(1);
3684 else if (ret == 0)
3685 return(0);
3686 }
3687 else if (x->value.hex.total > y->value.hex.total)
3688 return(1);
3689
3690 return(-1);
3691 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00003692 return (-2);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003693 case XML_SCHEMAS_BASE64BINARY:
3694 if (y->type == XML_SCHEMAS_BASE64BINARY) {
3695 if (x->value.base64.total == y->value.base64.total) {
3696 int ret = xmlStrcmp(x->value.base64.str,
3697 y->value.base64.str);
3698 if (ret > 0)
3699 return(1);
3700 else if (ret == 0)
3701 return(0);
3702 }
3703 else if (x->value.base64.total > y->value.base64.total)
3704 return(1);
3705 else
3706 return(-1);
3707 }
3708 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00003709 case XML_SCHEMAS_STRING:
3710 case XML_SCHEMAS_IDREFS:
3711 case XML_SCHEMAS_ENTITIES:
3712 case XML_SCHEMAS_NMTOKENS:
3713 TODO
3714 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00003715 }
Daniel Veillard5a872412002-05-22 06:40:27 +00003716 return -2;
Daniel Veillard4255d502002-04-16 15:50:10 +00003717}
3718
3719/**
Daniel Veillardc4c21552003-03-29 10:53:38 +00003720 * xmlSchemaNormLen:
3721 * @value: a string
3722 *
3723 * Computes the UTF8 length of the normalized value of the string
3724 *
3725 * Returns the length or -1 in case of error.
3726 */
3727static int
3728xmlSchemaNormLen(const xmlChar *value) {
3729 const xmlChar *utf;
3730 int ret = 0;
3731
3732 if (value == NULL)
3733 return(-1);
3734 utf = value;
William M. Brack76e95df2003-10-18 16:20:14 +00003735 while (IS_BLANK_CH(*utf)) utf++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003736 while (*utf != 0) {
3737 if (utf[0] & 0x80) {
3738 if ((utf[1] & 0xc0) != 0x80)
3739 return(-1);
3740 if ((utf[0] & 0xe0) == 0xe0) {
3741 if ((utf[2] & 0xc0) != 0x80)
3742 return(-1);
3743 if ((utf[0] & 0xf0) == 0xf0) {
3744 if ((utf[0] & 0xf8) != 0xf0 || (utf[3] & 0xc0) != 0x80)
3745 return(-1);
3746 utf += 4;
3747 } else {
3748 utf += 3;
3749 }
3750 } else {
3751 utf += 2;
3752 }
William M. Brack76e95df2003-10-18 16:20:14 +00003753 } else if (IS_BLANK_CH(*utf)) {
3754 while (IS_BLANK_CH(*utf)) utf++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003755 if (*utf == 0)
3756 break;
3757 } else {
3758 utf++;
3759 }
3760 ret++;
3761 }
3762 return(ret);
3763}
3764
Daniel Veillard6927b102004-10-27 17:29:04 +00003765/**
3766 * xmlSchemaGetFacetValueAsULong:
3767 * @facet: an schemas type facet
3768 *
3769 * Extract the value of a facet
3770 *
3771 * Returns the value as a long
3772 */
Daniel Veillardc0826a72004-08-10 14:17:33 +00003773unsigned long
3774xmlSchemaGetFacetValueAsULong(xmlSchemaFacetPtr facet)
3775{
3776 /*
3777 * TODO: Check if this is a decimal.
3778 */
3779 return ((unsigned long) facet->val->value.decimal.lo);
3780}
3781
Daniel Veillardc4c21552003-03-29 10:53:38 +00003782/**
Daniel Veillard01fa6152004-06-29 17:04:39 +00003783 * xmlSchemaValidateListSimpleTypeFacet:
3784 * @facet: the facet to check
3785 * @value: the lexical repr of the value to validate
3786 * @actualLen: the number of list items
3787 * @expectedLen: the resulting expected number of list items
3788 *
3789 * Checks the value of a list simple type against a facet.
3790 *
3791 * Returns 0 if the value is valid, a positive error code
3792 * number otherwise and -1 in case of an internal error.
3793 */
3794int
3795xmlSchemaValidateListSimpleTypeFacet(xmlSchemaFacetPtr facet,
3796 const xmlChar *value,
3797 unsigned long actualLen,
3798 unsigned long *expectedLen)
3799{
Daniel Veillardce682bc2004-11-05 17:22:25 +00003800 if (facet == NULL)
3801 return(-1);
Daniel Veillard01fa6152004-06-29 17:04:39 +00003802 /*
3803 * TODO: Check if this will work with large numbers.
3804 * (compare value.decimal.mi and value.decimal.hi as well?).
3805 */
3806 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
3807 if (actualLen != facet->val->value.decimal.lo) {
Daniel Veillardc0826a72004-08-10 14:17:33 +00003808 if (expectedLen != 0)
3809 *expectedLen = facet->val->value.decimal.lo;
Daniel Veillard01fa6152004-06-29 17:04:39 +00003810 return (XML_SCHEMAV_CVC_LENGTH_VALID);
3811 }
3812 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
3813 if (actualLen < facet->val->value.decimal.lo) {
Daniel Veillardc0826a72004-08-10 14:17:33 +00003814 if (expectedLen != 0)
3815 *expectedLen = facet->val->value.decimal.lo;
Daniel Veillard01fa6152004-06-29 17:04:39 +00003816 return (XML_SCHEMAV_CVC_MINLENGTH_VALID);
3817 }
3818 } else if (facet->type == XML_SCHEMA_FACET_MAXLENGTH) {
3819 if (actualLen > facet->val->value.decimal.lo) {
Daniel Veillardc0826a72004-08-10 14:17:33 +00003820 if (expectedLen != 0)
3821 *expectedLen = facet->val->value.decimal.lo;
Daniel Veillard01fa6152004-06-29 17:04:39 +00003822 return (XML_SCHEMAV_CVC_MAXLENGTH_VALID);
3823 }
3824 } else
3825 /*
3826 * NOTE: That we can pass NULL as xmlSchemaValPtr to
3827 * xmlSchemaValidateFacet, since the remaining facet types
3828 * are: XML_SCHEMA_FACET_PATTERN, XML_SCHEMA_FACET_ENUMERATION.
3829 */
3830 return(xmlSchemaValidateFacet(NULL, facet, value, NULL));
3831 return (0);
3832}
3833
3834/**
Daniel Veillard6927b102004-10-27 17:29:04 +00003835 * xmlSchemaValidateLengthFacet:
Daniel Veillardc0826a72004-08-10 14:17:33 +00003836 * @type: the built-in type
3837 * @facet: the facet to check
3838 * @value: the lexical repr. of the value to be validated
3839 * @val: the precomputed value
3840 * @length: the actual length of the value
3841 *
3842 * Checka a value against a "length", "minLength" and "maxLength"
3843 * facet; sets @length to the computed length of @value.
3844 *
3845 * Returns 0 if the value is valid, a positive error code
3846 * otherwise and -1 in case of an internal or API error.
3847 */
3848int
3849xmlSchemaValidateLengthFacet(xmlSchemaTypePtr type,
3850 xmlSchemaFacetPtr facet,
3851 const xmlChar *value,
3852 xmlSchemaValPtr val,
3853 unsigned long *length)
3854{
3855 unsigned int len = 0;
3856
Daniel Veillardce682bc2004-11-05 17:22:25 +00003857 if ((length == NULL) || (facet == NULL) || (type == NULL))
3858 return (-1);
Daniel Veillardc0826a72004-08-10 14:17:33 +00003859 *length = 0;
3860 if ((facet->type != XML_SCHEMA_FACET_LENGTH) &&
3861 (facet->type != XML_SCHEMA_FACET_MAXLENGTH) &&
3862 (facet->type != XML_SCHEMA_FACET_MINLENGTH))
3863 return (-1);
3864
3865 if ((facet->val == NULL) ||
3866 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
3867 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
3868 (facet->val->value.decimal.frac != 0)) {
3869 return(-1);
3870 }
3871 if ((val != NULL) && (val->type == XML_SCHEMAS_HEXBINARY))
3872 len = val->value.hex.total;
3873 else if ((val != NULL) && (val->type == XML_SCHEMAS_BASE64BINARY))
3874 len = val->value.base64.total;
3875 else {
3876 switch (type->builtInType) {
3877 case XML_SCHEMAS_IDREF:
3878 case XML_SCHEMAS_NORMSTRING:
3879 case XML_SCHEMAS_TOKEN:
3880 case XML_SCHEMAS_LANGUAGE:
3881 case XML_SCHEMAS_NMTOKEN:
3882 case XML_SCHEMAS_NAME:
3883 case XML_SCHEMAS_NCNAME:
3884 case XML_SCHEMAS_ID:
3885 len = xmlSchemaNormLen(value);
3886 break;
3887 case XML_SCHEMAS_STRING:
3888 /*
3889 * FIXME: What exactly to do with anyURI?
3890 */
3891 case XML_SCHEMAS_ANYURI:
3892 if (value != NULL)
3893 len = xmlUTF8Strlen(value);
3894 break;
3895 default:
3896 TODO
3897 }
3898 }
3899 *length = (unsigned long) len;
3900 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
3901 if (len != facet->val->value.decimal.lo)
3902 return(XML_SCHEMAV_CVC_LENGTH_VALID);
3903 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
3904 if (len < facet->val->value.decimal.lo)
3905 return(XML_SCHEMAV_CVC_MINLENGTH_VALID);
3906 } else {
3907 if (len > facet->val->value.decimal.lo)
3908 return(XML_SCHEMAV_CVC_MAXLENGTH_VALID);
3909 }
3910
3911 return (0);
3912}
3913
3914/**
3915 * xmlSchemaValidateFacet:
Daniel Veillard01c13b52002-12-10 15:19:08 +00003916 * @base: the base type
Daniel Veillard4255d502002-04-16 15:50:10 +00003917 * @facet: the facet to check
3918 * @value: the lexical repr of the value to validate
3919 * @val: the precomputed value
3920 *
3921 * Check a value against a facet condition
3922 *
3923 * Returns 0 if the element is schemas valid, a positive error code
3924 * number otherwise and -1 in case of internal or API error.
3925 */
3926int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00003927xmlSchemaValidateFacet(xmlSchemaTypePtr base ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +00003928 xmlSchemaFacetPtr facet,
Daniel Veillard4255d502002-04-16 15:50:10 +00003929 const xmlChar *value, xmlSchemaValPtr val)
3930{
3931 int ret;
3932
Daniel Veillardce682bc2004-11-05 17:22:25 +00003933 if ((facet == NULL) || (value == NULL))
3934 return(-1);
Daniel Veillard4255d502002-04-16 15:50:10 +00003935 switch (facet->type) {
3936 case XML_SCHEMA_FACET_PATTERN:
3937 ret = xmlRegexpExec(facet->regexp, value);
3938 if (ret == 1)
3939 return(0);
3940 if (ret == 0) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00003941 return(XML_SCHEMAV_CVC_PATTERN_VALID);
Daniel Veillard4255d502002-04-16 15:50:10 +00003942 }
3943 return(ret);
3944 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
3945 ret = xmlSchemaCompareValues(val, facet->val);
3946 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003947 /* TODO error code */
Daniel Veillard4255d502002-04-16 15:50:10 +00003948 return(-1);
3949 }
3950 if (ret == -1)
3951 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00003952 /* error code */
Daniel Veillard01fa6152004-06-29 17:04:39 +00003953 return(XML_SCHEMAV_CVC_MAXEXCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00003954 case XML_SCHEMA_FACET_MAXINCLUSIVE:
3955 ret = xmlSchemaCompareValues(val, facet->val);
3956 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003957 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00003958 return(-1);
3959 }
3960 if ((ret == -1) || (ret == 0))
3961 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00003962 /* error code */
Daniel Veillard01fa6152004-06-29 17:04:39 +00003963 return(XML_SCHEMAV_CVC_MAXINCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00003964 case XML_SCHEMA_FACET_MINEXCLUSIVE:
3965 ret = xmlSchemaCompareValues(val, facet->val);
3966 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003967 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00003968 return(-1);
3969 }
3970 if (ret == 1)
3971 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00003972 /* error code */
Daniel Veillard01fa6152004-06-29 17:04:39 +00003973 return(XML_SCHEMAV_CVC_MINEXCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00003974 case XML_SCHEMA_FACET_MININCLUSIVE:
3975 ret = xmlSchemaCompareValues(val, facet->val);
3976 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003977 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00003978 return(-1);
3979 }
3980 if ((ret == 1) || (ret == 0))
3981 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00003982 /* error code */
Daniel Veillard01fa6152004-06-29 17:04:39 +00003983 return(XML_SCHEMAV_CVC_MININCLUSIVE_VALID);
Daniel Veillard8651f532002-04-17 09:06:27 +00003984 case XML_SCHEMA_FACET_WHITESPACE:
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003985 /* TODO whitespaces */
Daniel Veillard01fa6152004-06-29 17:04:39 +00003986 /*
3987 * NOTE: Whitespace should be handled to normalize
3988 * the value to be validated against a the facets;
3989 * not to normalize the value in-between.
3990 */
Daniel Veillard8651f532002-04-17 09:06:27 +00003991 return(0);
Daniel Veillard88c58912002-04-23 07:12:20 +00003992 case XML_SCHEMA_FACET_ENUMERATION:
3993 if ((facet->value != NULL) &&
3994 (xmlStrEqual(facet->value, value)))
3995 return(0);
Daniel Veillard01fa6152004-06-29 17:04:39 +00003996 return(XML_SCHEMAV_CVC_ENUMERATION_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003997 case XML_SCHEMA_FACET_LENGTH:
3998 case XML_SCHEMA_FACET_MAXLENGTH:
3999 case XML_SCHEMA_FACET_MINLENGTH: {
4000 unsigned int len = 0;
4001
4002 if ((facet->val == NULL) ||
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004003 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
4004 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004005 (facet->val->value.decimal.frac != 0)) {
4006 return(-1);
4007 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00004008 if ((val != NULL) && (val->type == XML_SCHEMAS_HEXBINARY))
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004009 len = val->value.hex.total;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00004010 else if ((val != NULL) && (val->type == XML_SCHEMAS_BASE64BINARY))
4011 len = val->value.base64.total;
4012 else {
Daniel Veillard01fa6152004-06-29 17:04:39 +00004013 switch (base->builtInType) {
Daniel Veillard560c2a42003-07-06 21:13:49 +00004014 case XML_SCHEMAS_IDREF:
4015 case XML_SCHEMAS_NORMSTRING:
4016 case XML_SCHEMAS_TOKEN:
4017 case XML_SCHEMAS_LANGUAGE:
4018 case XML_SCHEMAS_NMTOKEN:
4019 case XML_SCHEMAS_NAME:
4020 case XML_SCHEMAS_NCNAME:
4021 case XML_SCHEMAS_ID:
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004022 len = xmlSchemaNormLen(value);
4023 break;
Daniel Veillard560c2a42003-07-06 21:13:49 +00004024 case XML_SCHEMAS_STRING:
Daniel Veillard01fa6152004-06-29 17:04:39 +00004025 /*
4026 * FIXME: What exactly to do with anyURI?
4027 */
4028 case XML_SCHEMAS_ANYURI:
William M. Brackfbf2c5e2004-02-03 17:55:56 +00004029 if (value != NULL)
4030 len = xmlUTF8Strlen(value);
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004031 break;
Daniel Veillard560c2a42003-07-06 21:13:49 +00004032 default:
4033 TODO
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004034 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004035 }
4036 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004037 if (len != facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004038 return(XML_SCHEMAV_CVC_LENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004039 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004040 if (len < facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004041 return(XML_SCHEMAV_CVC_MINLENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004042 } else {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004043 if (len > facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004044 return(XML_SCHEMAV_CVC_MAXLENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004045 }
4046 break;
4047 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00004048 case XML_SCHEMA_FACET_TOTALDIGITS:
4049 case XML_SCHEMA_FACET_FRACTIONDIGITS:
4050
4051 if ((facet->val == NULL) ||
4052 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
4053 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
4054 (facet->val->value.decimal.frac != 0)) {
4055 return(-1);
4056 }
4057 if ((val == NULL) ||
4058 ((val->type != XML_SCHEMAS_DECIMAL) &&
4059 (val->type != XML_SCHEMAS_INTEGER) &&
4060 (val->type != XML_SCHEMAS_NPINTEGER) &&
4061 (val->type != XML_SCHEMAS_NINTEGER) &&
4062 (val->type != XML_SCHEMAS_NNINTEGER) &&
4063 (val->type != XML_SCHEMAS_PINTEGER) &&
4064 (val->type != XML_SCHEMAS_INT) &&
4065 (val->type != XML_SCHEMAS_UINT) &&
4066 (val->type != XML_SCHEMAS_LONG) &&
4067 (val->type != XML_SCHEMAS_ULONG) &&
4068 (val->type != XML_SCHEMAS_SHORT) &&
4069 (val->type != XML_SCHEMAS_USHORT) &&
4070 (val->type != XML_SCHEMAS_BYTE) &&
4071 (val->type != XML_SCHEMAS_UBYTE))) {
4072 return(-1);
4073 }
4074 if (facet->type == XML_SCHEMA_FACET_TOTALDIGITS) {
4075 if (val->value.decimal.total > facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004076 return(XML_SCHEMAV_CVC_TOTALDIGITS_VALID);
Daniel Veillard560c2a42003-07-06 21:13:49 +00004077
4078 } else if (facet->type == XML_SCHEMA_FACET_FRACTIONDIGITS) {
4079 if (val->value.decimal.frac > facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004080 return(XML_SCHEMAV_CVC_FRACTIONDIGITS_VALID);
Daniel Veillard560c2a42003-07-06 21:13:49 +00004081 }
4082 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00004083 default:
4084 TODO
4085 }
4086 return(0);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00004087
Daniel Veillard4255d502002-04-16 15:50:10 +00004088}
4089
4090#endif /* LIBXML_SCHEMAS_ENABLED */