blob: 3ff8acfe7d2542ce223beed7f8ddfcfcd9be770f [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/**
Kasimier T. Buchcik91feaf82004-11-12 14:04:58 +00001548 * xmlSchemaWhiteSpaceReplace:
1549 * @value: a value
1550 *
1551 * Replaces 0xd, 0x9 and 0xa with a space.
1552 *
1553 * Returns the new string or NULL if no change was required.
1554 */
1555xmlChar *
1556xmlSchemaWhiteSpaceReplace(const xmlChar *value) {
1557 const xmlChar *cur = value;
1558 xmlChar *ret = NULL, *mcur;
1559
1560 if (value == NULL)
1561 return(NULL);
1562
1563 while ((*cur != 0) &&
1564 (((*cur) != 0xd) && ((*cur) != 0x9) && ((*cur) != 0xa))) {
1565 cur++;
1566 }
1567 if (*cur == 0)
1568 return (NULL);
1569 ret = xmlStrdup(value);
1570 /* TODO FIXME: I guess gcc will bark at this. */
1571 mcur = (xmlChar *) (ret + (cur - value));
1572 do {
1573 if ( ((*mcur) == 0xd) || ((*mcur) == 0x9) || ((*mcur) == 0xa) )
1574 *mcur = ' ';
1575 mcur++;
1576 } while (*mcur != 0);
1577 return(ret);
1578}
1579
1580/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001581 * xmlSchemaCollapseString:
1582 * @value: a value
1583 *
1584 * Removes and normalize white spaces in the string
1585 *
1586 * Returns the new string or NULL if no change was required.
1587 */
Daniel Veillard01fa6152004-06-29 17:04:39 +00001588xmlChar *
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001589xmlSchemaCollapseString(const xmlChar *value) {
1590 const xmlChar *start = value, *end, *f;
1591 xmlChar *g;
1592 int col = 0;
1593
1594 if (value == NULL) return(NULL);
William M. Brack76e95df2003-10-18 16:20:14 +00001595 while ((*start != 0) && (IS_BLANK_CH(*start))) start++;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001596 end = start;
1597 while (*end != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00001598 if ((*end == ' ') && (IS_BLANK_CH(end[1]))) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001599 col = end - start;
1600 break;
1601 } else if ((*end == 0xa) || (*end == 0x9) || (*end == 0xd)) {
1602 col = end - start;
1603 break;
1604 }
1605 end++;
1606 }
1607 if (col == 0) {
1608 f = end;
1609 end--;
William M. Brack76e95df2003-10-18 16:20:14 +00001610 while ((end > start) && (IS_BLANK_CH(*end))) end--;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001611 end++;
1612 if ((start == value) && (f == end)) return(NULL);
1613 return(xmlStrndup(start, end - start));
1614 }
1615 start = xmlStrdup(start);
1616 if (start == NULL) return(NULL);
1617 g = (xmlChar *) (start + col);
1618 end = g;
1619 while (*end != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00001620 if (IS_BLANK_CH(*end)) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001621 end++;
William M. Brack76e95df2003-10-18 16:20:14 +00001622 while (IS_BLANK_CH(*end)) end++;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001623 if (*end != 0)
1624 *g++ = ' ';
1625 } else
1626 *g++ = *end++;
1627 }
1628 *g = 0;
1629 return((xmlChar *) start);
1630}
1631
1632/**
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001633 * xmlSchemaValAtomicListNode:
1634 * @type: the predefined atomic type for a token in the list
1635 * @value: the list value to check
1636 * @ret: the return computed value
1637 * @node: the node containing the value
1638 *
1639 * Check that a value conforms to the lexical space of the predefined
1640 * list type. if true a value is computed and returned in @ret.
1641 *
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001642 * Returns the number of items if this validates, a negative error code
1643 * number otherwise
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001644 */
1645static int
1646xmlSchemaValAtomicListNode(xmlSchemaTypePtr type, const xmlChar *value,
1647 xmlSchemaValPtr *ret, xmlNodePtr node) {
1648 xmlChar *val, *cur, *endval;
1649 int nb_values = 0;
Daniel Veillard580ced82003-03-21 21:22:48 +00001650 int tmp = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001651
1652 if (value == NULL) {
1653 return(-1);
1654 }
1655 val = xmlStrdup(value);
1656 if (val == NULL) {
1657 return(-1);
1658 }
Daniel Veillard6fc5db02005-01-16 00:05:58 +00001659 if (ret != NULL) {
1660 *ret = NULL;
1661 }
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001662 cur = val;
1663 /*
1664 * Split the list
1665 */
William M. Brack76e95df2003-10-18 16:20:14 +00001666 while (IS_BLANK_CH(*cur)) *cur++ = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001667 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00001668 if (IS_BLANK_CH(*cur)) {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001669 *cur = 0;
1670 cur++;
William M. Brack76e95df2003-10-18 16:20:14 +00001671 while (IS_BLANK_CH(*cur)) *cur++ = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001672 } else {
1673 nb_values++;
1674 cur++;
William M. Brack76e95df2003-10-18 16:20:14 +00001675 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001676 }
1677 }
1678 if (nb_values == 0) {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001679 xmlFree(val);
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001680 return(nb_values);
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001681 }
1682 endval = cur;
1683 cur = val;
1684 while ((*cur == 0) && (cur != endval)) cur++;
1685 while (cur != endval) {
1686 tmp = xmlSchemaValPredefTypeNode(type, cur, NULL, node);
1687 if (tmp != 0)
1688 break;
1689 while (*cur != 0) cur++;
1690 while ((*cur == 0) && (cur != endval)) cur++;
1691 }
Daniel Veillard6fc5db02005-01-16 00:05:58 +00001692 /* TODO what return value ? c.f. bug #158628
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001693 if (ret != NULL) {
1694 TODO
Daniel Veillard6fc5db02005-01-16 00:05:58 +00001695 } */
1696 xmlFree(val);
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001697 if (tmp == 0)
1698 return(nb_values);
1699 return(-1);
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001700}
1701
1702/**
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001703 * xmlSchemaParseUInt:
1704 * @str: pointer to the string R/W
1705 * @llo: pointer to the low result
1706 * @lmi: pointer to the mid result
1707 * @lhi: pointer to the high result
1708 *
1709 * Parse an unsigned long into 3 fields.
1710 *
1711 * Returns the number of chars parsed or -1 if overflow of the capacity
1712 */
1713static int
1714xmlSchemaParseUInt(const xmlChar **str, unsigned long *llo,
1715 unsigned long *lmi, unsigned long *lhi) {
1716 unsigned long lo = 0, mi = 0, hi = 0;
1717 const xmlChar *tmp, *cur = *str;
1718 int ret = 0, i = 0;
1719
1720 while (*cur == '0') {
1721 ret++;
1722 cur++;
1723 }
1724 tmp = cur;
1725 while ((*tmp != 0) && (*tmp >= '0') && (*tmp <= '9')) {
1726 i++;tmp++;ret++;
1727 }
1728 if (i > 24) {
1729 *str = tmp;
1730 return(-1);
1731 }
1732 while (i > 16) {
1733 hi = hi * 10 + (*cur++ - '0');
1734 i--;
1735 }
1736 while (i > 8) {
1737 mi = mi * 10 + (*cur++ - '0');
1738 i--;
1739 }
1740 while (i > 0) {
1741 lo = lo * 10 + (*cur++ - '0');
1742 i--;
1743 }
1744
1745 *str = cur;
1746 *llo = lo;
1747 *lmi = mi;
1748 *lhi = hi;
1749 return(ret);
1750}
1751
1752/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001753 * xmlSchemaValAtomicType:
1754 * @type: the predefined type
1755 * @value: the value to check
1756 * @val: the return computed value
1757 * @node: the node containing the value
1758 * flags: flags to control the vlidation
1759 *
1760 * Check that a value conforms to the lexical space of the atomic type.
1761 * if true a value is computed and returned in @val.
Daniel Veillard01fa6152004-06-29 17:04:39 +00001762 * This checks the value space for list types as well (IDREFS, NMTOKENS).
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001763 *
1764 * Returns 0 if this validates, a positive error code number otherwise
1765 * and -1 in case of internal or API error.
1766 */
1767static int
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001768xmlSchemaValAtomicType(xmlSchemaTypePtr type, const xmlChar * value,
1769 xmlSchemaValPtr * val, xmlNodePtr node, int flags)
1770{
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001771 xmlSchemaValPtr v;
1772 xmlChar *norm = NULL;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001773 int ret = 0;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001774
1775 if (xmlSchemaTypesInitialized == 0)
Daniel Veillard01fa6152004-06-29 17:04:39 +00001776 xmlSchemaInitTypes();
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001777 if (type == NULL)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001778 return (-1);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001779
Daniel Veillardeebd6332004-08-26 10:30:44 +00001780 /*
1781 * validating a non existant text node is similar to validating
1782 * an empty one.
1783 */
1784 if (value == NULL)
1785 value = BAD_CAST "";
1786
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001787 if (val != NULL)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001788 *val = NULL;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001789 if ((flags == 0) && (value != NULL)) {
Kasimier T. Buchcik91feaf82004-11-12 14:04:58 +00001790
Daniel Veillard01fa6152004-06-29 17:04:39 +00001791 if ((type->builtInType != XML_SCHEMAS_STRING) &&
Kasimier T. Buchcik91feaf82004-11-12 14:04:58 +00001792 (type->builtInType != XML_SCHEMAS_ANYTYPE) &&
1793 (type->builtInType != XML_SCHEMAS_ANYSIMPLETYPE)) {
1794 if (type->builtInType == XML_SCHEMAS_NORMSTRING)
1795 norm = xmlSchemaWhiteSpaceReplace(value);
1796 else
1797 norm = xmlSchemaCollapseString(value);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001798 if (norm != NULL)
1799 value = norm;
1800 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001801 }
1802
Daniel Veillard01fa6152004-06-29 17:04:39 +00001803 switch (type->builtInType) {
William M. Brack2f2a6632004-08-20 23:09:47 +00001804 case XML_SCHEMAS_UNKNOWN:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001805 goto error;
William M. Brack2f2a6632004-08-20 23:09:47 +00001806 case XML_SCHEMAS_ANYTYPE:
1807 case XML_SCHEMAS_ANYSIMPLETYPE:
1808 goto return0;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001809 case XML_SCHEMAS_STRING:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001810 goto return0;
Daniel Veillard1516d5b2004-01-22 07:27:45 +00001811 case XML_SCHEMAS_NORMSTRING:{
1812 const xmlChar *cur = value;
1813
1814 while (*cur != 0) {
1815 if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) {
1816 goto return1;
1817 } else {
1818 cur++;
1819 }
1820 }
1821 if (val != NULL) {
1822 v = xmlSchemaNewValue(XML_SCHEMAS_NORMSTRING);
1823 if (v != NULL) {
1824 v->value.str = xmlStrdup(value);
1825 *val = v;
1826 } else {
1827 goto error;
1828 }
1829 }
1830 goto return0;
1831 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001832 case XML_SCHEMAS_DECIMAL:{
1833 const xmlChar *cur = value, *tmp;
1834 unsigned int frac = 0, len, neg = 0;
1835 unsigned long base = 0;
1836
1837 if (cur == NULL)
1838 goto return1;
1839 if (*cur == '+')
1840 cur++;
1841 else if (*cur == '-') {
1842 neg = 1;
1843 cur++;
1844 }
1845 tmp = cur;
1846 while ((*cur >= '0') && (*cur <= '9')) {
1847 base = base * 10 + (*cur - '0');
1848 cur++;
1849 }
1850 len = cur - tmp;
1851 if (*cur == '.') {
1852 cur++;
1853 tmp = cur;
1854 while ((*cur >= '0') && (*cur <= '9')) {
1855 base = base * 10 + (*cur - '0');
1856 cur++;
1857 }
1858 frac = cur - tmp;
1859 }
1860 if (*cur != 0)
1861 goto return1;
1862 if (val != NULL) {
1863 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
1864 if (v != NULL) {
1865 v->value.decimal.lo = base;
1866 v->value.decimal.sign = neg;
1867 v->value.decimal.frac = frac;
1868 v->value.decimal.total = frac + len;
1869 *val = v;
1870 }
1871 }
1872 goto return0;
1873 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001874 case XML_SCHEMAS_TIME:
1875 case XML_SCHEMAS_GDAY:
1876 case XML_SCHEMAS_GMONTH:
1877 case XML_SCHEMAS_GMONTHDAY:
1878 case XML_SCHEMAS_GYEAR:
1879 case XML_SCHEMAS_GYEARMONTH:
1880 case XML_SCHEMAS_DATE:
1881 case XML_SCHEMAS_DATETIME:
Daniel Veillard01fa6152004-06-29 17:04:39 +00001882 ret = xmlSchemaValidateDates(type->builtInType, value, val);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001883 break;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001884 case XML_SCHEMAS_DURATION:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001885 ret = xmlSchemaValidateDuration(type, value, val);
1886 break;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001887 case XML_SCHEMAS_FLOAT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001888 case XML_SCHEMAS_DOUBLE:{
1889 const xmlChar *cur = value;
1890 int neg = 0;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001891
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001892 if (cur == NULL)
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00001893 goto return1;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001894 if ((cur[0] == 'N') && (cur[1] == 'a') && (cur[2] == 'N')) {
1895 cur += 3;
1896 if (*cur != 0)
1897 goto return1;
1898 if (val != NULL) {
1899 if (type == xmlSchemaTypeFloatDef) {
1900 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1901 if (v != NULL) {
1902 v->value.f = (float) xmlXPathNAN;
1903 } else {
1904 xmlSchemaFreeValue(v);
1905 goto error;
1906 }
1907 } else {
1908 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1909 if (v != NULL) {
1910 v->value.d = xmlXPathNAN;
1911 } else {
1912 xmlSchemaFreeValue(v);
1913 goto error;
1914 }
1915 }
1916 *val = v;
1917 }
1918 goto return0;
1919 }
1920 if (*cur == '-') {
1921 neg = 1;
1922 cur++;
1923 }
1924 if ((cur[0] == 'I') && (cur[1] == 'N') && (cur[2] == 'F')) {
1925 cur += 3;
1926 if (*cur != 0)
1927 goto return1;
1928 if (val != NULL) {
1929 if (type == xmlSchemaTypeFloatDef) {
1930 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1931 if (v != NULL) {
1932 if (neg)
1933 v->value.f = (float) xmlXPathNINF;
1934 else
1935 v->value.f = (float) xmlXPathPINF;
1936 } else {
1937 xmlSchemaFreeValue(v);
1938 goto error;
1939 }
1940 } else {
1941 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1942 if (v != NULL) {
1943 if (neg)
1944 v->value.d = xmlXPathNINF;
1945 else
1946 v->value.d = xmlXPathPINF;
1947 } else {
1948 xmlSchemaFreeValue(v);
1949 goto error;
1950 }
1951 }
1952 *val = v;
1953 }
1954 goto return0;
1955 }
1956 if ((neg == 0) && (*cur == '+'))
1957 cur++;
1958 if ((cur[0] == 0) || (cur[0] == '+') || (cur[0] == '-'))
1959 goto return1;
1960 while ((*cur >= '0') && (*cur <= '9')) {
1961 cur++;
1962 }
1963 if (*cur == '.') {
1964 cur++;
1965 while ((*cur >= '0') && (*cur <= '9'))
1966 cur++;
1967 }
1968 if ((*cur == 'e') || (*cur == 'E')) {
1969 cur++;
1970 if ((*cur == '-') || (*cur == '+'))
1971 cur++;
1972 while ((*cur >= '0') && (*cur <= '9'))
1973 cur++;
1974 }
1975 if (*cur != 0)
1976 goto return1;
1977 if (val != NULL) {
1978 if (type == xmlSchemaTypeFloatDef) {
1979 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1980 if (v != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001981 if (sscanf((const char *) value, "%f",
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001982 &(v->value.f)) == 1) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00001983 *val = v;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001984 } else {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001985 xmlSchemaFreeValue(v);
1986 goto return1;
1987 }
1988 } else {
1989 goto error;
1990 }
1991 } else {
1992 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1993 if (v != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001994 if (sscanf((const char *) value, "%lf",
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001995 &(v->value.d)) == 1) {
1996 *val = v;
1997 } else {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001998 xmlSchemaFreeValue(v);
1999 goto return1;
2000 }
2001 } else {
2002 goto error;
2003 }
2004 }
2005 }
2006 goto return0;
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00002007 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002008 case XML_SCHEMAS_BOOLEAN:{
2009 const xmlChar *cur = value;
2010
2011 if ((cur[0] == '0') && (cur[1] == 0))
2012 ret = 0;
2013 else if ((cur[0] == '1') && (cur[1] == 0))
2014 ret = 1;
2015 else if ((cur[0] == 't') && (cur[1] == 'r')
2016 && (cur[2] == 'u') && (cur[3] == 'e')
2017 && (cur[4] == 0))
2018 ret = 1;
2019 else if ((cur[0] == 'f') && (cur[1] == 'a')
2020 && (cur[2] == 'l') && (cur[3] == 's')
2021 && (cur[4] == 'e') && (cur[5] == 0))
2022 ret = 0;
2023 else
2024 goto return1;
2025 if (val != NULL) {
2026 v = xmlSchemaNewValue(XML_SCHEMAS_BOOLEAN);
2027 if (v != NULL) {
2028 v->value.b = ret;
2029 *val = v;
2030 } else {
2031 goto error;
2032 }
2033 }
2034 goto return0;
2035 }
2036 case XML_SCHEMAS_TOKEN:{
2037 const xmlChar *cur = value;
2038
William M. Brack76e95df2003-10-18 16:20:14 +00002039 if (IS_BLANK_CH(*cur))
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002040 goto return1;
2041
2042 while (*cur != 0) {
2043 if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) {
2044 goto return1;
2045 } else if (*cur == ' ') {
2046 cur++;
2047 if (*cur == 0)
2048 goto return1;
2049 if (*cur == ' ')
2050 goto return1;
2051 } else {
2052 cur++;
2053 }
2054 }
2055 if (val != NULL) {
2056 v = xmlSchemaNewValue(XML_SCHEMAS_TOKEN);
2057 if (v != NULL) {
2058 v->value.str = xmlStrdup(value);
2059 *val = v;
2060 } else {
2061 goto error;
2062 }
2063 }
2064 goto return0;
2065 }
2066 case XML_SCHEMAS_LANGUAGE:
2067 if (xmlCheckLanguageID(value) == 1) {
2068 if (val != NULL) {
2069 v = xmlSchemaNewValue(XML_SCHEMAS_LANGUAGE);
2070 if (v != NULL) {
2071 v->value.str = xmlStrdup(value);
2072 *val = v;
2073 } else {
2074 goto error;
2075 }
2076 }
2077 goto return0;
2078 }
2079 goto return1;
2080 case XML_SCHEMAS_NMTOKEN:
2081 if (xmlValidateNMToken(value, 1) == 0) {
2082 if (val != NULL) {
2083 v = xmlSchemaNewValue(XML_SCHEMAS_NMTOKEN);
2084 if (v != NULL) {
2085 v->value.str = xmlStrdup(value);
2086 *val = v;
2087 } else {
2088 goto error;
2089 }
2090 }
2091 goto return0;
2092 }
2093 goto return1;
2094 case XML_SCHEMAS_NMTOKENS:
2095 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeNmtokenDef,
2096 value, val, node);
2097 if (ret > 0)
2098 ret = 0;
2099 else
2100 ret = 1;
2101 goto done;
2102 case XML_SCHEMAS_NAME:
2103 ret = xmlValidateName(value, 1);
Daniel Veillarddf292f72005-01-16 19:00:15 +00002104 if ((ret == 0) && (val != NULL) && (value != NULL)) {
2105 v = xmlSchemaNewValue(XML_SCHEMAS_NAME);
2106 if (v != NULL) {
2107 const xmlChar *start = value, *end;
2108 while (IS_BLANK_CH(*start)) start++;
2109 end = start;
2110 while ((*end != 0) && (!IS_BLANK_CH(*end))) end++;
2111 v->value.str = xmlStrndup(start, end - start);
2112 *val = v;
2113 } else {
2114 goto error;
2115 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002116 }
2117 goto done;
2118 case XML_SCHEMAS_QNAME:{
2119 xmlChar *uri = NULL;
2120 xmlChar *local = NULL;
2121
2122 ret = xmlValidateQName(value, 1);
2123 if ((ret == 0) && (node != NULL)) {
2124 xmlChar *prefix;
2125
2126 local = xmlSplitQName2(value, &prefix);
2127 if (prefix != NULL) {
2128 xmlNsPtr ns;
2129
2130 ns = xmlSearchNs(node->doc, node, prefix);
2131 if (ns == NULL)
2132 ret = 1;
2133 else if (val != NULL)
2134 uri = xmlStrdup(ns->href);
2135 }
2136 if ((local != NULL) && ((val == NULL) || (ret != 0)))
2137 xmlFree(local);
2138 if (prefix != NULL)
2139 xmlFree(prefix);
2140 }
2141 if ((ret == 0) && (val != NULL)) {
2142 v = xmlSchemaNewValue(XML_SCHEMAS_QNAME);
2143 if (v != NULL) {
2144 if (local != NULL)
2145 v->value.qname.name = local;
2146 else
2147 v->value.qname.name = xmlStrdup(value);
2148 if (uri != NULL)
2149 v->value.qname.uri = uri;
2150
2151 *val = v;
2152 } else {
2153 if (local != NULL)
2154 xmlFree(local);
2155 if (uri != NULL)
2156 xmlFree(uri);
2157 goto error;
2158 }
2159 }
2160 goto done;
2161 }
2162 case XML_SCHEMAS_NCNAME:
2163 ret = xmlValidateNCName(value, 1);
2164 if ((ret == 0) && (val != NULL)) {
2165 v = xmlSchemaNewValue(XML_SCHEMAS_NCNAME);
2166 if (v != NULL) {
2167 v->value.str = xmlStrdup(value);
2168 *val = v;
2169 } else {
2170 goto error;
2171 }
2172 }
2173 goto done;
2174 case XML_SCHEMAS_ID:
2175 ret = xmlValidateNCName(value, 1);
2176 if ((ret == 0) && (val != NULL)) {
2177 v = xmlSchemaNewValue(XML_SCHEMAS_ID);
2178 if (v != NULL) {
2179 v->value.str = xmlStrdup(value);
2180 *val = v;
2181 } else {
2182 goto error;
2183 }
2184 }
2185 if ((ret == 0) && (node != NULL) &&
2186 (node->type == XML_ATTRIBUTE_NODE)) {
2187 xmlAttrPtr attr = (xmlAttrPtr) node;
2188
2189 /*
2190 * NOTE: the IDness might have already be declared in the DTD
2191 */
2192 if (attr->atype != XML_ATTRIBUTE_ID) {
2193 xmlIDPtr res;
2194 xmlChar *strip;
2195
2196 strip = xmlSchemaStrip(value);
2197 if (strip != NULL) {
2198 res = xmlAddID(NULL, node->doc, strip, attr);
2199 xmlFree(strip);
2200 } else
2201 res = xmlAddID(NULL, node->doc, value, attr);
2202 if (res == NULL) {
2203 ret = 2;
2204 } else {
2205 attr->atype = XML_ATTRIBUTE_ID;
2206 }
2207 }
2208 }
2209 goto done;
2210 case XML_SCHEMAS_IDREF:
2211 ret = xmlValidateNCName(value, 1);
2212 if ((ret == 0) && (val != NULL)) {
2213 TODO;
2214 }
2215 if ((ret == 0) && (node != NULL) &&
2216 (node->type == XML_ATTRIBUTE_NODE)) {
2217 xmlAttrPtr attr = (xmlAttrPtr) node;
2218 xmlChar *strip;
2219
2220 strip = xmlSchemaStrip(value);
2221 if (strip != NULL) {
2222 xmlAddRef(NULL, node->doc, strip, attr);
2223 xmlFree(strip);
2224 } else
2225 xmlAddRef(NULL, node->doc, value, attr);
2226 attr->atype = XML_ATTRIBUTE_IDREF;
2227 }
2228 goto done;
2229 case XML_SCHEMAS_IDREFS:
2230 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeIdrefDef,
2231 value, val, node);
2232 if (ret < 0)
2233 ret = 2;
2234 else
2235 ret = 0;
2236 if ((ret == 0) && (node != NULL) &&
2237 (node->type == XML_ATTRIBUTE_NODE)) {
2238 xmlAttrPtr attr = (xmlAttrPtr) node;
2239
2240 attr->atype = XML_ATTRIBUTE_IDREFS;
2241 }
2242 goto done;
2243 case XML_SCHEMAS_ENTITY:{
2244 xmlChar *strip;
2245
2246 ret = xmlValidateNCName(value, 1);
2247 if ((node == NULL) || (node->doc == NULL))
2248 ret = 3;
2249 if (ret == 0) {
2250 xmlEntityPtr ent;
2251
2252 strip = xmlSchemaStrip(value);
2253 if (strip != NULL) {
2254 ent = xmlGetDocEntity(node->doc, strip);
2255 xmlFree(strip);
2256 } else {
2257 ent = xmlGetDocEntity(node->doc, value);
2258 }
2259 if ((ent == NULL) ||
2260 (ent->etype !=
2261 XML_EXTERNAL_GENERAL_UNPARSED_ENTITY))
2262 ret = 4;
2263 }
2264 if ((ret == 0) && (val != NULL)) {
2265 TODO;
2266 }
2267 if ((ret == 0) && (node != NULL) &&
2268 (node->type == XML_ATTRIBUTE_NODE)) {
2269 xmlAttrPtr attr = (xmlAttrPtr) node;
2270
2271 attr->atype = XML_ATTRIBUTE_ENTITY;
2272 }
2273 goto done;
2274 }
2275 case XML_SCHEMAS_ENTITIES:
2276 if ((node == NULL) || (node->doc == NULL))
2277 goto return3;
2278 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeEntityDef,
2279 value, val, node);
2280 if (ret <= 0)
2281 ret = 1;
2282 else
2283 ret = 0;
2284 if ((ret == 0) && (node != NULL) &&
2285 (node->type == XML_ATTRIBUTE_NODE)) {
2286 xmlAttrPtr attr = (xmlAttrPtr) node;
2287
2288 attr->atype = XML_ATTRIBUTE_ENTITIES;
2289 }
2290 goto done;
2291 case XML_SCHEMAS_NOTATION:{
2292 xmlChar *uri = NULL;
2293 xmlChar *local = NULL;
2294
2295 ret = xmlValidateQName(value, 1);
2296 if ((ret == 0) && (node != NULL)) {
2297 xmlChar *prefix;
2298
2299 local = xmlSplitQName2(value, &prefix);
2300 if (prefix != NULL) {
2301 xmlNsPtr ns;
2302
2303 ns = xmlSearchNs(node->doc, node, prefix);
2304 if (ns == NULL)
2305 ret = 1;
2306 else if (val != NULL)
2307 uri = xmlStrdup(ns->href);
2308 }
2309 if ((local != NULL) && ((val == NULL) || (ret != 0)))
2310 xmlFree(local);
2311 if (prefix != NULL)
2312 xmlFree(prefix);
2313 }
2314 if ((node == NULL) || (node->doc == NULL))
2315 ret = 3;
2316 if (ret == 0) {
2317 ret = xmlValidateNotationUse(NULL, node->doc, value);
2318 if (ret == 1)
2319 ret = 0;
2320 else
2321 ret = 1;
2322 }
2323 if ((ret == 0) && (val != NULL)) {
2324 v = xmlSchemaNewValue(XML_SCHEMAS_NOTATION);
2325 if (v != NULL) {
2326 if (local != NULL)
2327 v->value.qname.name = local;
2328 else
2329 v->value.qname.name = xmlStrdup(value);
2330 if (uri != NULL)
2331 v->value.qname.uri = uri;
2332
2333 *val = v;
2334 } else {
2335 if (local != NULL)
2336 xmlFree(local);
2337 if (uri != NULL)
2338 xmlFree(uri);
2339 goto error;
2340 }
2341 }
2342 goto done;
2343 }
2344 case XML_SCHEMAS_ANYURI:{
Daniel Veillard11c466a2004-03-14 12:20:15 +00002345 if (*value != 0) {
2346 xmlURIPtr uri = xmlParseURI((const char *) value);
2347 if (uri == NULL)
2348 goto return1;
2349 xmlFreeURI(uri);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002350 }
Daniel Veillard11c466a2004-03-14 12:20:15 +00002351
2352 if (val != NULL) {
2353 v = xmlSchemaNewValue(XML_SCHEMAS_ANYURI);
2354 if (v == NULL)
2355 goto error;
2356 v->value.str = xmlStrdup(value);
2357 *val = v;
2358 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002359 goto return0;
2360 }
2361 case XML_SCHEMAS_HEXBINARY:{
2362 const xmlChar *cur = value;
2363 xmlChar *base;
2364 int total, i = 0;
2365
Daniel Veillardf34a20e2004-08-31 08:42:17 +00002366 if (cur == NULL)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002367 goto return1;
2368
2369 while (((*cur >= '0') && (*cur <= '9')) ||
2370 ((*cur >= 'A') && (*cur <= 'F')) ||
2371 ((*cur >= 'a') && (*cur <= 'f'))) {
2372 i++;
2373 cur++;
2374 }
2375
2376 if (*cur != 0)
2377 goto return1;
2378 if ((i % 2) != 0)
2379 goto return1;
2380
2381 if (val != NULL) {
2382
2383 v = xmlSchemaNewValue(XML_SCHEMAS_HEXBINARY);
2384 if (v == NULL)
2385 goto error;
2386
2387 cur = xmlStrdup(value);
2388 if (cur == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002389 xmlSchemaTypeErrMemory(node, "allocating hexbin data");
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002390 xmlFree(v);
2391 goto return1;
2392 }
2393
2394 total = i / 2; /* number of octets */
2395
2396 base = (xmlChar *) cur;
2397 while (i-- > 0) {
2398 if (*base >= 'a')
2399 *base = *base - ('a' - 'A');
2400 base++;
2401 }
2402
2403 v->value.hex.str = (xmlChar *) cur;
2404 v->value.hex.total = total;
2405 *val = v;
2406 }
2407 goto return0;
2408 }
2409 case XML_SCHEMAS_BASE64BINARY:{
2410 /* ISSUE:
2411 *
2412 * Ignore all stray characters? (yes, currently)
2413 * Worry about long lines? (no, currently)
2414 *
2415 * rfc2045.txt:
2416 *
2417 * "The encoded output stream must be represented in lines of
2418 * no more than 76 characters each. All line breaks or other
2419 * characters not found in Table 1 must be ignored by decoding
2420 * software. In base64 data, characters other than those in
2421 * Table 1, line breaks, and other white space probably
2422 * indicate a transmission error, about which a warning
2423 * message or even a message rejection might be appropriate
2424 * under some circumstances." */
2425 const xmlChar *cur = value;
2426 xmlChar *base;
2427 int total, i = 0, pad = 0;
2428
2429 if (cur == NULL)
2430 goto return1;
2431
2432 for (; *cur; ++cur) {
2433 int decc;
2434
2435 decc = _xmlSchemaBase64Decode(*cur);
2436 if (decc < 0) ;
2437 else if (decc < 64)
2438 i++;
2439 else
2440 break;
2441 }
2442 for (; *cur; ++cur) {
2443 int decc;
2444
2445 decc = _xmlSchemaBase64Decode(*cur);
2446 if (decc < 0) ;
2447 else if (decc < 64)
2448 goto return1;
2449 if (decc == 64)
2450 pad++;
2451 }
2452
2453 /* rfc2045.txt: "Special processing is performed if fewer than
2454 * 24 bits are available at the end of the data being encoded.
2455 * A full encoding quantum is always completed at the end of a
2456 * body. When fewer than 24 input bits are available in an
2457 * input group, zero bits are added (on the right) to form an
2458 * integral number of 6-bit groups. Padding at the end of the
2459 * data is performed using the "=" character. Since all
2460 * base64 input is an integral number of octets, only the
2461 * following cases can arise: (1) the final quantum of
2462 * encoding input is an integral multiple of 24 bits; here,
2463 * the final unit of encoded output will be an integral
2464 * multiple ofindent: Standard input:701: Warning:old style
2465 * assignment ambiguity in "=*". Assuming "= *" 4 characters
2466 * with no "=" padding, (2) the final
2467 * quantum of encoding input is exactly 8 bits; here, the
2468 * final unit of encoded output will be two characters
2469 * followed by two "=" padding characters, or (3) the final
2470 * quantum of encoding input is exactly 16 bits; here, the
2471 * final unit of encoded output will be three characters
2472 * followed by one "=" padding character." */
2473
2474 total = 3 * (i / 4);
2475 if (pad == 0) {
2476 if (i % 4 != 0)
2477 goto return1;
2478 } else if (pad == 1) {
2479 int decc;
2480
2481 if (i % 4 != 3)
2482 goto return1;
2483 for (decc = _xmlSchemaBase64Decode(*cur);
2484 (decc < 0) || (decc > 63);
2485 decc = _xmlSchemaBase64Decode(*cur))
2486 --cur;
2487 /* 16bits in 24bits means 2 pad bits: nnnnnn nnmmmm mmmm00*/
2488 /* 00111100 -> 0x3c */
2489 if (decc & ~0x3c)
2490 goto return1;
2491 total += 2;
2492 } else if (pad == 2) {
2493 int decc;
2494
2495 if (i % 4 != 2)
2496 goto return1;
2497 for (decc = _xmlSchemaBase64Decode(*cur);
2498 (decc < 0) || (decc > 63);
2499 decc = _xmlSchemaBase64Decode(*cur))
2500 --cur;
2501 /* 8bits in 12bits means 4 pad bits: nnnnnn nn0000 */
2502 /* 00110000 -> 0x30 */
2503 if (decc & ~0x30)
2504 goto return1;
2505 total += 1;
2506 } else
2507 goto return1;
2508
2509 if (val != NULL) {
2510 v = xmlSchemaNewValue(XML_SCHEMAS_BASE64BINARY);
2511 if (v == NULL)
2512 goto error;
2513 base =
2514 (xmlChar *) xmlMallocAtomic((i + pad + 1) *
2515 sizeof(xmlChar));
2516 if (base == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002517 xmlSchemaTypeErrMemory(node, "allocating base64 data");
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002518 xmlFree(v);
2519 goto return1;
2520 }
2521 v->value.base64.str = base;
2522 for (cur = value; *cur; ++cur)
2523 if (_xmlSchemaBase64Decode(*cur) >= 0) {
2524 *base = *cur;
2525 ++base;
2526 }
2527 *base = 0;
2528 v->value.base64.total = total;
2529 *val = v;
2530 }
2531 goto return0;
2532 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002533 case XML_SCHEMAS_INTEGER:
2534 case XML_SCHEMAS_PINTEGER:
2535 case XML_SCHEMAS_NPINTEGER:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002536 case XML_SCHEMAS_NINTEGER:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002537 case XML_SCHEMAS_NNINTEGER:{
2538 const xmlChar *cur = value;
2539 unsigned long lo, mi, hi;
2540 int sign = 0;
2541
2542 if (cur == NULL)
2543 goto return1;
2544 if (*cur == '-') {
2545 sign = 1;
2546 cur++;
2547 } else if (*cur == '+')
2548 cur++;
2549 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2550 if (ret == 0)
2551 goto return1;
2552 if (*cur != 0)
2553 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002554 if (type->builtInType == XML_SCHEMAS_NPINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002555 if ((sign == 0) &&
2556 ((hi != 0) || (mi != 0) || (lo != 0)))
2557 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002558 } else if (type->builtInType == XML_SCHEMAS_PINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002559 if (sign == 1)
2560 goto return1;
2561 if ((hi == 0) && (mi == 0) && (lo == 0))
2562 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002563 } else if (type->builtInType == XML_SCHEMAS_NINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002564 if (sign == 0)
2565 goto return1;
2566 if ((hi == 0) && (mi == 0) && (lo == 0))
2567 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002568 } else if (type->builtInType == XML_SCHEMAS_NNINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002569 if ((sign == 1) &&
2570 ((hi != 0) || (mi != 0) || (lo != 0)))
2571 goto return1;
2572 }
2573 /*
2574 * We can store a value only if no overflow occured
2575 */
2576 if ((ret > 0) && (val != NULL)) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00002577 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002578 if (v != NULL) {
2579 v->value.decimal.lo = lo;
2580 v->value.decimal.mi = lo;
2581 v->value.decimal.hi = lo;
2582 v->value.decimal.sign = sign;
2583 v->value.decimal.frac = 0;
2584 v->value.decimal.total = cur - value;
2585 *val = v;
2586 }
2587 }
2588 goto return0;
2589 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002590 case XML_SCHEMAS_LONG:
2591 case XML_SCHEMAS_BYTE:
2592 case XML_SCHEMAS_SHORT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002593 case XML_SCHEMAS_INT:{
2594 const xmlChar *cur = value;
2595 unsigned long lo, mi, hi;
2596 int total = 0;
2597 int sign = 0;
2598
2599 if (cur == NULL)
2600 goto return1;
2601 if (*cur == '-') {
2602 sign = 1;
2603 cur++;
2604 } else if (*cur == '+')
2605 cur++;
2606 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2607 if (ret <= 0)
2608 goto return1;
2609 if (*cur != 0)
2610 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002611 if (type->builtInType == XML_SCHEMAS_LONG) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002612 if (hi >= 922) {
2613 if (hi > 922)
2614 goto return1;
2615 if (mi >= 33720368) {
2616 if (mi > 33720368)
2617 goto return1;
2618 if ((sign == 0) && (lo > 54775807))
2619 goto return1;
2620 if ((sign == 1) && (lo > 54775808))
2621 goto return1;
2622 }
2623 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002624 } else if (type->builtInType == XML_SCHEMAS_INT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002625 if (hi != 0)
2626 goto return1;
2627 if (mi >= 21) {
2628 if (mi > 21)
2629 goto return1;
2630 if ((sign == 0) && (lo > 47483647))
2631 goto return1;
2632 if ((sign == 1) && (lo > 47483648))
2633 goto return1;
2634 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002635 } else if (type->builtInType == XML_SCHEMAS_SHORT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002636 if ((mi != 0) || (hi != 0))
2637 goto return1;
2638 if ((sign == 1) && (lo > 32768))
2639 goto return1;
2640 if ((sign == 0) && (lo > 32767))
2641 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002642 } else if (type->builtInType == XML_SCHEMAS_BYTE) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002643 if ((mi != 0) || (hi != 0))
2644 goto return1;
2645 if ((sign == 1) && (lo > 128))
2646 goto return1;
2647 if ((sign == 0) && (lo > 127))
2648 goto return1;
2649 }
2650 if (val != NULL) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00002651 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002652 if (v != NULL) {
2653 v->value.decimal.lo = lo;
2654 v->value.decimal.mi = lo;
2655 v->value.decimal.hi = lo;
2656 v->value.decimal.sign = sign;
2657 v->value.decimal.frac = 0;
2658 v->value.decimal.total = total;
2659 *val = v;
2660 }
2661 }
2662 goto return0;
2663 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002664 case XML_SCHEMAS_UINT:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002665 case XML_SCHEMAS_ULONG:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002666 case XML_SCHEMAS_USHORT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002667 case XML_SCHEMAS_UBYTE:{
2668 const xmlChar *cur = value;
2669 unsigned long lo, mi, hi;
2670 int total = 0;
2671
2672 if (cur == NULL)
2673 goto return1;
2674 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2675 if (ret <= 0)
2676 goto return1;
2677 if (*cur != 0)
2678 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002679 if (type->builtInType == XML_SCHEMAS_ULONG) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002680 if (hi >= 1844) {
2681 if (hi > 1844)
2682 goto return1;
2683 if (mi >= 67440737) {
2684 if (mi > 67440737)
2685 goto return1;
2686 if (lo > 9551615)
2687 goto return1;
2688 }
2689 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002690 } else if (type->builtInType == XML_SCHEMAS_UINT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002691 if (hi != 0)
2692 goto return1;
2693 if (mi >= 42) {
2694 if (mi > 42)
2695 goto return1;
2696 if (lo > 94967295)
2697 goto return1;
2698 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002699 } else if (type->builtInType == XML_SCHEMAS_USHORT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002700 if ((mi != 0) || (hi != 0))
2701 goto return1;
2702 if (lo > 65535)
2703 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002704 } else if (type->builtInType == XML_SCHEMAS_UBYTE) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002705 if ((mi != 0) || (hi != 0))
2706 goto return1;
2707 if (lo > 255)
2708 goto return1;
2709 }
2710 if (val != NULL) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00002711 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002712 if (v != NULL) {
2713 v->value.decimal.lo = lo;
2714 v->value.decimal.mi = mi;
2715 v->value.decimal.hi = hi;
2716 v->value.decimal.sign = 0;
2717 v->value.decimal.frac = 0;
2718 v->value.decimal.total = total;
2719 *val = v;
2720 }
2721 }
2722 goto return0;
2723 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002724 }
2725
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002726 done:
2727 if (norm != NULL)
2728 xmlFree(norm);
2729 return (ret);
2730 return3:
2731 if (norm != NULL)
2732 xmlFree(norm);
2733 return (3);
2734 return1:
2735 if (norm != NULL)
2736 xmlFree(norm);
2737 return (1);
2738 return0:
2739 if (norm != NULL)
2740 xmlFree(norm);
2741 return (0);
2742 error:
2743 if (norm != NULL)
2744 xmlFree(norm);
2745 return (-1);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002746}
2747
2748/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002749 * xmlSchemaValPredefTypeNode:
Daniel Veillard4255d502002-04-16 15:50:10 +00002750 * @type: the predefined type
2751 * @value: the value to check
2752 * @val: the return computed value
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002753 * @node: the node containing the value
Daniel Veillard4255d502002-04-16 15:50:10 +00002754 *
2755 * Check that a value conforms to the lexical space of the predefined type.
2756 * if true a value is computed and returned in @val.
2757 *
2758 * Returns 0 if this validates, a positive error code number otherwise
2759 * and -1 in case of internal or API error.
2760 */
2761int
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002762xmlSchemaValPredefTypeNode(xmlSchemaTypePtr type, const xmlChar *value,
2763 xmlSchemaValPtr *val, xmlNodePtr node) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002764 return(xmlSchemaValAtomicType(type, value, val, node, 0));
Daniel Veillard4255d502002-04-16 15:50:10 +00002765}
2766
2767/**
Daniel Veillardc0826a72004-08-10 14:17:33 +00002768 * xmlSchemaValPredefTypeNodeNoNorm:
2769 * @type: the predefined type
2770 * @value: the value to check
2771 * @val: the return computed value
2772 * @node: the node containing the value
2773 *
2774 * Check that a value conforms to the lexical space of the predefined type.
2775 * if true a value is computed and returned in @val.
2776 * This one does apply any normalization to the value.
2777 *
2778 * Returns 0 if this validates, a positive error code number otherwise
2779 * and -1 in case of internal or API error.
2780 */
2781int
2782xmlSchemaValPredefTypeNodeNoNorm(xmlSchemaTypePtr type, const xmlChar *value,
2783 xmlSchemaValPtr *val, xmlNodePtr node) {
2784 return(xmlSchemaValAtomicType(type, value, val, node, 1));
2785}
2786
2787/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002788 * xmlSchemaValidatePredefinedType:
2789 * @type: the predefined type
2790 * @value: the value to check
2791 * @val: the return computed value
2792 *
2793 * Check that a value conforms to the lexical space of the predefined type.
2794 * if true a value is computed and returned in @val.
2795 *
2796 * Returns 0 if this validates, a positive error code number otherwise
2797 * and -1 in case of internal or API error.
2798 */
2799int
2800xmlSchemaValidatePredefinedType(xmlSchemaTypePtr type, const xmlChar *value,
2801 xmlSchemaValPtr *val) {
2802 return(xmlSchemaValPredefTypeNode(type, value, val, NULL));
2803}
2804
2805/**
Daniel Veillard4255d502002-04-16 15:50:10 +00002806 * xmlSchemaCompareDecimals:
2807 * @x: a first decimal value
2808 * @y: a second decimal value
2809 *
2810 * Compare 2 decimals
2811 *
2812 * Returns -1 if x < y, 0 if x == y, 1 if x > y and -2 in case of error
2813 */
2814static int
2815xmlSchemaCompareDecimals(xmlSchemaValPtr x, xmlSchemaValPtr y)
2816{
2817 xmlSchemaValPtr swp;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002818 int order = 1, p;
Daniel Veillard4255d502002-04-16 15:50:10 +00002819 unsigned long tmp;
2820
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002821 if ((x->value.decimal.sign) &&
2822 ((x->value.decimal.lo != 0) ||
2823 (x->value.decimal.mi != 0) ||
2824 (x->value.decimal.hi != 0))) {
2825 if ((y->value.decimal.sign) &&
2826 ((y->value.decimal.lo != 0) ||
2827 (y->value.decimal.mi != 0) ||
2828 (y->value.decimal.hi != 0)))
Daniel Veillard80b19092003-03-28 13:29:53 +00002829 order = -1;
2830 else
2831 return (-1);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002832 } else if ((y->value.decimal.sign) &&
2833 ((y->value.decimal.lo != 0) ||
2834 (y->value.decimal.mi != 0) ||
2835 (y->value.decimal.hi != 0))) {
Daniel Veillard4255d502002-04-16 15:50:10 +00002836 return (1);
Daniel Veillard80b19092003-03-28 13:29:53 +00002837 }
Daniel Veillard4255d502002-04-16 15:50:10 +00002838 if (x->value.decimal.frac == y->value.decimal.frac) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002839 if (x->value.decimal.hi < y->value.decimal.hi)
2840 return (-order);
Daniel Veillard01fa6152004-06-29 17:04:39 +00002841 if (x->value.decimal.hi > y->value.decimal.hi)
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002842 return (order);
2843 if (x->value.decimal.mi < y->value.decimal.mi)
2844 return (-order);
Daniel Veillard01fa6152004-06-29 17:04:39 +00002845 if (x->value.decimal.mi > y->value.decimal.mi)
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002846 return (order);
2847 if (x->value.decimal.lo < y->value.decimal.lo)
Daniel Veillard80b19092003-03-28 13:29:53 +00002848 return (-order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002849 if (x->value.decimal.lo > y->value.decimal.lo)
Daniel Veillard80b19092003-03-28 13:29:53 +00002850 return(order);
2851 return(0);
Daniel Veillard4255d502002-04-16 15:50:10 +00002852 }
2853 if (y->value.decimal.frac > x->value.decimal.frac) {
2854 swp = y;
2855 y = x;
2856 x = swp;
2857 order = -order;
2858 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002859 p = powten[x->value.decimal.frac - y->value.decimal.frac];
2860 tmp = x->value.decimal.lo / p;
2861 if (tmp > y->value.decimal.lo)
Daniel Veillard4255d502002-04-16 15:50:10 +00002862 return (order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002863 if (tmp < y->value.decimal.lo)
Daniel Veillard4255d502002-04-16 15:50:10 +00002864 return (-order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002865 tmp = y->value.decimal.lo * p;
2866 if (x->value.decimal.lo < tmp)
Daniel Veillard4255d502002-04-16 15:50:10 +00002867 return (-order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002868 if (x->value.decimal.lo == tmp)
Daniel Veillard4255d502002-04-16 15:50:10 +00002869 return (0);
2870 return (order);
2871}
2872
2873/**
Daniel Veillard070803b2002-05-03 07:29:38 +00002874 * xmlSchemaCompareDurations:
2875 * @x: a first duration value
2876 * @y: a second duration value
2877 *
2878 * Compare 2 durations
2879 *
2880 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
2881 * case of error
2882 */
2883static int
2884xmlSchemaCompareDurations(xmlSchemaValPtr x, xmlSchemaValPtr y)
2885{
2886 long carry, mon, day;
2887 double sec;
Daniel Veillard80b19092003-03-28 13:29:53 +00002888 int invert = 1;
2889 long xmon, xday, myear, minday, maxday;
Daniel Veillard070803b2002-05-03 07:29:38 +00002890 static const long dayRange [2][12] = {
2891 { 0, 28, 59, 89, 120, 150, 181, 212, 242, 273, 303, 334, },
2892 { 0, 31, 62, 92, 123, 153, 184, 215, 245, 276, 306, 337} };
2893
2894 if ((x == NULL) || (y == NULL))
Daniel Veillard5a872412002-05-22 06:40:27 +00002895 return -2;
Daniel Veillard070803b2002-05-03 07:29:38 +00002896
2897 /* months */
2898 mon = x->value.dur.mon - y->value.dur.mon;
2899
2900 /* seconds */
2901 sec = x->value.dur.sec - y->value.dur.sec;
2902 carry = (long)sec / SECS_PER_DAY;
2903 sec -= (double)(carry * SECS_PER_DAY);
2904
2905 /* days */
2906 day = x->value.dur.day - y->value.dur.day + carry;
2907
2908 /* easy test */
2909 if (mon == 0) {
2910 if (day == 0)
2911 if (sec == 0.0)
2912 return 0;
2913 else if (sec < 0.0)
2914 return -1;
2915 else
2916 return 1;
2917 else if (day < 0)
2918 return -1;
2919 else
2920 return 1;
2921 }
2922
2923 if (mon > 0) {
2924 if ((day >= 0) && (sec >= 0.0))
2925 return 1;
2926 else {
2927 xmon = mon;
2928 xday = -day;
2929 }
2930 } else if ((day <= 0) && (sec <= 0.0)) {
2931 return -1;
2932 } else {
Daniel Veillard80b19092003-03-28 13:29:53 +00002933 invert = -1;
Daniel Veillard070803b2002-05-03 07:29:38 +00002934 xmon = -mon;
2935 xday = day;
2936 }
2937
2938 myear = xmon / 12;
Daniel Veillard80b19092003-03-28 13:29:53 +00002939 if (myear == 0) {
2940 minday = 0;
2941 maxday = 0;
2942 } else {
2943 maxday = 366 * ((myear + 3) / 4) +
2944 365 * ((myear - 1) % 4);
2945 minday = maxday - 1;
2946 }
2947
Daniel Veillard070803b2002-05-03 07:29:38 +00002948 xmon = xmon % 12;
2949 minday += dayRange[0][xmon];
2950 maxday += dayRange[1][xmon];
2951
Daniel Veillard80b19092003-03-28 13:29:53 +00002952 if ((maxday == minday) && (maxday == xday))
2953 return(0); /* can this really happen ? */
Daniel Veillard070803b2002-05-03 07:29:38 +00002954 if (maxday < xday)
Daniel Veillard80b19092003-03-28 13:29:53 +00002955 return(-invert);
2956 if (minday > xday)
2957 return(invert);
Daniel Veillard070803b2002-05-03 07:29:38 +00002958
2959 /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00002960 return 2;
2961}
2962
2963/*
2964 * macros for adding date/times and durations
2965 */
2966#define FQUOTIENT(a,b) (floor(((double)a/(double)b)))
2967#define MODULO(a,b) (a - FQUOTIENT(a,b) * b)
2968#define FQUOTIENT_RANGE(a,low,high) (FQUOTIENT((a-low),(high-low)))
2969#define MODULO_RANGE(a,low,high) ((MODULO((a-low),(high-low)))+low)
2970
2971/**
Daniel Veillard669adfc2004-05-29 20:12:46 +00002972 * xmlSchemaDupVal:
2973 * @v: the #xmlSchemaValPtr value to duplicate
2974 *
2975 * Makes a copy of @v. The calling program is responsible for freeing
2976 * the returned value.
2977 *
2978 * returns a pointer to a duplicated #xmlSchemaValPtr or NULL if error.
2979 */
2980static xmlSchemaValPtr
2981xmlSchemaDupVal (xmlSchemaValPtr v)
2982{
2983 xmlSchemaValPtr ret = xmlSchemaNewValue(v->type);
2984 if (ret == NULL)
2985 return NULL;
2986
2987 memcpy(ret, v, sizeof(xmlSchemaVal));
2988 return ret;
2989}
2990
2991/**
Daniel Veillard5a872412002-05-22 06:40:27 +00002992 * _xmlSchemaDateAdd:
2993 * @dt: an #xmlSchemaValPtr
2994 * @dur: an #xmlSchemaValPtr of type #XS_DURATION
2995 *
2996 * Compute a new date/time from @dt and @dur. This function assumes @dt
2997 * is either #XML_SCHEMAS_DATETIME, #XML_SCHEMAS_DATE, #XML_SCHEMAS_GYEARMONTH,
Daniel Veillard669adfc2004-05-29 20:12:46 +00002998 * or #XML_SCHEMAS_GYEAR. The returned #xmlSchemaVal is the same type as
2999 * @dt. The calling program is responsible for freeing the returned value.
Daniel Veillard5a872412002-05-22 06:40:27 +00003000 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00003001 * Returns a pointer to a new #xmlSchemaVal or NULL if error.
Daniel Veillard5a872412002-05-22 06:40:27 +00003002 */
3003static xmlSchemaValPtr
3004_xmlSchemaDateAdd (xmlSchemaValPtr dt, xmlSchemaValPtr dur)
3005{
Daniel Veillard669adfc2004-05-29 20:12:46 +00003006 xmlSchemaValPtr ret, tmp;
Daniel Veillard5a872412002-05-22 06:40:27 +00003007 long carry, tempdays, temp;
3008 xmlSchemaValDatePtr r, d;
3009 xmlSchemaValDurationPtr u;
3010
3011 if ((dt == NULL) || (dur == NULL))
3012 return NULL;
3013
3014 ret = xmlSchemaNewValue(dt->type);
3015 if (ret == NULL)
3016 return NULL;
3017
Daniel Veillard669adfc2004-05-29 20:12:46 +00003018 /* make a copy so we don't alter the original value */
3019 tmp = xmlSchemaDupVal(dt);
3020 if (tmp == NULL) {
3021 xmlSchemaFreeValue(ret);
3022 return NULL;
3023 }
3024
Daniel Veillard5a872412002-05-22 06:40:27 +00003025 r = &(ret->value.date);
Daniel Veillard669adfc2004-05-29 20:12:46 +00003026 d = &(tmp->value.date);
Daniel Veillard5a872412002-05-22 06:40:27 +00003027 u = &(dur->value.dur);
3028
3029 /* normalization */
3030 if (d->mon == 0)
3031 d->mon = 1;
3032
3033 /* normalize for time zone offset */
3034 u->sec -= (d->tzo * 60);
3035 d->tzo = 0;
3036
3037 /* normalization */
3038 if (d->day == 0)
3039 d->day = 1;
3040
3041 /* month */
3042 carry = d->mon + u->mon;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003043 r->mon = (unsigned int) MODULO_RANGE(carry, 1, 13);
3044 carry = (long) FQUOTIENT_RANGE(carry, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00003045
3046 /* year (may be modified later) */
3047 r->year = d->year + carry;
3048 if (r->year == 0) {
3049 if (d->year > 0)
3050 r->year--;
3051 else
3052 r->year++;
3053 }
3054
3055 /* time zone */
3056 r->tzo = d->tzo;
3057 r->tz_flag = d->tz_flag;
3058
3059 /* seconds */
3060 r->sec = d->sec + u->sec;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003061 carry = (long) FQUOTIENT((long)r->sec, 60);
Daniel Veillard5a872412002-05-22 06:40:27 +00003062 if (r->sec != 0.0) {
3063 r->sec = MODULO(r->sec, 60.0);
3064 }
3065
3066 /* minute */
3067 carry += d->min;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003068 r->min = (unsigned int) MODULO(carry, 60);
3069 carry = (long) FQUOTIENT(carry, 60);
Daniel Veillard5a872412002-05-22 06:40:27 +00003070
3071 /* hours */
3072 carry += d->hour;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003073 r->hour = (unsigned int) MODULO(carry, 24);
3074 carry = (long)FQUOTIENT(carry, 24);
Daniel Veillard5a872412002-05-22 06:40:27 +00003075
3076 /*
3077 * days
3078 * Note we use tempdays because the temporary values may need more
3079 * than 5 bits
3080 */
3081 if ((VALID_YEAR(r->year)) && (VALID_MONTH(r->mon)) &&
3082 (d->day > MAX_DAYINMONTH(r->year, r->mon)))
3083 tempdays = MAX_DAYINMONTH(r->year, r->mon);
3084 else if (d->day < 1)
3085 tempdays = 1;
3086 else
3087 tempdays = d->day;
3088
3089 tempdays += u->day + carry;
3090
3091 while (1) {
3092 if (tempdays < 1) {
Daniel Veillardebe25d42004-03-25 09:35:49 +00003093 long tmon = (long) MODULO_RANGE(r->mon-1, 1, 13);
3094 long tyr = r->year + (long)FQUOTIENT_RANGE(r->mon-1, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00003095 if (tyr == 0)
3096 tyr--;
3097 tempdays += MAX_DAYINMONTH(tyr, tmon);
3098 carry = -1;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003099 } else if (tempdays > (long) MAX_DAYINMONTH(r->year, r->mon)) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003100 tempdays = tempdays - MAX_DAYINMONTH(r->year, r->mon);
3101 carry = 1;
3102 } else
3103 break;
3104
3105 temp = r->mon + carry;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003106 r->mon = (unsigned int) MODULO_RANGE(temp, 1, 13);
3107 r->year = r->year + (unsigned int) FQUOTIENT_RANGE(temp, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00003108 if (r->year == 0) {
3109 if (temp < 1)
3110 r->year--;
3111 else
3112 r->year++;
3113 }
3114 }
3115
3116 r->day = tempdays;
3117
3118 /*
3119 * adjust the date/time type to the date values
3120 */
3121 if (ret->type != XML_SCHEMAS_DATETIME) {
3122 if ((r->hour) || (r->min) || (r->sec))
3123 ret->type = XML_SCHEMAS_DATETIME;
3124 else if (ret->type != XML_SCHEMAS_DATE) {
3125 if ((r->mon != 1) && (r->day != 1))
3126 ret->type = XML_SCHEMAS_DATE;
3127 else if ((ret->type != XML_SCHEMAS_GYEARMONTH) && (r->mon != 1))
3128 ret->type = XML_SCHEMAS_GYEARMONTH;
3129 }
3130 }
3131
Daniel Veillard669adfc2004-05-29 20:12:46 +00003132 xmlSchemaFreeValue(tmp);
Daniel Veillard5a872412002-05-22 06:40:27 +00003133
Daniel Veillard5a872412002-05-22 06:40:27 +00003134 return ret;
3135}
3136
3137/**
3138 * xmlSchemaDateNormalize:
Daniel Veillard669adfc2004-05-29 20:12:46 +00003139 * @dt: an #xmlSchemaValPtr of a date/time type value.
3140 * @offset: number of seconds to adjust @dt by.
Daniel Veillard5a872412002-05-22 06:40:27 +00003141 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00003142 * Normalize @dt to GMT time. The @offset parameter is subtracted from
3143 * the return value is a time-zone offset is present on @dt.
Daniel Veillard5a872412002-05-22 06:40:27 +00003144 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00003145 * Returns a normalized copy of @dt or NULL if error.
Daniel Veillard5a872412002-05-22 06:40:27 +00003146 */
3147static xmlSchemaValPtr
3148xmlSchemaDateNormalize (xmlSchemaValPtr dt, double offset)
3149{
3150 xmlSchemaValPtr dur, ret;
3151
3152 if (dt == NULL)
3153 return NULL;
3154
3155 if (((dt->type != XML_SCHEMAS_TIME) &&
3156 (dt->type != XML_SCHEMAS_DATETIME)) || (dt->value.date.tzo == 0))
3157 return xmlSchemaDupVal(dt);
3158
3159 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
3160 if (dur == NULL)
3161 return NULL;
3162
3163 dur->value.date.sec -= offset;
3164
3165 ret = _xmlSchemaDateAdd(dt, dur);
3166 if (ret == NULL)
3167 return NULL;
3168
3169 xmlSchemaFreeValue(dur);
3170
3171 /* ret->value.date.tzo = 0; */
3172 return ret;
3173}
3174
3175/**
3176 * _xmlSchemaDateCastYMToDays:
3177 * @dt: an #xmlSchemaValPtr
3178 *
3179 * Convert mon and year of @dt to total number of days. Take the
3180 * number of years since (or before) 1 AD and add the number of leap
3181 * years. This is a function because negative
3182 * years must be handled a little differently and there is no zero year.
3183 *
3184 * Returns number of days.
3185 */
3186static long
3187_xmlSchemaDateCastYMToDays (const xmlSchemaValPtr dt)
3188{
3189 long ret;
Daniel Veillard49e89632004-09-23 16:24:36 +00003190 int mon;
Daniel Veillard5a872412002-05-22 06:40:27 +00003191
Daniel Veillard49e89632004-09-23 16:24:36 +00003192 mon = dt->value.date.mon;
3193 if (mon <= 0) mon = 1; /* normalization */
3194
3195 if (dt->value.date.year <= 0)
Daniel Veillard5a872412002-05-22 06:40:27 +00003196 ret = (dt->value.date.year * 365) +
3197 (((dt->value.date.year+1)/4)-((dt->value.date.year+1)/100)+
3198 ((dt->value.date.year+1)/400)) +
Daniel Veillard49e89632004-09-23 16:24:36 +00003199 DAY_IN_YEAR(0, mon, dt->value.date.year);
Daniel Veillard5a872412002-05-22 06:40:27 +00003200 else
3201 ret = ((dt->value.date.year-1) * 365) +
3202 (((dt->value.date.year-1)/4)-((dt->value.date.year-1)/100)+
3203 ((dt->value.date.year-1)/400)) +
Daniel Veillard49e89632004-09-23 16:24:36 +00003204 DAY_IN_YEAR(0, mon, dt->value.date.year);
Daniel Veillard5a872412002-05-22 06:40:27 +00003205
3206 return ret;
3207}
3208
3209/**
3210 * TIME_TO_NUMBER:
3211 * @dt: an #xmlSchemaValPtr
3212 *
3213 * Calculates the number of seconds in the time portion of @dt.
3214 *
3215 * Returns seconds.
3216 */
3217#define TIME_TO_NUMBER(dt) \
3218 ((double)((dt->value.date.hour * SECS_PER_HOUR) + \
Daniel Veillardb3721c22003-03-31 11:22:25 +00003219 (dt->value.date.min * SECS_PER_MIN) + \
3220 (dt->value.date.tzo * SECS_PER_MIN)) + \
3221 dt->value.date.sec)
Daniel Veillard5a872412002-05-22 06:40:27 +00003222
3223/**
3224 * xmlSchemaCompareDates:
3225 * @x: a first date/time value
3226 * @y: a second date/time value
3227 *
3228 * Compare 2 date/times
3229 *
3230 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3231 * case of error
3232 */
3233static int
3234xmlSchemaCompareDates (xmlSchemaValPtr x, xmlSchemaValPtr y)
3235{
3236 unsigned char xmask, ymask, xor_mask, and_mask;
3237 xmlSchemaValPtr p1, p2, q1, q2;
3238 long p1d, p2d, q1d, q2d;
3239
3240 if ((x == NULL) || (y == NULL))
3241 return -2;
3242
3243 if (x->value.date.tz_flag) {
3244
3245 if (!y->value.date.tz_flag) {
3246 p1 = xmlSchemaDateNormalize(x, 0);
3247 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3248 /* normalize y + 14:00 */
3249 q1 = xmlSchemaDateNormalize(y, (14 * SECS_PER_HOUR));
3250
3251 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003252 if (p1d < q1d) {
3253 xmlSchemaFreeValue(p1);
3254 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003255 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003256 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003257 double sec;
3258
3259 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00003260 if (sec < 0.0) {
3261 xmlSchemaFreeValue(p1);
3262 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003263 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003264 } else {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003265 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003266 /* normalize y - 14:00 */
3267 q2 = xmlSchemaDateNormalize(y, -(14 * SECS_PER_HOUR));
3268 q2d = _xmlSchemaDateCastYMToDays(q2) + q2->value.date.day;
3269 if (p1d > q2d)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003270 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003271 else if (p1d == q2d) {
3272 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q2);
3273 if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003274 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003275 else
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003276 ret = 2; /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00003277 }
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003278 xmlSchemaFreeValue(p1);
3279 xmlSchemaFreeValue(q1);
3280 xmlSchemaFreeValue(q2);
3281 if (ret != 0)
3282 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003283 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00003284 } else {
3285 xmlSchemaFreeValue(p1);
3286 xmlSchemaFreeValue(q1);
3287 }
Daniel Veillard5a872412002-05-22 06:40:27 +00003288 }
3289 } else if (y->value.date.tz_flag) {
3290 q1 = xmlSchemaDateNormalize(y, 0);
3291 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
3292
3293 /* normalize x - 14:00 */
3294 p1 = xmlSchemaDateNormalize(x, -(14 * SECS_PER_HOUR));
3295 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3296
Daniel Veillardfdc91562002-07-01 21:52:03 +00003297 if (p1d < q1d) {
3298 xmlSchemaFreeValue(p1);
3299 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003300 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003301 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003302 double sec;
3303
3304 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00003305 if (sec < 0.0) {
3306 xmlSchemaFreeValue(p1);
3307 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003308 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003309 } else {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003310 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003311 /* normalize x + 14:00 */
3312 p2 = xmlSchemaDateNormalize(x, (14 * SECS_PER_HOUR));
3313 p2d = _xmlSchemaDateCastYMToDays(p2) + p2->value.date.day;
3314
Daniel Veillard6560a422003-03-27 21:25:38 +00003315 if (p2d > q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003316 ret = 1;
Daniel Veillard6560a422003-03-27 21:25:38 +00003317 } else if (p2d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003318 sec = TIME_TO_NUMBER(p2) - TIME_TO_NUMBER(q1);
3319 if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003320 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003321 else
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003322 ret = 2; /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00003323 }
Daniel Veillard6560a422003-03-27 21:25:38 +00003324 xmlSchemaFreeValue(p1);
3325 xmlSchemaFreeValue(q1);
3326 xmlSchemaFreeValue(p2);
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003327 if (ret != 0)
3328 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003329 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00003330 } else {
3331 xmlSchemaFreeValue(p1);
3332 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003333 }
3334 }
3335
3336 /*
3337 * if the same type then calculate the difference
3338 */
3339 if (x->type == y->type) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003340 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003341 q1 = xmlSchemaDateNormalize(y, 0);
3342 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
3343
3344 p1 = xmlSchemaDateNormalize(x, 0);
3345 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3346
Daniel Veillardfdc91562002-07-01 21:52:03 +00003347 if (p1d < q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003348 ret = -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003349 } else if (p1d > q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003350 ret = 1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003351 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00003352 double sec;
3353
3354 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
3355 if (sec < 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003356 ret = -1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003357 else if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003358 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003359
3360 }
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003361 xmlSchemaFreeValue(p1);
3362 xmlSchemaFreeValue(q1);
3363 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003364 }
3365
3366 switch (x->type) {
3367 case XML_SCHEMAS_DATETIME:
3368 xmask = 0xf;
3369 break;
3370 case XML_SCHEMAS_DATE:
3371 xmask = 0x7;
3372 break;
3373 case XML_SCHEMAS_GYEAR:
3374 xmask = 0x1;
3375 break;
3376 case XML_SCHEMAS_GMONTH:
3377 xmask = 0x2;
3378 break;
3379 case XML_SCHEMAS_GDAY:
3380 xmask = 0x3;
3381 break;
3382 case XML_SCHEMAS_GYEARMONTH:
3383 xmask = 0x3;
3384 break;
3385 case XML_SCHEMAS_GMONTHDAY:
3386 xmask = 0x6;
3387 break;
3388 case XML_SCHEMAS_TIME:
3389 xmask = 0x8;
3390 break;
3391 default:
3392 xmask = 0;
3393 break;
3394 }
3395
3396 switch (y->type) {
3397 case XML_SCHEMAS_DATETIME:
3398 ymask = 0xf;
3399 break;
3400 case XML_SCHEMAS_DATE:
3401 ymask = 0x7;
3402 break;
3403 case XML_SCHEMAS_GYEAR:
3404 ymask = 0x1;
3405 break;
3406 case XML_SCHEMAS_GMONTH:
3407 ymask = 0x2;
3408 break;
3409 case XML_SCHEMAS_GDAY:
3410 ymask = 0x3;
3411 break;
3412 case XML_SCHEMAS_GYEARMONTH:
3413 ymask = 0x3;
3414 break;
3415 case XML_SCHEMAS_GMONTHDAY:
3416 ymask = 0x6;
3417 break;
3418 case XML_SCHEMAS_TIME:
3419 ymask = 0x8;
3420 break;
3421 default:
3422 ymask = 0;
3423 break;
3424 }
3425
3426 xor_mask = xmask ^ ymask; /* mark type differences */
3427 and_mask = xmask & ymask; /* mark field specification */
3428
3429 /* year */
3430 if (xor_mask & 1)
3431 return 2; /* indeterminate */
3432 else if (and_mask & 1) {
3433 if (x->value.date.year < y->value.date.year)
3434 return -1;
3435 else if (x->value.date.year > y->value.date.year)
3436 return 1;
3437 }
3438
3439 /* month */
3440 if (xor_mask & 2)
3441 return 2; /* indeterminate */
3442 else if (and_mask & 2) {
3443 if (x->value.date.mon < y->value.date.mon)
3444 return -1;
3445 else if (x->value.date.mon > y->value.date.mon)
3446 return 1;
3447 }
3448
3449 /* day */
3450 if (xor_mask & 4)
3451 return 2; /* indeterminate */
3452 else if (and_mask & 4) {
3453 if (x->value.date.day < y->value.date.day)
3454 return -1;
3455 else if (x->value.date.day > y->value.date.day)
3456 return 1;
3457 }
3458
3459 /* time */
3460 if (xor_mask & 8)
3461 return 2; /* indeterminate */
3462 else if (and_mask & 8) {
3463 if (x->value.date.hour < y->value.date.hour)
3464 return -1;
3465 else if (x->value.date.hour > y->value.date.hour)
3466 return 1;
3467 else if (x->value.date.min < y->value.date.min)
3468 return -1;
3469 else if (x->value.date.min > y->value.date.min)
3470 return 1;
3471 else if (x->value.date.sec < y->value.date.sec)
3472 return -1;
3473 else if (x->value.date.sec > y->value.date.sec)
3474 return 1;
3475 }
3476
Daniel Veillard070803b2002-05-03 07:29:38 +00003477 return 0;
3478}
3479
3480/**
Daniel Veillardc4c21552003-03-29 10:53:38 +00003481 * xmlSchemaCompareNormStrings:
3482 * @x: a first string value
3483 * @y: a second string value
3484 *
3485 * Compare 2 string for their normalized values.
3486 *
3487 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
3488 * case of error
3489 */
3490static int
3491xmlSchemaCompareNormStrings(xmlSchemaValPtr x, xmlSchemaValPtr y) {
3492 const xmlChar *utf1;
3493 const xmlChar *utf2;
3494 int tmp;
3495
3496 if ((x == NULL) || (y == NULL))
3497 return(-2);
3498 utf1 = x->value.str;
3499 utf2 = y->value.str;
3500
William M. Brack76e95df2003-10-18 16:20:14 +00003501 while (IS_BLANK_CH(*utf1)) utf1++;
3502 while (IS_BLANK_CH(*utf2)) utf2++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003503 while ((*utf1 != 0) && (*utf2 != 0)) {
William M. Brack76e95df2003-10-18 16:20:14 +00003504 if (IS_BLANK_CH(*utf1)) {
3505 if (!IS_BLANK_CH(*utf2)) {
Daniel Veillardc4c21552003-03-29 10:53:38 +00003506 tmp = *utf1 - *utf2;
3507 return(tmp);
3508 }
William M. Brack76e95df2003-10-18 16:20:14 +00003509 while (IS_BLANK_CH(*utf1)) utf1++;
3510 while (IS_BLANK_CH(*utf2)) utf2++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003511 } else {
3512 tmp = *utf1++ - *utf2++;
3513 if (tmp < 0)
3514 return(-1);
3515 if (tmp > 0)
3516 return(1);
3517 }
3518 }
3519 if (*utf1 != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00003520 while (IS_BLANK_CH(*utf1)) utf1++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003521 if (*utf1 != 0)
3522 return(1);
3523 }
3524 if (*utf2 != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00003525 while (IS_BLANK_CH(*utf2)) utf2++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003526 if (*utf2 != 0)
3527 return(-1);
3528 }
3529 return(0);
3530}
3531
3532/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003533 * xmlSchemaCompareFloats:
3534 * @x: a first float or double value
3535 * @y: a second float or double value
3536 *
3537 * Compare 2 values
3538 *
3539 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3540 * case of error
3541 */
3542static int
3543xmlSchemaCompareFloats(xmlSchemaValPtr x, xmlSchemaValPtr y) {
3544 double d1, d2;
3545
3546 if ((x == NULL) || (y == NULL))
3547 return(-2);
3548
3549 /*
3550 * Cast everything to doubles.
3551 */
3552 if (x->type == XML_SCHEMAS_DOUBLE)
3553 d1 = x->value.d;
3554 else if (x->type == XML_SCHEMAS_FLOAT)
3555 d1 = x->value.f;
3556 else
3557 return(-2);
3558
3559 if (y->type == XML_SCHEMAS_DOUBLE)
3560 d2 = y->value.d;
3561 else if (y->type == XML_SCHEMAS_FLOAT)
3562 d2 = y->value.f;
3563 else
3564 return(-2);
3565
3566 /*
3567 * Check for special cases.
3568 */
3569 if (xmlXPathIsNaN(d1)) {
3570 if (xmlXPathIsNaN(d2))
3571 return(0);
3572 return(1);
3573 }
3574 if (xmlXPathIsNaN(d2))
3575 return(-1);
3576 if (d1 == xmlXPathPINF) {
3577 if (d2 == xmlXPathPINF)
3578 return(0);
3579 return(1);
3580 }
3581 if (d2 == xmlXPathPINF)
3582 return(-1);
3583 if (d1 == xmlXPathNINF) {
3584 if (d2 == xmlXPathNINF)
3585 return(0);
3586 return(-1);
3587 }
3588 if (d2 == xmlXPathNINF)
3589 return(1);
3590
3591 /*
3592 * basic tests, the last one we should have equality, but
3593 * portability is more important than speed and handling
3594 * NaN or Inf in a portable way is always a challenge, so ...
3595 */
3596 if (d1 < d2)
3597 return(-1);
3598 if (d1 > d2)
3599 return(1);
3600 if (d1 == d2)
3601 return(0);
3602 return(2);
3603}
3604
3605/**
Daniel Veillard4255d502002-04-16 15:50:10 +00003606 * xmlSchemaCompareValues:
3607 * @x: a first value
3608 * @y: a second value
3609 *
3610 * Compare 2 values
3611 *
Daniel Veillard5a872412002-05-22 06:40:27 +00003612 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3613 * case of error
Daniel Veillard4255d502002-04-16 15:50:10 +00003614 */
Daniel Veillard80b19092003-03-28 13:29:53 +00003615int
Daniel Veillard4255d502002-04-16 15:50:10 +00003616xmlSchemaCompareValues(xmlSchemaValPtr x, xmlSchemaValPtr y) {
3617 if ((x == NULL) || (y == NULL))
3618 return(-2);
3619
3620 switch (x->type) {
Daniel Veillard80b19092003-03-28 13:29:53 +00003621 case XML_SCHEMAS_UNKNOWN:
William M. Brack2f2a6632004-08-20 23:09:47 +00003622 case XML_SCHEMAS_ANYTYPE:
3623 case XML_SCHEMAS_ANYSIMPLETYPE:
Daniel Veillard80b19092003-03-28 13:29:53 +00003624 return(-2);
3625 case XML_SCHEMAS_INTEGER:
3626 case XML_SCHEMAS_NPINTEGER:
3627 case XML_SCHEMAS_NINTEGER:
3628 case XML_SCHEMAS_NNINTEGER:
3629 case XML_SCHEMAS_PINTEGER:
3630 case XML_SCHEMAS_INT:
3631 case XML_SCHEMAS_UINT:
3632 case XML_SCHEMAS_LONG:
3633 case XML_SCHEMAS_ULONG:
3634 case XML_SCHEMAS_SHORT:
3635 case XML_SCHEMAS_USHORT:
3636 case XML_SCHEMAS_BYTE:
3637 case XML_SCHEMAS_UBYTE:
Daniel Veillard4255d502002-04-16 15:50:10 +00003638 case XML_SCHEMAS_DECIMAL:
Daniel Veillard80b19092003-03-28 13:29:53 +00003639 if (y->type == x->type)
3640 return(xmlSchemaCompareDecimals(x, y));
3641 if ((y->type == XML_SCHEMAS_DECIMAL) ||
3642 (y->type == XML_SCHEMAS_INTEGER) ||
3643 (y->type == XML_SCHEMAS_NPINTEGER) ||
3644 (y->type == XML_SCHEMAS_NINTEGER) ||
3645 (y->type == XML_SCHEMAS_NNINTEGER) ||
3646 (y->type == XML_SCHEMAS_PINTEGER) ||
3647 (y->type == XML_SCHEMAS_INT) ||
3648 (y->type == XML_SCHEMAS_UINT) ||
3649 (y->type == XML_SCHEMAS_LONG) ||
3650 (y->type == XML_SCHEMAS_ULONG) ||
3651 (y->type == XML_SCHEMAS_SHORT) ||
3652 (y->type == XML_SCHEMAS_USHORT) ||
3653 (y->type == XML_SCHEMAS_BYTE) ||
3654 (y->type == XML_SCHEMAS_UBYTE))
Daniel Veillard4255d502002-04-16 15:50:10 +00003655 return(xmlSchemaCompareDecimals(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00003656 return(-2);
Daniel Veillard070803b2002-05-03 07:29:38 +00003657 case XML_SCHEMAS_DURATION:
3658 if (y->type == XML_SCHEMAS_DURATION)
3659 return(xmlSchemaCompareDurations(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00003660 return(-2);
3661 case XML_SCHEMAS_TIME:
3662 case XML_SCHEMAS_GDAY:
3663 case XML_SCHEMAS_GMONTH:
3664 case XML_SCHEMAS_GMONTHDAY:
3665 case XML_SCHEMAS_GYEAR:
3666 case XML_SCHEMAS_GYEARMONTH:
3667 case XML_SCHEMAS_DATE:
3668 case XML_SCHEMAS_DATETIME:
3669 if ((y->type == XML_SCHEMAS_DATETIME) ||
3670 (y->type == XML_SCHEMAS_TIME) ||
3671 (y->type == XML_SCHEMAS_GDAY) ||
3672 (y->type == XML_SCHEMAS_GMONTH) ||
3673 (y->type == XML_SCHEMAS_GMONTHDAY) ||
3674 (y->type == XML_SCHEMAS_GYEAR) ||
3675 (y->type == XML_SCHEMAS_DATE) ||
3676 (y->type == XML_SCHEMAS_GYEARMONTH))
3677 return (xmlSchemaCompareDates(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00003678 return (-2);
Daniel Veillard80b19092003-03-28 13:29:53 +00003679 case XML_SCHEMAS_NORMSTRING:
Daniel Veillard80b19092003-03-28 13:29:53 +00003680 case XML_SCHEMAS_TOKEN:
3681 case XML_SCHEMAS_LANGUAGE:
3682 case XML_SCHEMAS_NMTOKEN:
Daniel Veillard80b19092003-03-28 13:29:53 +00003683 case XML_SCHEMAS_NAME:
Daniel Veillard80b19092003-03-28 13:29:53 +00003684 case XML_SCHEMAS_NCNAME:
3685 case XML_SCHEMAS_ID:
3686 case XML_SCHEMAS_IDREF:
Daniel Veillard80b19092003-03-28 13:29:53 +00003687 case XML_SCHEMAS_ENTITY:
Daniel Veillard80b19092003-03-28 13:29:53 +00003688 case XML_SCHEMAS_NOTATION:
3689 case XML_SCHEMAS_ANYURI:
Daniel Veillardc4c21552003-03-29 10:53:38 +00003690 if ((y->type == XML_SCHEMAS_NORMSTRING) ||
3691 (y->type == XML_SCHEMAS_TOKEN) ||
3692 (y->type == XML_SCHEMAS_LANGUAGE) ||
3693 (y->type == XML_SCHEMAS_NMTOKEN) ||
3694 (y->type == XML_SCHEMAS_NAME) ||
3695 (y->type == XML_SCHEMAS_QNAME) ||
3696 (y->type == XML_SCHEMAS_NCNAME) ||
3697 (y->type == XML_SCHEMAS_ID) ||
3698 (y->type == XML_SCHEMAS_IDREF) ||
3699 (y->type == XML_SCHEMAS_ENTITY) ||
3700 (y->type == XML_SCHEMAS_NOTATION) ||
3701 (y->type == XML_SCHEMAS_ANYURI))
3702 return (xmlSchemaCompareNormStrings(x, y));
3703 return (-2);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003704 case XML_SCHEMAS_QNAME:
3705 if (y->type == XML_SCHEMAS_QNAME) {
3706 if ((xmlStrEqual(x->value.qname.name, y->value.qname.name)) &&
3707 (xmlStrEqual(x->value.qname.uri, y->value.qname.uri)))
3708 return(0);
3709 return(2);
3710 }
3711 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00003712 case XML_SCHEMAS_FLOAT:
3713 case XML_SCHEMAS_DOUBLE:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003714 if ((y->type == XML_SCHEMAS_FLOAT) ||
3715 (y->type == XML_SCHEMAS_DOUBLE))
3716 return (xmlSchemaCompareFloats(x, y));
3717 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00003718 case XML_SCHEMAS_BOOLEAN:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003719 if (y->type == XML_SCHEMAS_BOOLEAN) {
3720 if (x->value.b == y->value.b)
3721 return(0);
3722 if (x->value.b == 0)
3723 return(-1);
3724 return(1);
3725 }
3726 return (-2);
Daniel Veillard560c2a42003-07-06 21:13:49 +00003727 case XML_SCHEMAS_HEXBINARY:
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00003728 if (y->type == XML_SCHEMAS_HEXBINARY) {
3729 if (x->value.hex.total == y->value.hex.total) {
3730 int ret = xmlStrcmp(x->value.hex.str, y->value.hex.str);
3731 if (ret > 0)
3732 return(1);
3733 else if (ret == 0)
3734 return(0);
3735 }
3736 else if (x->value.hex.total > y->value.hex.total)
3737 return(1);
3738
3739 return(-1);
3740 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00003741 return (-2);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003742 case XML_SCHEMAS_BASE64BINARY:
3743 if (y->type == XML_SCHEMAS_BASE64BINARY) {
3744 if (x->value.base64.total == y->value.base64.total) {
3745 int ret = xmlStrcmp(x->value.base64.str,
3746 y->value.base64.str);
3747 if (ret > 0)
3748 return(1);
3749 else if (ret == 0)
3750 return(0);
3751 }
3752 else if (x->value.base64.total > y->value.base64.total)
3753 return(1);
3754 else
3755 return(-1);
3756 }
3757 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00003758 case XML_SCHEMAS_STRING:
3759 case XML_SCHEMAS_IDREFS:
3760 case XML_SCHEMAS_ENTITIES:
3761 case XML_SCHEMAS_NMTOKENS:
3762 TODO
3763 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00003764 }
Daniel Veillard5a872412002-05-22 06:40:27 +00003765 return -2;
Daniel Veillard4255d502002-04-16 15:50:10 +00003766}
3767
3768/**
Daniel Veillardc4c21552003-03-29 10:53:38 +00003769 * xmlSchemaNormLen:
3770 * @value: a string
3771 *
3772 * Computes the UTF8 length of the normalized value of the string
3773 *
3774 * Returns the length or -1 in case of error.
3775 */
3776static int
3777xmlSchemaNormLen(const xmlChar *value) {
3778 const xmlChar *utf;
3779 int ret = 0;
3780
3781 if (value == NULL)
3782 return(-1);
3783 utf = value;
William M. Brack76e95df2003-10-18 16:20:14 +00003784 while (IS_BLANK_CH(*utf)) utf++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003785 while (*utf != 0) {
3786 if (utf[0] & 0x80) {
3787 if ((utf[1] & 0xc0) != 0x80)
3788 return(-1);
3789 if ((utf[0] & 0xe0) == 0xe0) {
3790 if ((utf[2] & 0xc0) != 0x80)
3791 return(-1);
3792 if ((utf[0] & 0xf0) == 0xf0) {
3793 if ((utf[0] & 0xf8) != 0xf0 || (utf[3] & 0xc0) != 0x80)
3794 return(-1);
3795 utf += 4;
3796 } else {
3797 utf += 3;
3798 }
3799 } else {
3800 utf += 2;
3801 }
William M. Brack76e95df2003-10-18 16:20:14 +00003802 } else if (IS_BLANK_CH(*utf)) {
3803 while (IS_BLANK_CH(*utf)) utf++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003804 if (*utf == 0)
3805 break;
3806 } else {
3807 utf++;
3808 }
3809 ret++;
3810 }
3811 return(ret);
3812}
3813
Daniel Veillard6927b102004-10-27 17:29:04 +00003814/**
3815 * xmlSchemaGetFacetValueAsULong:
3816 * @facet: an schemas type facet
3817 *
3818 * Extract the value of a facet
3819 *
3820 * Returns the value as a long
3821 */
Daniel Veillardc0826a72004-08-10 14:17:33 +00003822unsigned long
3823xmlSchemaGetFacetValueAsULong(xmlSchemaFacetPtr facet)
3824{
3825 /*
3826 * TODO: Check if this is a decimal.
3827 */
William M. Brack094dd862004-11-14 14:28:34 +00003828 if (facet == NULL)
3829 return 0;
Daniel Veillardc0826a72004-08-10 14:17:33 +00003830 return ((unsigned long) facet->val->value.decimal.lo);
3831}
3832
Daniel Veillardc4c21552003-03-29 10:53:38 +00003833/**
Daniel Veillard01fa6152004-06-29 17:04:39 +00003834 * xmlSchemaValidateListSimpleTypeFacet:
3835 * @facet: the facet to check
3836 * @value: the lexical repr of the value to validate
3837 * @actualLen: the number of list items
3838 * @expectedLen: the resulting expected number of list items
3839 *
3840 * Checks the value of a list simple type against a facet.
3841 *
3842 * Returns 0 if the value is valid, a positive error code
3843 * number otherwise and -1 in case of an internal error.
3844 */
3845int
3846xmlSchemaValidateListSimpleTypeFacet(xmlSchemaFacetPtr facet,
3847 const xmlChar *value,
3848 unsigned long actualLen,
3849 unsigned long *expectedLen)
3850{
Daniel Veillardce682bc2004-11-05 17:22:25 +00003851 if (facet == NULL)
3852 return(-1);
Daniel Veillard01fa6152004-06-29 17:04:39 +00003853 /*
3854 * TODO: Check if this will work with large numbers.
3855 * (compare value.decimal.mi and value.decimal.hi as well?).
3856 */
3857 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
3858 if (actualLen != facet->val->value.decimal.lo) {
Daniel Veillardc0826a72004-08-10 14:17:33 +00003859 if (expectedLen != 0)
3860 *expectedLen = facet->val->value.decimal.lo;
Daniel Veillard01fa6152004-06-29 17:04:39 +00003861 return (XML_SCHEMAV_CVC_LENGTH_VALID);
3862 }
3863 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
3864 if (actualLen < facet->val->value.decimal.lo) {
Daniel Veillardc0826a72004-08-10 14:17:33 +00003865 if (expectedLen != 0)
3866 *expectedLen = facet->val->value.decimal.lo;
Daniel Veillard01fa6152004-06-29 17:04:39 +00003867 return (XML_SCHEMAV_CVC_MINLENGTH_VALID);
3868 }
3869 } else if (facet->type == XML_SCHEMA_FACET_MAXLENGTH) {
3870 if (actualLen > facet->val->value.decimal.lo) {
Daniel Veillardc0826a72004-08-10 14:17:33 +00003871 if (expectedLen != 0)
3872 *expectedLen = facet->val->value.decimal.lo;
Daniel Veillard01fa6152004-06-29 17:04:39 +00003873 return (XML_SCHEMAV_CVC_MAXLENGTH_VALID);
3874 }
3875 } else
3876 /*
3877 * NOTE: That we can pass NULL as xmlSchemaValPtr to
3878 * xmlSchemaValidateFacet, since the remaining facet types
3879 * are: XML_SCHEMA_FACET_PATTERN, XML_SCHEMA_FACET_ENUMERATION.
3880 */
3881 return(xmlSchemaValidateFacet(NULL, facet, value, NULL));
3882 return (0);
3883}
3884
3885/**
Daniel Veillard6927b102004-10-27 17:29:04 +00003886 * xmlSchemaValidateLengthFacet:
Daniel Veillardc0826a72004-08-10 14:17:33 +00003887 * @type: the built-in type
3888 * @facet: the facet to check
3889 * @value: the lexical repr. of the value to be validated
3890 * @val: the precomputed value
3891 * @length: the actual length of the value
3892 *
3893 * Checka a value against a "length", "minLength" and "maxLength"
3894 * facet; sets @length to the computed length of @value.
3895 *
3896 * Returns 0 if the value is valid, a positive error code
3897 * otherwise and -1 in case of an internal or API error.
3898 */
3899int
3900xmlSchemaValidateLengthFacet(xmlSchemaTypePtr type,
3901 xmlSchemaFacetPtr facet,
3902 const xmlChar *value,
3903 xmlSchemaValPtr val,
3904 unsigned long *length)
3905{
3906 unsigned int len = 0;
3907
Daniel Veillardce682bc2004-11-05 17:22:25 +00003908 if ((length == NULL) || (facet == NULL) || (type == NULL))
3909 return (-1);
Daniel Veillardc0826a72004-08-10 14:17:33 +00003910 *length = 0;
3911 if ((facet->type != XML_SCHEMA_FACET_LENGTH) &&
3912 (facet->type != XML_SCHEMA_FACET_MAXLENGTH) &&
3913 (facet->type != XML_SCHEMA_FACET_MINLENGTH))
3914 return (-1);
3915
3916 if ((facet->val == NULL) ||
3917 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
3918 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
3919 (facet->val->value.decimal.frac != 0)) {
3920 return(-1);
3921 }
3922 if ((val != NULL) && (val->type == XML_SCHEMAS_HEXBINARY))
3923 len = val->value.hex.total;
3924 else if ((val != NULL) && (val->type == XML_SCHEMAS_BASE64BINARY))
3925 len = val->value.base64.total;
3926 else {
3927 switch (type->builtInType) {
3928 case XML_SCHEMAS_IDREF:
3929 case XML_SCHEMAS_NORMSTRING:
3930 case XML_SCHEMAS_TOKEN:
3931 case XML_SCHEMAS_LANGUAGE:
3932 case XML_SCHEMAS_NMTOKEN:
3933 case XML_SCHEMAS_NAME:
3934 case XML_SCHEMAS_NCNAME:
3935 case XML_SCHEMAS_ID:
3936 len = xmlSchemaNormLen(value);
3937 break;
3938 case XML_SCHEMAS_STRING:
3939 /*
3940 * FIXME: What exactly to do with anyURI?
3941 */
3942 case XML_SCHEMAS_ANYURI:
3943 if (value != NULL)
3944 len = xmlUTF8Strlen(value);
3945 break;
3946 default:
3947 TODO
3948 }
3949 }
3950 *length = (unsigned long) len;
3951 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
3952 if (len != facet->val->value.decimal.lo)
3953 return(XML_SCHEMAV_CVC_LENGTH_VALID);
3954 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
3955 if (len < facet->val->value.decimal.lo)
3956 return(XML_SCHEMAV_CVC_MINLENGTH_VALID);
3957 } else {
3958 if (len > facet->val->value.decimal.lo)
3959 return(XML_SCHEMAV_CVC_MAXLENGTH_VALID);
3960 }
3961
3962 return (0);
3963}
3964
3965/**
3966 * xmlSchemaValidateFacet:
Daniel Veillard01c13b52002-12-10 15:19:08 +00003967 * @base: the base type
Daniel Veillard4255d502002-04-16 15:50:10 +00003968 * @facet: the facet to check
3969 * @value: the lexical repr of the value to validate
3970 * @val: the precomputed value
3971 *
3972 * Check a value against a facet condition
3973 *
3974 * Returns 0 if the element is schemas valid, a positive error code
3975 * number otherwise and -1 in case of internal or API error.
3976 */
3977int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00003978xmlSchemaValidateFacet(xmlSchemaTypePtr base ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +00003979 xmlSchemaFacetPtr facet,
Daniel Veillard4255d502002-04-16 15:50:10 +00003980 const xmlChar *value, xmlSchemaValPtr val)
3981{
3982 int ret;
3983
Daniel Veillardce682bc2004-11-05 17:22:25 +00003984 if ((facet == NULL) || (value == NULL))
3985 return(-1);
Daniel Veillard4255d502002-04-16 15:50:10 +00003986 switch (facet->type) {
3987 case XML_SCHEMA_FACET_PATTERN:
3988 ret = xmlRegexpExec(facet->regexp, value);
3989 if (ret == 1)
3990 return(0);
3991 if (ret == 0) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00003992 return(XML_SCHEMAV_CVC_PATTERN_VALID);
Daniel Veillard4255d502002-04-16 15:50:10 +00003993 }
3994 return(ret);
3995 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
3996 ret = xmlSchemaCompareValues(val, facet->val);
3997 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003998 /* TODO error code */
Daniel Veillard4255d502002-04-16 15:50:10 +00003999 return(-1);
4000 }
4001 if (ret == -1)
4002 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00004003 /* error code */
Daniel Veillard01fa6152004-06-29 17:04:39 +00004004 return(XML_SCHEMAV_CVC_MAXEXCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00004005 case XML_SCHEMA_FACET_MAXINCLUSIVE:
4006 ret = xmlSchemaCompareValues(val, facet->val);
4007 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004008 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00004009 return(-1);
4010 }
4011 if ((ret == -1) || (ret == 0))
4012 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00004013 /* error code */
Daniel Veillard01fa6152004-06-29 17:04:39 +00004014 return(XML_SCHEMAV_CVC_MAXINCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00004015 case XML_SCHEMA_FACET_MINEXCLUSIVE:
4016 ret = xmlSchemaCompareValues(val, facet->val);
4017 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004018 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00004019 return(-1);
4020 }
4021 if (ret == 1)
4022 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00004023 /* error code */
Daniel Veillard01fa6152004-06-29 17:04:39 +00004024 return(XML_SCHEMAV_CVC_MINEXCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00004025 case XML_SCHEMA_FACET_MININCLUSIVE:
4026 ret = xmlSchemaCompareValues(val, facet->val);
4027 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004028 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00004029 return(-1);
4030 }
4031 if ((ret == 1) || (ret == 0))
4032 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00004033 /* error code */
Daniel Veillard01fa6152004-06-29 17:04:39 +00004034 return(XML_SCHEMAV_CVC_MININCLUSIVE_VALID);
Daniel Veillard8651f532002-04-17 09:06:27 +00004035 case XML_SCHEMA_FACET_WHITESPACE:
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004036 /* TODO whitespaces */
Daniel Veillard01fa6152004-06-29 17:04:39 +00004037 /*
4038 * NOTE: Whitespace should be handled to normalize
4039 * the value to be validated against a the facets;
4040 * not to normalize the value in-between.
4041 */
Daniel Veillard8651f532002-04-17 09:06:27 +00004042 return(0);
Daniel Veillard88c58912002-04-23 07:12:20 +00004043 case XML_SCHEMA_FACET_ENUMERATION:
4044 if ((facet->value != NULL) &&
4045 (xmlStrEqual(facet->value, value)))
4046 return(0);
Daniel Veillard01fa6152004-06-29 17:04:39 +00004047 return(XML_SCHEMAV_CVC_ENUMERATION_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004048 case XML_SCHEMA_FACET_LENGTH:
4049 case XML_SCHEMA_FACET_MAXLENGTH:
4050 case XML_SCHEMA_FACET_MINLENGTH: {
4051 unsigned int len = 0;
4052
4053 if ((facet->val == NULL) ||
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004054 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
4055 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004056 (facet->val->value.decimal.frac != 0)) {
4057 return(-1);
4058 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00004059 if ((val != NULL) && (val->type == XML_SCHEMAS_HEXBINARY))
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004060 len = val->value.hex.total;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00004061 else if ((val != NULL) && (val->type == XML_SCHEMAS_BASE64BINARY))
4062 len = val->value.base64.total;
4063 else {
Daniel Veillard01fa6152004-06-29 17:04:39 +00004064 switch (base->builtInType) {
Daniel Veillard560c2a42003-07-06 21:13:49 +00004065 case XML_SCHEMAS_IDREF:
4066 case XML_SCHEMAS_NORMSTRING:
4067 case XML_SCHEMAS_TOKEN:
4068 case XML_SCHEMAS_LANGUAGE:
4069 case XML_SCHEMAS_NMTOKEN:
4070 case XML_SCHEMAS_NAME:
4071 case XML_SCHEMAS_NCNAME:
4072 case XML_SCHEMAS_ID:
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004073 len = xmlSchemaNormLen(value);
4074 break;
Daniel Veillard560c2a42003-07-06 21:13:49 +00004075 case XML_SCHEMAS_STRING:
Daniel Veillard01fa6152004-06-29 17:04:39 +00004076 /*
4077 * FIXME: What exactly to do with anyURI?
4078 */
4079 case XML_SCHEMAS_ANYURI:
William M. Brackfbf2c5e2004-02-03 17:55:56 +00004080 if (value != NULL)
4081 len = xmlUTF8Strlen(value);
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004082 break;
Daniel Veillard560c2a42003-07-06 21:13:49 +00004083 default:
4084 TODO
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004085 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004086 }
4087 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004088 if (len != facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004089 return(XML_SCHEMAV_CVC_LENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004090 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004091 if (len < facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004092 return(XML_SCHEMAV_CVC_MINLENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004093 } else {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004094 if (len > facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004095 return(XML_SCHEMAV_CVC_MAXLENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004096 }
4097 break;
4098 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00004099 case XML_SCHEMA_FACET_TOTALDIGITS:
4100 case XML_SCHEMA_FACET_FRACTIONDIGITS:
4101
4102 if ((facet->val == NULL) ||
4103 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
4104 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
4105 (facet->val->value.decimal.frac != 0)) {
4106 return(-1);
4107 }
4108 if ((val == NULL) ||
4109 ((val->type != XML_SCHEMAS_DECIMAL) &&
4110 (val->type != XML_SCHEMAS_INTEGER) &&
4111 (val->type != XML_SCHEMAS_NPINTEGER) &&
4112 (val->type != XML_SCHEMAS_NINTEGER) &&
4113 (val->type != XML_SCHEMAS_NNINTEGER) &&
4114 (val->type != XML_SCHEMAS_PINTEGER) &&
4115 (val->type != XML_SCHEMAS_INT) &&
4116 (val->type != XML_SCHEMAS_UINT) &&
4117 (val->type != XML_SCHEMAS_LONG) &&
4118 (val->type != XML_SCHEMAS_ULONG) &&
4119 (val->type != XML_SCHEMAS_SHORT) &&
4120 (val->type != XML_SCHEMAS_USHORT) &&
4121 (val->type != XML_SCHEMAS_BYTE) &&
4122 (val->type != XML_SCHEMAS_UBYTE))) {
4123 return(-1);
4124 }
4125 if (facet->type == XML_SCHEMA_FACET_TOTALDIGITS) {
4126 if (val->value.decimal.total > facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004127 return(XML_SCHEMAV_CVC_TOTALDIGITS_VALID);
Daniel Veillard560c2a42003-07-06 21:13:49 +00004128
4129 } else if (facet->type == XML_SCHEMA_FACET_FRACTIONDIGITS) {
4130 if (val->value.decimal.frac > facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004131 return(XML_SCHEMAV_CVC_FRACTIONDIGITS_VALID);
Daniel Veillard560c2a42003-07-06 21:13:49 +00004132 }
4133 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00004134 default:
4135 TODO
4136 }
4137 return(0);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00004138
Daniel Veillard4255d502002-04-16 15:50:10 +00004139}
4140
4141#endif /* LIBXML_SCHEMAS_ENABLED */