blob: 622f683e457232b52c7703e1edd7808bde8eb8f3 [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);
2104 if ((ret == 0) && (val != NULL)) {
2105 TODO;
2106 }
2107 goto done;
2108 case XML_SCHEMAS_QNAME:{
2109 xmlChar *uri = NULL;
2110 xmlChar *local = NULL;
2111
2112 ret = xmlValidateQName(value, 1);
2113 if ((ret == 0) && (node != NULL)) {
2114 xmlChar *prefix;
2115
2116 local = xmlSplitQName2(value, &prefix);
2117 if (prefix != NULL) {
2118 xmlNsPtr ns;
2119
2120 ns = xmlSearchNs(node->doc, node, prefix);
2121 if (ns == NULL)
2122 ret = 1;
2123 else if (val != NULL)
2124 uri = xmlStrdup(ns->href);
2125 }
2126 if ((local != NULL) && ((val == NULL) || (ret != 0)))
2127 xmlFree(local);
2128 if (prefix != NULL)
2129 xmlFree(prefix);
2130 }
2131 if ((ret == 0) && (val != NULL)) {
2132 v = xmlSchemaNewValue(XML_SCHEMAS_QNAME);
2133 if (v != NULL) {
2134 if (local != NULL)
2135 v->value.qname.name = local;
2136 else
2137 v->value.qname.name = xmlStrdup(value);
2138 if (uri != NULL)
2139 v->value.qname.uri = uri;
2140
2141 *val = v;
2142 } else {
2143 if (local != NULL)
2144 xmlFree(local);
2145 if (uri != NULL)
2146 xmlFree(uri);
2147 goto error;
2148 }
2149 }
2150 goto done;
2151 }
2152 case XML_SCHEMAS_NCNAME:
2153 ret = xmlValidateNCName(value, 1);
2154 if ((ret == 0) && (val != NULL)) {
2155 v = xmlSchemaNewValue(XML_SCHEMAS_NCNAME);
2156 if (v != NULL) {
2157 v->value.str = xmlStrdup(value);
2158 *val = v;
2159 } else {
2160 goto error;
2161 }
2162 }
2163 goto done;
2164 case XML_SCHEMAS_ID:
2165 ret = xmlValidateNCName(value, 1);
2166 if ((ret == 0) && (val != NULL)) {
2167 v = xmlSchemaNewValue(XML_SCHEMAS_ID);
2168 if (v != NULL) {
2169 v->value.str = xmlStrdup(value);
2170 *val = v;
2171 } else {
2172 goto error;
2173 }
2174 }
2175 if ((ret == 0) && (node != NULL) &&
2176 (node->type == XML_ATTRIBUTE_NODE)) {
2177 xmlAttrPtr attr = (xmlAttrPtr) node;
2178
2179 /*
2180 * NOTE: the IDness might have already be declared in the DTD
2181 */
2182 if (attr->atype != XML_ATTRIBUTE_ID) {
2183 xmlIDPtr res;
2184 xmlChar *strip;
2185
2186 strip = xmlSchemaStrip(value);
2187 if (strip != NULL) {
2188 res = xmlAddID(NULL, node->doc, strip, attr);
2189 xmlFree(strip);
2190 } else
2191 res = xmlAddID(NULL, node->doc, value, attr);
2192 if (res == NULL) {
2193 ret = 2;
2194 } else {
2195 attr->atype = XML_ATTRIBUTE_ID;
2196 }
2197 }
2198 }
2199 goto done;
2200 case XML_SCHEMAS_IDREF:
2201 ret = xmlValidateNCName(value, 1);
2202 if ((ret == 0) && (val != NULL)) {
2203 TODO;
2204 }
2205 if ((ret == 0) && (node != NULL) &&
2206 (node->type == XML_ATTRIBUTE_NODE)) {
2207 xmlAttrPtr attr = (xmlAttrPtr) node;
2208 xmlChar *strip;
2209
2210 strip = xmlSchemaStrip(value);
2211 if (strip != NULL) {
2212 xmlAddRef(NULL, node->doc, strip, attr);
2213 xmlFree(strip);
2214 } else
2215 xmlAddRef(NULL, node->doc, value, attr);
2216 attr->atype = XML_ATTRIBUTE_IDREF;
2217 }
2218 goto done;
2219 case XML_SCHEMAS_IDREFS:
2220 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeIdrefDef,
2221 value, val, node);
2222 if (ret < 0)
2223 ret = 2;
2224 else
2225 ret = 0;
2226 if ((ret == 0) && (node != NULL) &&
2227 (node->type == XML_ATTRIBUTE_NODE)) {
2228 xmlAttrPtr attr = (xmlAttrPtr) node;
2229
2230 attr->atype = XML_ATTRIBUTE_IDREFS;
2231 }
2232 goto done;
2233 case XML_SCHEMAS_ENTITY:{
2234 xmlChar *strip;
2235
2236 ret = xmlValidateNCName(value, 1);
2237 if ((node == NULL) || (node->doc == NULL))
2238 ret = 3;
2239 if (ret == 0) {
2240 xmlEntityPtr ent;
2241
2242 strip = xmlSchemaStrip(value);
2243 if (strip != NULL) {
2244 ent = xmlGetDocEntity(node->doc, strip);
2245 xmlFree(strip);
2246 } else {
2247 ent = xmlGetDocEntity(node->doc, value);
2248 }
2249 if ((ent == NULL) ||
2250 (ent->etype !=
2251 XML_EXTERNAL_GENERAL_UNPARSED_ENTITY))
2252 ret = 4;
2253 }
2254 if ((ret == 0) && (val != NULL)) {
2255 TODO;
2256 }
2257 if ((ret == 0) && (node != NULL) &&
2258 (node->type == XML_ATTRIBUTE_NODE)) {
2259 xmlAttrPtr attr = (xmlAttrPtr) node;
2260
2261 attr->atype = XML_ATTRIBUTE_ENTITY;
2262 }
2263 goto done;
2264 }
2265 case XML_SCHEMAS_ENTITIES:
2266 if ((node == NULL) || (node->doc == NULL))
2267 goto return3;
2268 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeEntityDef,
2269 value, val, node);
2270 if (ret <= 0)
2271 ret = 1;
2272 else
2273 ret = 0;
2274 if ((ret == 0) && (node != NULL) &&
2275 (node->type == XML_ATTRIBUTE_NODE)) {
2276 xmlAttrPtr attr = (xmlAttrPtr) node;
2277
2278 attr->atype = XML_ATTRIBUTE_ENTITIES;
2279 }
2280 goto done;
2281 case XML_SCHEMAS_NOTATION:{
2282 xmlChar *uri = NULL;
2283 xmlChar *local = NULL;
2284
2285 ret = xmlValidateQName(value, 1);
2286 if ((ret == 0) && (node != NULL)) {
2287 xmlChar *prefix;
2288
2289 local = xmlSplitQName2(value, &prefix);
2290 if (prefix != NULL) {
2291 xmlNsPtr ns;
2292
2293 ns = xmlSearchNs(node->doc, node, prefix);
2294 if (ns == NULL)
2295 ret = 1;
2296 else if (val != NULL)
2297 uri = xmlStrdup(ns->href);
2298 }
2299 if ((local != NULL) && ((val == NULL) || (ret != 0)))
2300 xmlFree(local);
2301 if (prefix != NULL)
2302 xmlFree(prefix);
2303 }
2304 if ((node == NULL) || (node->doc == NULL))
2305 ret = 3;
2306 if (ret == 0) {
2307 ret = xmlValidateNotationUse(NULL, node->doc, value);
2308 if (ret == 1)
2309 ret = 0;
2310 else
2311 ret = 1;
2312 }
2313 if ((ret == 0) && (val != NULL)) {
2314 v = xmlSchemaNewValue(XML_SCHEMAS_NOTATION);
2315 if (v != NULL) {
2316 if (local != NULL)
2317 v->value.qname.name = local;
2318 else
2319 v->value.qname.name = xmlStrdup(value);
2320 if (uri != NULL)
2321 v->value.qname.uri = uri;
2322
2323 *val = v;
2324 } else {
2325 if (local != NULL)
2326 xmlFree(local);
2327 if (uri != NULL)
2328 xmlFree(uri);
2329 goto error;
2330 }
2331 }
2332 goto done;
2333 }
2334 case XML_SCHEMAS_ANYURI:{
Daniel Veillard11c466a2004-03-14 12:20:15 +00002335 if (*value != 0) {
2336 xmlURIPtr uri = xmlParseURI((const char *) value);
2337 if (uri == NULL)
2338 goto return1;
2339 xmlFreeURI(uri);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002340 }
Daniel Veillard11c466a2004-03-14 12:20:15 +00002341
2342 if (val != NULL) {
2343 v = xmlSchemaNewValue(XML_SCHEMAS_ANYURI);
2344 if (v == NULL)
2345 goto error;
2346 v->value.str = xmlStrdup(value);
2347 *val = v;
2348 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002349 goto return0;
2350 }
2351 case XML_SCHEMAS_HEXBINARY:{
2352 const xmlChar *cur = value;
2353 xmlChar *base;
2354 int total, i = 0;
2355
Daniel Veillardf34a20e2004-08-31 08:42:17 +00002356 if (cur == NULL)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002357 goto return1;
2358
2359 while (((*cur >= '0') && (*cur <= '9')) ||
2360 ((*cur >= 'A') && (*cur <= 'F')) ||
2361 ((*cur >= 'a') && (*cur <= 'f'))) {
2362 i++;
2363 cur++;
2364 }
2365
2366 if (*cur != 0)
2367 goto return1;
2368 if ((i % 2) != 0)
2369 goto return1;
2370
2371 if (val != NULL) {
2372
2373 v = xmlSchemaNewValue(XML_SCHEMAS_HEXBINARY);
2374 if (v == NULL)
2375 goto error;
2376
2377 cur = xmlStrdup(value);
2378 if (cur == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002379 xmlSchemaTypeErrMemory(node, "allocating hexbin data");
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002380 xmlFree(v);
2381 goto return1;
2382 }
2383
2384 total = i / 2; /* number of octets */
2385
2386 base = (xmlChar *) cur;
2387 while (i-- > 0) {
2388 if (*base >= 'a')
2389 *base = *base - ('a' - 'A');
2390 base++;
2391 }
2392
2393 v->value.hex.str = (xmlChar *) cur;
2394 v->value.hex.total = total;
2395 *val = v;
2396 }
2397 goto return0;
2398 }
2399 case XML_SCHEMAS_BASE64BINARY:{
2400 /* ISSUE:
2401 *
2402 * Ignore all stray characters? (yes, currently)
2403 * Worry about long lines? (no, currently)
2404 *
2405 * rfc2045.txt:
2406 *
2407 * "The encoded output stream must be represented in lines of
2408 * no more than 76 characters each. All line breaks or other
2409 * characters not found in Table 1 must be ignored by decoding
2410 * software. In base64 data, characters other than those in
2411 * Table 1, line breaks, and other white space probably
2412 * indicate a transmission error, about which a warning
2413 * message or even a message rejection might be appropriate
2414 * under some circumstances." */
2415 const xmlChar *cur = value;
2416 xmlChar *base;
2417 int total, i = 0, pad = 0;
2418
2419 if (cur == NULL)
2420 goto return1;
2421
2422 for (; *cur; ++cur) {
2423 int decc;
2424
2425 decc = _xmlSchemaBase64Decode(*cur);
2426 if (decc < 0) ;
2427 else if (decc < 64)
2428 i++;
2429 else
2430 break;
2431 }
2432 for (; *cur; ++cur) {
2433 int decc;
2434
2435 decc = _xmlSchemaBase64Decode(*cur);
2436 if (decc < 0) ;
2437 else if (decc < 64)
2438 goto return1;
2439 if (decc == 64)
2440 pad++;
2441 }
2442
2443 /* rfc2045.txt: "Special processing is performed if fewer than
2444 * 24 bits are available at the end of the data being encoded.
2445 * A full encoding quantum is always completed at the end of a
2446 * body. When fewer than 24 input bits are available in an
2447 * input group, zero bits are added (on the right) to form an
2448 * integral number of 6-bit groups. Padding at the end of the
2449 * data is performed using the "=" character. Since all
2450 * base64 input is an integral number of octets, only the
2451 * following cases can arise: (1) the final quantum of
2452 * encoding input is an integral multiple of 24 bits; here,
2453 * the final unit of encoded output will be an integral
2454 * multiple ofindent: Standard input:701: Warning:old style
2455 * assignment ambiguity in "=*". Assuming "= *" 4 characters
2456 * with no "=" padding, (2) the final
2457 * quantum of encoding input is exactly 8 bits; here, the
2458 * final unit of encoded output will be two characters
2459 * followed by two "=" padding characters, or (3) the final
2460 * quantum of encoding input is exactly 16 bits; here, the
2461 * final unit of encoded output will be three characters
2462 * followed by one "=" padding character." */
2463
2464 total = 3 * (i / 4);
2465 if (pad == 0) {
2466 if (i % 4 != 0)
2467 goto return1;
2468 } else if (pad == 1) {
2469 int decc;
2470
2471 if (i % 4 != 3)
2472 goto return1;
2473 for (decc = _xmlSchemaBase64Decode(*cur);
2474 (decc < 0) || (decc > 63);
2475 decc = _xmlSchemaBase64Decode(*cur))
2476 --cur;
2477 /* 16bits in 24bits means 2 pad bits: nnnnnn nnmmmm mmmm00*/
2478 /* 00111100 -> 0x3c */
2479 if (decc & ~0x3c)
2480 goto return1;
2481 total += 2;
2482 } else if (pad == 2) {
2483 int decc;
2484
2485 if (i % 4 != 2)
2486 goto return1;
2487 for (decc = _xmlSchemaBase64Decode(*cur);
2488 (decc < 0) || (decc > 63);
2489 decc = _xmlSchemaBase64Decode(*cur))
2490 --cur;
2491 /* 8bits in 12bits means 4 pad bits: nnnnnn nn0000 */
2492 /* 00110000 -> 0x30 */
2493 if (decc & ~0x30)
2494 goto return1;
2495 total += 1;
2496 } else
2497 goto return1;
2498
2499 if (val != NULL) {
2500 v = xmlSchemaNewValue(XML_SCHEMAS_BASE64BINARY);
2501 if (v == NULL)
2502 goto error;
2503 base =
2504 (xmlChar *) xmlMallocAtomic((i + pad + 1) *
2505 sizeof(xmlChar));
2506 if (base == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002507 xmlSchemaTypeErrMemory(node, "allocating base64 data");
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002508 xmlFree(v);
2509 goto return1;
2510 }
2511 v->value.base64.str = base;
2512 for (cur = value; *cur; ++cur)
2513 if (_xmlSchemaBase64Decode(*cur) >= 0) {
2514 *base = *cur;
2515 ++base;
2516 }
2517 *base = 0;
2518 v->value.base64.total = total;
2519 *val = v;
2520 }
2521 goto return0;
2522 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002523 case XML_SCHEMAS_INTEGER:
2524 case XML_SCHEMAS_PINTEGER:
2525 case XML_SCHEMAS_NPINTEGER:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002526 case XML_SCHEMAS_NINTEGER:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002527 case XML_SCHEMAS_NNINTEGER:{
2528 const xmlChar *cur = value;
2529 unsigned long lo, mi, hi;
2530 int sign = 0;
2531
2532 if (cur == NULL)
2533 goto return1;
2534 if (*cur == '-') {
2535 sign = 1;
2536 cur++;
2537 } else if (*cur == '+')
2538 cur++;
2539 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2540 if (ret == 0)
2541 goto return1;
2542 if (*cur != 0)
2543 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002544 if (type->builtInType == XML_SCHEMAS_NPINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002545 if ((sign == 0) &&
2546 ((hi != 0) || (mi != 0) || (lo != 0)))
2547 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002548 } else if (type->builtInType == XML_SCHEMAS_PINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002549 if (sign == 1)
2550 goto return1;
2551 if ((hi == 0) && (mi == 0) && (lo == 0))
2552 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002553 } else if (type->builtInType == XML_SCHEMAS_NINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002554 if (sign == 0)
2555 goto return1;
2556 if ((hi == 0) && (mi == 0) && (lo == 0))
2557 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002558 } else if (type->builtInType == XML_SCHEMAS_NNINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002559 if ((sign == 1) &&
2560 ((hi != 0) || (mi != 0) || (lo != 0)))
2561 goto return1;
2562 }
2563 /*
2564 * We can store a value only if no overflow occured
2565 */
2566 if ((ret > 0) && (val != NULL)) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00002567 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002568 if (v != NULL) {
2569 v->value.decimal.lo = lo;
2570 v->value.decimal.mi = lo;
2571 v->value.decimal.hi = lo;
2572 v->value.decimal.sign = sign;
2573 v->value.decimal.frac = 0;
2574 v->value.decimal.total = cur - value;
2575 *val = v;
2576 }
2577 }
2578 goto return0;
2579 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002580 case XML_SCHEMAS_LONG:
2581 case XML_SCHEMAS_BYTE:
2582 case XML_SCHEMAS_SHORT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002583 case XML_SCHEMAS_INT:{
2584 const xmlChar *cur = value;
2585 unsigned long lo, mi, hi;
2586 int total = 0;
2587 int sign = 0;
2588
2589 if (cur == NULL)
2590 goto return1;
2591 if (*cur == '-') {
2592 sign = 1;
2593 cur++;
2594 } else if (*cur == '+')
2595 cur++;
2596 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2597 if (ret <= 0)
2598 goto return1;
2599 if (*cur != 0)
2600 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002601 if (type->builtInType == XML_SCHEMAS_LONG) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002602 if (hi >= 922) {
2603 if (hi > 922)
2604 goto return1;
2605 if (mi >= 33720368) {
2606 if (mi > 33720368)
2607 goto return1;
2608 if ((sign == 0) && (lo > 54775807))
2609 goto return1;
2610 if ((sign == 1) && (lo > 54775808))
2611 goto return1;
2612 }
2613 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002614 } else if (type->builtInType == XML_SCHEMAS_INT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002615 if (hi != 0)
2616 goto return1;
2617 if (mi >= 21) {
2618 if (mi > 21)
2619 goto return1;
2620 if ((sign == 0) && (lo > 47483647))
2621 goto return1;
2622 if ((sign == 1) && (lo > 47483648))
2623 goto return1;
2624 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002625 } else if (type->builtInType == XML_SCHEMAS_SHORT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002626 if ((mi != 0) || (hi != 0))
2627 goto return1;
2628 if ((sign == 1) && (lo > 32768))
2629 goto return1;
2630 if ((sign == 0) && (lo > 32767))
2631 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002632 } else if (type->builtInType == XML_SCHEMAS_BYTE) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002633 if ((mi != 0) || (hi != 0))
2634 goto return1;
2635 if ((sign == 1) && (lo > 128))
2636 goto return1;
2637 if ((sign == 0) && (lo > 127))
2638 goto return1;
2639 }
2640 if (val != NULL) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00002641 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002642 if (v != NULL) {
2643 v->value.decimal.lo = lo;
2644 v->value.decimal.mi = lo;
2645 v->value.decimal.hi = lo;
2646 v->value.decimal.sign = sign;
2647 v->value.decimal.frac = 0;
2648 v->value.decimal.total = total;
2649 *val = v;
2650 }
2651 }
2652 goto return0;
2653 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002654 case XML_SCHEMAS_UINT:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002655 case XML_SCHEMAS_ULONG:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002656 case XML_SCHEMAS_USHORT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002657 case XML_SCHEMAS_UBYTE:{
2658 const xmlChar *cur = value;
2659 unsigned long lo, mi, hi;
2660 int total = 0;
2661
2662 if (cur == NULL)
2663 goto return1;
2664 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2665 if (ret <= 0)
2666 goto return1;
2667 if (*cur != 0)
2668 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002669 if (type->builtInType == XML_SCHEMAS_ULONG) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002670 if (hi >= 1844) {
2671 if (hi > 1844)
2672 goto return1;
2673 if (mi >= 67440737) {
2674 if (mi > 67440737)
2675 goto return1;
2676 if (lo > 9551615)
2677 goto return1;
2678 }
2679 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002680 } else if (type->builtInType == XML_SCHEMAS_UINT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002681 if (hi != 0)
2682 goto return1;
2683 if (mi >= 42) {
2684 if (mi > 42)
2685 goto return1;
2686 if (lo > 94967295)
2687 goto return1;
2688 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002689 } else if (type->builtInType == XML_SCHEMAS_USHORT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002690 if ((mi != 0) || (hi != 0))
2691 goto return1;
2692 if (lo > 65535)
2693 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002694 } else if (type->builtInType == XML_SCHEMAS_UBYTE) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002695 if ((mi != 0) || (hi != 0))
2696 goto return1;
2697 if (lo > 255)
2698 goto return1;
2699 }
2700 if (val != NULL) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00002701 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002702 if (v != NULL) {
2703 v->value.decimal.lo = lo;
2704 v->value.decimal.mi = mi;
2705 v->value.decimal.hi = hi;
2706 v->value.decimal.sign = 0;
2707 v->value.decimal.frac = 0;
2708 v->value.decimal.total = total;
2709 *val = v;
2710 }
2711 }
2712 goto return0;
2713 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002714 }
2715
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002716 done:
2717 if (norm != NULL)
2718 xmlFree(norm);
2719 return (ret);
2720 return3:
2721 if (norm != NULL)
2722 xmlFree(norm);
2723 return (3);
2724 return1:
2725 if (norm != NULL)
2726 xmlFree(norm);
2727 return (1);
2728 return0:
2729 if (norm != NULL)
2730 xmlFree(norm);
2731 return (0);
2732 error:
2733 if (norm != NULL)
2734 xmlFree(norm);
2735 return (-1);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002736}
2737
2738/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002739 * xmlSchemaValPredefTypeNode:
Daniel Veillard4255d502002-04-16 15:50:10 +00002740 * @type: the predefined type
2741 * @value: the value to check
2742 * @val: the return computed value
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002743 * @node: the node containing the value
Daniel Veillard4255d502002-04-16 15:50:10 +00002744 *
2745 * Check that a value conforms to the lexical space of the predefined type.
2746 * if true a value is computed and returned in @val.
2747 *
2748 * Returns 0 if this validates, a positive error code number otherwise
2749 * and -1 in case of internal or API error.
2750 */
2751int
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002752xmlSchemaValPredefTypeNode(xmlSchemaTypePtr type, const xmlChar *value,
2753 xmlSchemaValPtr *val, xmlNodePtr node) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002754 return(xmlSchemaValAtomicType(type, value, val, node, 0));
Daniel Veillard4255d502002-04-16 15:50:10 +00002755}
2756
2757/**
Daniel Veillardc0826a72004-08-10 14:17:33 +00002758 * xmlSchemaValPredefTypeNodeNoNorm:
2759 * @type: the predefined type
2760 * @value: the value to check
2761 * @val: the return computed value
2762 * @node: the node containing the value
2763 *
2764 * Check that a value conforms to the lexical space of the predefined type.
2765 * if true a value is computed and returned in @val.
2766 * This one does apply any normalization to the value.
2767 *
2768 * Returns 0 if this validates, a positive error code number otherwise
2769 * and -1 in case of internal or API error.
2770 */
2771int
2772xmlSchemaValPredefTypeNodeNoNorm(xmlSchemaTypePtr type, const xmlChar *value,
2773 xmlSchemaValPtr *val, xmlNodePtr node) {
2774 return(xmlSchemaValAtomicType(type, value, val, node, 1));
2775}
2776
2777/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002778 * xmlSchemaValidatePredefinedType:
2779 * @type: the predefined type
2780 * @value: the value to check
2781 * @val: the return computed value
2782 *
2783 * Check that a value conforms to the lexical space of the predefined type.
2784 * if true a value is computed and returned in @val.
2785 *
2786 * Returns 0 if this validates, a positive error code number otherwise
2787 * and -1 in case of internal or API error.
2788 */
2789int
2790xmlSchemaValidatePredefinedType(xmlSchemaTypePtr type, const xmlChar *value,
2791 xmlSchemaValPtr *val) {
2792 return(xmlSchemaValPredefTypeNode(type, value, val, NULL));
2793}
2794
2795/**
Daniel Veillard4255d502002-04-16 15:50:10 +00002796 * xmlSchemaCompareDecimals:
2797 * @x: a first decimal value
2798 * @y: a second decimal value
2799 *
2800 * Compare 2 decimals
2801 *
2802 * Returns -1 if x < y, 0 if x == y, 1 if x > y and -2 in case of error
2803 */
2804static int
2805xmlSchemaCompareDecimals(xmlSchemaValPtr x, xmlSchemaValPtr y)
2806{
2807 xmlSchemaValPtr swp;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002808 int order = 1, p;
Daniel Veillard4255d502002-04-16 15:50:10 +00002809 unsigned long tmp;
2810
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002811 if ((x->value.decimal.sign) &&
2812 ((x->value.decimal.lo != 0) ||
2813 (x->value.decimal.mi != 0) ||
2814 (x->value.decimal.hi != 0))) {
2815 if ((y->value.decimal.sign) &&
2816 ((y->value.decimal.lo != 0) ||
2817 (y->value.decimal.mi != 0) ||
2818 (y->value.decimal.hi != 0)))
Daniel Veillard80b19092003-03-28 13:29:53 +00002819 order = -1;
2820 else
2821 return (-1);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002822 } else if ((y->value.decimal.sign) &&
2823 ((y->value.decimal.lo != 0) ||
2824 (y->value.decimal.mi != 0) ||
2825 (y->value.decimal.hi != 0))) {
Daniel Veillard4255d502002-04-16 15:50:10 +00002826 return (1);
Daniel Veillard80b19092003-03-28 13:29:53 +00002827 }
Daniel Veillard4255d502002-04-16 15:50:10 +00002828 if (x->value.decimal.frac == y->value.decimal.frac) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002829 if (x->value.decimal.hi < y->value.decimal.hi)
2830 return (-order);
Daniel Veillard01fa6152004-06-29 17:04:39 +00002831 if (x->value.decimal.hi > y->value.decimal.hi)
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002832 return (order);
2833 if (x->value.decimal.mi < y->value.decimal.mi)
2834 return (-order);
Daniel Veillard01fa6152004-06-29 17:04:39 +00002835 if (x->value.decimal.mi > y->value.decimal.mi)
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002836 return (order);
2837 if (x->value.decimal.lo < y->value.decimal.lo)
Daniel Veillard80b19092003-03-28 13:29:53 +00002838 return (-order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002839 if (x->value.decimal.lo > y->value.decimal.lo)
Daniel Veillard80b19092003-03-28 13:29:53 +00002840 return(order);
2841 return(0);
Daniel Veillard4255d502002-04-16 15:50:10 +00002842 }
2843 if (y->value.decimal.frac > x->value.decimal.frac) {
2844 swp = y;
2845 y = x;
2846 x = swp;
2847 order = -order;
2848 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002849 p = powten[x->value.decimal.frac - y->value.decimal.frac];
2850 tmp = x->value.decimal.lo / p;
2851 if (tmp > y->value.decimal.lo)
Daniel Veillard4255d502002-04-16 15:50:10 +00002852 return (order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002853 if (tmp < y->value.decimal.lo)
Daniel Veillard4255d502002-04-16 15:50:10 +00002854 return (-order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002855 tmp = y->value.decimal.lo * p;
2856 if (x->value.decimal.lo < tmp)
Daniel Veillard4255d502002-04-16 15:50:10 +00002857 return (-order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002858 if (x->value.decimal.lo == tmp)
Daniel Veillard4255d502002-04-16 15:50:10 +00002859 return (0);
2860 return (order);
2861}
2862
2863/**
Daniel Veillard070803b2002-05-03 07:29:38 +00002864 * xmlSchemaCompareDurations:
2865 * @x: a first duration value
2866 * @y: a second duration value
2867 *
2868 * Compare 2 durations
2869 *
2870 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
2871 * case of error
2872 */
2873static int
2874xmlSchemaCompareDurations(xmlSchemaValPtr x, xmlSchemaValPtr y)
2875{
2876 long carry, mon, day;
2877 double sec;
Daniel Veillard80b19092003-03-28 13:29:53 +00002878 int invert = 1;
2879 long xmon, xday, myear, minday, maxday;
Daniel Veillard070803b2002-05-03 07:29:38 +00002880 static const long dayRange [2][12] = {
2881 { 0, 28, 59, 89, 120, 150, 181, 212, 242, 273, 303, 334, },
2882 { 0, 31, 62, 92, 123, 153, 184, 215, 245, 276, 306, 337} };
2883
2884 if ((x == NULL) || (y == NULL))
Daniel Veillard5a872412002-05-22 06:40:27 +00002885 return -2;
Daniel Veillard070803b2002-05-03 07:29:38 +00002886
2887 /* months */
2888 mon = x->value.dur.mon - y->value.dur.mon;
2889
2890 /* seconds */
2891 sec = x->value.dur.sec - y->value.dur.sec;
2892 carry = (long)sec / SECS_PER_DAY;
2893 sec -= (double)(carry * SECS_PER_DAY);
2894
2895 /* days */
2896 day = x->value.dur.day - y->value.dur.day + carry;
2897
2898 /* easy test */
2899 if (mon == 0) {
2900 if (day == 0)
2901 if (sec == 0.0)
2902 return 0;
2903 else if (sec < 0.0)
2904 return -1;
2905 else
2906 return 1;
2907 else if (day < 0)
2908 return -1;
2909 else
2910 return 1;
2911 }
2912
2913 if (mon > 0) {
2914 if ((day >= 0) && (sec >= 0.0))
2915 return 1;
2916 else {
2917 xmon = mon;
2918 xday = -day;
2919 }
2920 } else if ((day <= 0) && (sec <= 0.0)) {
2921 return -1;
2922 } else {
Daniel Veillard80b19092003-03-28 13:29:53 +00002923 invert = -1;
Daniel Veillard070803b2002-05-03 07:29:38 +00002924 xmon = -mon;
2925 xday = day;
2926 }
2927
2928 myear = xmon / 12;
Daniel Veillard80b19092003-03-28 13:29:53 +00002929 if (myear == 0) {
2930 minday = 0;
2931 maxday = 0;
2932 } else {
2933 maxday = 366 * ((myear + 3) / 4) +
2934 365 * ((myear - 1) % 4);
2935 minday = maxday - 1;
2936 }
2937
Daniel Veillard070803b2002-05-03 07:29:38 +00002938 xmon = xmon % 12;
2939 minday += dayRange[0][xmon];
2940 maxday += dayRange[1][xmon];
2941
Daniel Veillard80b19092003-03-28 13:29:53 +00002942 if ((maxday == minday) && (maxday == xday))
2943 return(0); /* can this really happen ? */
Daniel Veillard070803b2002-05-03 07:29:38 +00002944 if (maxday < xday)
Daniel Veillard80b19092003-03-28 13:29:53 +00002945 return(-invert);
2946 if (minday > xday)
2947 return(invert);
Daniel Veillard070803b2002-05-03 07:29:38 +00002948
2949 /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00002950 return 2;
2951}
2952
2953/*
2954 * macros for adding date/times and durations
2955 */
2956#define FQUOTIENT(a,b) (floor(((double)a/(double)b)))
2957#define MODULO(a,b) (a - FQUOTIENT(a,b) * b)
2958#define FQUOTIENT_RANGE(a,low,high) (FQUOTIENT((a-low),(high-low)))
2959#define MODULO_RANGE(a,low,high) ((MODULO((a-low),(high-low)))+low)
2960
2961/**
Daniel Veillard669adfc2004-05-29 20:12:46 +00002962 * xmlSchemaDupVal:
2963 * @v: the #xmlSchemaValPtr value to duplicate
2964 *
2965 * Makes a copy of @v. The calling program is responsible for freeing
2966 * the returned value.
2967 *
2968 * returns a pointer to a duplicated #xmlSchemaValPtr or NULL if error.
2969 */
2970static xmlSchemaValPtr
2971xmlSchemaDupVal (xmlSchemaValPtr v)
2972{
2973 xmlSchemaValPtr ret = xmlSchemaNewValue(v->type);
2974 if (ret == NULL)
2975 return NULL;
2976
2977 memcpy(ret, v, sizeof(xmlSchemaVal));
2978 return ret;
2979}
2980
2981/**
Daniel Veillard5a872412002-05-22 06:40:27 +00002982 * _xmlSchemaDateAdd:
2983 * @dt: an #xmlSchemaValPtr
2984 * @dur: an #xmlSchemaValPtr of type #XS_DURATION
2985 *
2986 * Compute a new date/time from @dt and @dur. This function assumes @dt
2987 * is either #XML_SCHEMAS_DATETIME, #XML_SCHEMAS_DATE, #XML_SCHEMAS_GYEARMONTH,
Daniel Veillard669adfc2004-05-29 20:12:46 +00002988 * or #XML_SCHEMAS_GYEAR. The returned #xmlSchemaVal is the same type as
2989 * @dt. The calling program is responsible for freeing the returned value.
Daniel Veillard5a872412002-05-22 06:40:27 +00002990 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00002991 * Returns a pointer to a new #xmlSchemaVal or NULL if error.
Daniel Veillard5a872412002-05-22 06:40:27 +00002992 */
2993static xmlSchemaValPtr
2994_xmlSchemaDateAdd (xmlSchemaValPtr dt, xmlSchemaValPtr dur)
2995{
Daniel Veillard669adfc2004-05-29 20:12:46 +00002996 xmlSchemaValPtr ret, tmp;
Daniel Veillard5a872412002-05-22 06:40:27 +00002997 long carry, tempdays, temp;
2998 xmlSchemaValDatePtr r, d;
2999 xmlSchemaValDurationPtr u;
3000
3001 if ((dt == NULL) || (dur == NULL))
3002 return NULL;
3003
3004 ret = xmlSchemaNewValue(dt->type);
3005 if (ret == NULL)
3006 return NULL;
3007
Daniel Veillard669adfc2004-05-29 20:12:46 +00003008 /* make a copy so we don't alter the original value */
3009 tmp = xmlSchemaDupVal(dt);
3010 if (tmp == NULL) {
3011 xmlSchemaFreeValue(ret);
3012 return NULL;
3013 }
3014
Daniel Veillard5a872412002-05-22 06:40:27 +00003015 r = &(ret->value.date);
Daniel Veillard669adfc2004-05-29 20:12:46 +00003016 d = &(tmp->value.date);
Daniel Veillard5a872412002-05-22 06:40:27 +00003017 u = &(dur->value.dur);
3018
3019 /* normalization */
3020 if (d->mon == 0)
3021 d->mon = 1;
3022
3023 /* normalize for time zone offset */
3024 u->sec -= (d->tzo * 60);
3025 d->tzo = 0;
3026
3027 /* normalization */
3028 if (d->day == 0)
3029 d->day = 1;
3030
3031 /* month */
3032 carry = d->mon + u->mon;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003033 r->mon = (unsigned int) MODULO_RANGE(carry, 1, 13);
3034 carry = (long) FQUOTIENT_RANGE(carry, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00003035
3036 /* year (may be modified later) */
3037 r->year = d->year + carry;
3038 if (r->year == 0) {
3039 if (d->year > 0)
3040 r->year--;
3041 else
3042 r->year++;
3043 }
3044
3045 /* time zone */
3046 r->tzo = d->tzo;
3047 r->tz_flag = d->tz_flag;
3048
3049 /* seconds */
3050 r->sec = d->sec + u->sec;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003051 carry = (long) FQUOTIENT((long)r->sec, 60);
Daniel Veillard5a872412002-05-22 06:40:27 +00003052 if (r->sec != 0.0) {
3053 r->sec = MODULO(r->sec, 60.0);
3054 }
3055
3056 /* minute */
3057 carry += d->min;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003058 r->min = (unsigned int) MODULO(carry, 60);
3059 carry = (long) FQUOTIENT(carry, 60);
Daniel Veillard5a872412002-05-22 06:40:27 +00003060
3061 /* hours */
3062 carry += d->hour;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003063 r->hour = (unsigned int) MODULO(carry, 24);
3064 carry = (long)FQUOTIENT(carry, 24);
Daniel Veillard5a872412002-05-22 06:40:27 +00003065
3066 /*
3067 * days
3068 * Note we use tempdays because the temporary values may need more
3069 * than 5 bits
3070 */
3071 if ((VALID_YEAR(r->year)) && (VALID_MONTH(r->mon)) &&
3072 (d->day > MAX_DAYINMONTH(r->year, r->mon)))
3073 tempdays = MAX_DAYINMONTH(r->year, r->mon);
3074 else if (d->day < 1)
3075 tempdays = 1;
3076 else
3077 tempdays = d->day;
3078
3079 tempdays += u->day + carry;
3080
3081 while (1) {
3082 if (tempdays < 1) {
Daniel Veillardebe25d42004-03-25 09:35:49 +00003083 long tmon = (long) MODULO_RANGE(r->mon-1, 1, 13);
3084 long tyr = r->year + (long)FQUOTIENT_RANGE(r->mon-1, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00003085 if (tyr == 0)
3086 tyr--;
3087 tempdays += MAX_DAYINMONTH(tyr, tmon);
3088 carry = -1;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003089 } else if (tempdays > (long) MAX_DAYINMONTH(r->year, r->mon)) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003090 tempdays = tempdays - MAX_DAYINMONTH(r->year, r->mon);
3091 carry = 1;
3092 } else
3093 break;
3094
3095 temp = r->mon + carry;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003096 r->mon = (unsigned int) MODULO_RANGE(temp, 1, 13);
3097 r->year = r->year + (unsigned int) FQUOTIENT_RANGE(temp, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00003098 if (r->year == 0) {
3099 if (temp < 1)
3100 r->year--;
3101 else
3102 r->year++;
3103 }
3104 }
3105
3106 r->day = tempdays;
3107
3108 /*
3109 * adjust the date/time type to the date values
3110 */
3111 if (ret->type != XML_SCHEMAS_DATETIME) {
3112 if ((r->hour) || (r->min) || (r->sec))
3113 ret->type = XML_SCHEMAS_DATETIME;
3114 else if (ret->type != XML_SCHEMAS_DATE) {
3115 if ((r->mon != 1) && (r->day != 1))
3116 ret->type = XML_SCHEMAS_DATE;
3117 else if ((ret->type != XML_SCHEMAS_GYEARMONTH) && (r->mon != 1))
3118 ret->type = XML_SCHEMAS_GYEARMONTH;
3119 }
3120 }
3121
Daniel Veillard669adfc2004-05-29 20:12:46 +00003122 xmlSchemaFreeValue(tmp);
Daniel Veillard5a872412002-05-22 06:40:27 +00003123
Daniel Veillard5a872412002-05-22 06:40:27 +00003124 return ret;
3125}
3126
3127/**
3128 * xmlSchemaDateNormalize:
Daniel Veillard669adfc2004-05-29 20:12:46 +00003129 * @dt: an #xmlSchemaValPtr of a date/time type value.
3130 * @offset: number of seconds to adjust @dt by.
Daniel Veillard5a872412002-05-22 06:40:27 +00003131 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00003132 * Normalize @dt to GMT time. The @offset parameter is subtracted from
3133 * the return value is a time-zone offset is present on @dt.
Daniel Veillard5a872412002-05-22 06:40:27 +00003134 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00003135 * Returns a normalized copy of @dt or NULL if error.
Daniel Veillard5a872412002-05-22 06:40:27 +00003136 */
3137static xmlSchemaValPtr
3138xmlSchemaDateNormalize (xmlSchemaValPtr dt, double offset)
3139{
3140 xmlSchemaValPtr dur, ret;
3141
3142 if (dt == NULL)
3143 return NULL;
3144
3145 if (((dt->type != XML_SCHEMAS_TIME) &&
3146 (dt->type != XML_SCHEMAS_DATETIME)) || (dt->value.date.tzo == 0))
3147 return xmlSchemaDupVal(dt);
3148
3149 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
3150 if (dur == NULL)
3151 return NULL;
3152
3153 dur->value.date.sec -= offset;
3154
3155 ret = _xmlSchemaDateAdd(dt, dur);
3156 if (ret == NULL)
3157 return NULL;
3158
3159 xmlSchemaFreeValue(dur);
3160
3161 /* ret->value.date.tzo = 0; */
3162 return ret;
3163}
3164
3165/**
3166 * _xmlSchemaDateCastYMToDays:
3167 * @dt: an #xmlSchemaValPtr
3168 *
3169 * Convert mon and year of @dt to total number of days. Take the
3170 * number of years since (or before) 1 AD and add the number of leap
3171 * years. This is a function because negative
3172 * years must be handled a little differently and there is no zero year.
3173 *
3174 * Returns number of days.
3175 */
3176static long
3177_xmlSchemaDateCastYMToDays (const xmlSchemaValPtr dt)
3178{
3179 long ret;
Daniel Veillard49e89632004-09-23 16:24:36 +00003180 int mon;
Daniel Veillard5a872412002-05-22 06:40:27 +00003181
Daniel Veillard49e89632004-09-23 16:24:36 +00003182 mon = dt->value.date.mon;
3183 if (mon <= 0) mon = 1; /* normalization */
3184
3185 if (dt->value.date.year <= 0)
Daniel Veillard5a872412002-05-22 06:40:27 +00003186 ret = (dt->value.date.year * 365) +
3187 (((dt->value.date.year+1)/4)-((dt->value.date.year+1)/100)+
3188 ((dt->value.date.year+1)/400)) +
Daniel Veillard49e89632004-09-23 16:24:36 +00003189 DAY_IN_YEAR(0, mon, dt->value.date.year);
Daniel Veillard5a872412002-05-22 06:40:27 +00003190 else
3191 ret = ((dt->value.date.year-1) * 365) +
3192 (((dt->value.date.year-1)/4)-((dt->value.date.year-1)/100)+
3193 ((dt->value.date.year-1)/400)) +
Daniel Veillard49e89632004-09-23 16:24:36 +00003194 DAY_IN_YEAR(0, mon, dt->value.date.year);
Daniel Veillard5a872412002-05-22 06:40:27 +00003195
3196 return ret;
3197}
3198
3199/**
3200 * TIME_TO_NUMBER:
3201 * @dt: an #xmlSchemaValPtr
3202 *
3203 * Calculates the number of seconds in the time portion of @dt.
3204 *
3205 * Returns seconds.
3206 */
3207#define TIME_TO_NUMBER(dt) \
3208 ((double)((dt->value.date.hour * SECS_PER_HOUR) + \
Daniel Veillardb3721c22003-03-31 11:22:25 +00003209 (dt->value.date.min * SECS_PER_MIN) + \
3210 (dt->value.date.tzo * SECS_PER_MIN)) + \
3211 dt->value.date.sec)
Daniel Veillard5a872412002-05-22 06:40:27 +00003212
3213/**
3214 * xmlSchemaCompareDates:
3215 * @x: a first date/time value
3216 * @y: a second date/time value
3217 *
3218 * Compare 2 date/times
3219 *
3220 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3221 * case of error
3222 */
3223static int
3224xmlSchemaCompareDates (xmlSchemaValPtr x, xmlSchemaValPtr y)
3225{
3226 unsigned char xmask, ymask, xor_mask, and_mask;
3227 xmlSchemaValPtr p1, p2, q1, q2;
3228 long p1d, p2d, q1d, q2d;
3229
3230 if ((x == NULL) || (y == NULL))
3231 return -2;
3232
3233 if (x->value.date.tz_flag) {
3234
3235 if (!y->value.date.tz_flag) {
3236 p1 = xmlSchemaDateNormalize(x, 0);
3237 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3238 /* normalize y + 14:00 */
3239 q1 = xmlSchemaDateNormalize(y, (14 * SECS_PER_HOUR));
3240
3241 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003242 if (p1d < q1d) {
3243 xmlSchemaFreeValue(p1);
3244 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003245 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003246 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003247 double sec;
3248
3249 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00003250 if (sec < 0.0) {
3251 xmlSchemaFreeValue(p1);
3252 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003253 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003254 } else {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003255 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003256 /* normalize y - 14:00 */
3257 q2 = xmlSchemaDateNormalize(y, -(14 * SECS_PER_HOUR));
3258 q2d = _xmlSchemaDateCastYMToDays(q2) + q2->value.date.day;
3259 if (p1d > q2d)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003260 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003261 else if (p1d == q2d) {
3262 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q2);
3263 if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003264 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003265 else
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003266 ret = 2; /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00003267 }
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003268 xmlSchemaFreeValue(p1);
3269 xmlSchemaFreeValue(q1);
3270 xmlSchemaFreeValue(q2);
3271 if (ret != 0)
3272 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003273 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00003274 } else {
3275 xmlSchemaFreeValue(p1);
3276 xmlSchemaFreeValue(q1);
3277 }
Daniel Veillard5a872412002-05-22 06:40:27 +00003278 }
3279 } else if (y->value.date.tz_flag) {
3280 q1 = xmlSchemaDateNormalize(y, 0);
3281 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
3282
3283 /* normalize x - 14:00 */
3284 p1 = xmlSchemaDateNormalize(x, -(14 * SECS_PER_HOUR));
3285 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3286
Daniel Veillardfdc91562002-07-01 21:52:03 +00003287 if (p1d < q1d) {
3288 xmlSchemaFreeValue(p1);
3289 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003290 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003291 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003292 double sec;
3293
3294 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00003295 if (sec < 0.0) {
3296 xmlSchemaFreeValue(p1);
3297 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003298 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003299 } else {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003300 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003301 /* normalize x + 14:00 */
3302 p2 = xmlSchemaDateNormalize(x, (14 * SECS_PER_HOUR));
3303 p2d = _xmlSchemaDateCastYMToDays(p2) + p2->value.date.day;
3304
Daniel Veillard6560a422003-03-27 21:25:38 +00003305 if (p2d > q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003306 ret = 1;
Daniel Veillard6560a422003-03-27 21:25:38 +00003307 } else if (p2d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003308 sec = TIME_TO_NUMBER(p2) - TIME_TO_NUMBER(q1);
3309 if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003310 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003311 else
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003312 ret = 2; /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00003313 }
Daniel Veillard6560a422003-03-27 21:25:38 +00003314 xmlSchemaFreeValue(p1);
3315 xmlSchemaFreeValue(q1);
3316 xmlSchemaFreeValue(p2);
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003317 if (ret != 0)
3318 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003319 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00003320 } else {
3321 xmlSchemaFreeValue(p1);
3322 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003323 }
3324 }
3325
3326 /*
3327 * if the same type then calculate the difference
3328 */
3329 if (x->type == y->type) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003330 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003331 q1 = xmlSchemaDateNormalize(y, 0);
3332 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
3333
3334 p1 = xmlSchemaDateNormalize(x, 0);
3335 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3336
Daniel Veillardfdc91562002-07-01 21:52:03 +00003337 if (p1d < q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003338 ret = -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003339 } else if (p1d > q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003340 ret = 1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003341 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00003342 double sec;
3343
3344 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
3345 if (sec < 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003346 ret = -1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003347 else if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003348 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003349
3350 }
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003351 xmlSchemaFreeValue(p1);
3352 xmlSchemaFreeValue(q1);
3353 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003354 }
3355
3356 switch (x->type) {
3357 case XML_SCHEMAS_DATETIME:
3358 xmask = 0xf;
3359 break;
3360 case XML_SCHEMAS_DATE:
3361 xmask = 0x7;
3362 break;
3363 case XML_SCHEMAS_GYEAR:
3364 xmask = 0x1;
3365 break;
3366 case XML_SCHEMAS_GMONTH:
3367 xmask = 0x2;
3368 break;
3369 case XML_SCHEMAS_GDAY:
3370 xmask = 0x3;
3371 break;
3372 case XML_SCHEMAS_GYEARMONTH:
3373 xmask = 0x3;
3374 break;
3375 case XML_SCHEMAS_GMONTHDAY:
3376 xmask = 0x6;
3377 break;
3378 case XML_SCHEMAS_TIME:
3379 xmask = 0x8;
3380 break;
3381 default:
3382 xmask = 0;
3383 break;
3384 }
3385
3386 switch (y->type) {
3387 case XML_SCHEMAS_DATETIME:
3388 ymask = 0xf;
3389 break;
3390 case XML_SCHEMAS_DATE:
3391 ymask = 0x7;
3392 break;
3393 case XML_SCHEMAS_GYEAR:
3394 ymask = 0x1;
3395 break;
3396 case XML_SCHEMAS_GMONTH:
3397 ymask = 0x2;
3398 break;
3399 case XML_SCHEMAS_GDAY:
3400 ymask = 0x3;
3401 break;
3402 case XML_SCHEMAS_GYEARMONTH:
3403 ymask = 0x3;
3404 break;
3405 case XML_SCHEMAS_GMONTHDAY:
3406 ymask = 0x6;
3407 break;
3408 case XML_SCHEMAS_TIME:
3409 ymask = 0x8;
3410 break;
3411 default:
3412 ymask = 0;
3413 break;
3414 }
3415
3416 xor_mask = xmask ^ ymask; /* mark type differences */
3417 and_mask = xmask & ymask; /* mark field specification */
3418
3419 /* year */
3420 if (xor_mask & 1)
3421 return 2; /* indeterminate */
3422 else if (and_mask & 1) {
3423 if (x->value.date.year < y->value.date.year)
3424 return -1;
3425 else if (x->value.date.year > y->value.date.year)
3426 return 1;
3427 }
3428
3429 /* month */
3430 if (xor_mask & 2)
3431 return 2; /* indeterminate */
3432 else if (and_mask & 2) {
3433 if (x->value.date.mon < y->value.date.mon)
3434 return -1;
3435 else if (x->value.date.mon > y->value.date.mon)
3436 return 1;
3437 }
3438
3439 /* day */
3440 if (xor_mask & 4)
3441 return 2; /* indeterminate */
3442 else if (and_mask & 4) {
3443 if (x->value.date.day < y->value.date.day)
3444 return -1;
3445 else if (x->value.date.day > y->value.date.day)
3446 return 1;
3447 }
3448
3449 /* time */
3450 if (xor_mask & 8)
3451 return 2; /* indeterminate */
3452 else if (and_mask & 8) {
3453 if (x->value.date.hour < y->value.date.hour)
3454 return -1;
3455 else if (x->value.date.hour > y->value.date.hour)
3456 return 1;
3457 else if (x->value.date.min < y->value.date.min)
3458 return -1;
3459 else if (x->value.date.min > y->value.date.min)
3460 return 1;
3461 else if (x->value.date.sec < y->value.date.sec)
3462 return -1;
3463 else if (x->value.date.sec > y->value.date.sec)
3464 return 1;
3465 }
3466
Daniel Veillard070803b2002-05-03 07:29:38 +00003467 return 0;
3468}
3469
3470/**
Daniel Veillardc4c21552003-03-29 10:53:38 +00003471 * xmlSchemaCompareNormStrings:
3472 * @x: a first string value
3473 * @y: a second string value
3474 *
3475 * Compare 2 string for their normalized values.
3476 *
3477 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
3478 * case of error
3479 */
3480static int
3481xmlSchemaCompareNormStrings(xmlSchemaValPtr x, xmlSchemaValPtr y) {
3482 const xmlChar *utf1;
3483 const xmlChar *utf2;
3484 int tmp;
3485
3486 if ((x == NULL) || (y == NULL))
3487 return(-2);
3488 utf1 = x->value.str;
3489 utf2 = y->value.str;
3490
William M. Brack76e95df2003-10-18 16:20:14 +00003491 while (IS_BLANK_CH(*utf1)) utf1++;
3492 while (IS_BLANK_CH(*utf2)) utf2++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003493 while ((*utf1 != 0) && (*utf2 != 0)) {
William M. Brack76e95df2003-10-18 16:20:14 +00003494 if (IS_BLANK_CH(*utf1)) {
3495 if (!IS_BLANK_CH(*utf2)) {
Daniel Veillardc4c21552003-03-29 10:53:38 +00003496 tmp = *utf1 - *utf2;
3497 return(tmp);
3498 }
William M. Brack76e95df2003-10-18 16:20:14 +00003499 while (IS_BLANK_CH(*utf1)) utf1++;
3500 while (IS_BLANK_CH(*utf2)) utf2++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003501 } else {
3502 tmp = *utf1++ - *utf2++;
3503 if (tmp < 0)
3504 return(-1);
3505 if (tmp > 0)
3506 return(1);
3507 }
3508 }
3509 if (*utf1 != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00003510 while (IS_BLANK_CH(*utf1)) utf1++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003511 if (*utf1 != 0)
3512 return(1);
3513 }
3514 if (*utf2 != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00003515 while (IS_BLANK_CH(*utf2)) utf2++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003516 if (*utf2 != 0)
3517 return(-1);
3518 }
3519 return(0);
3520}
3521
3522/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003523 * xmlSchemaCompareFloats:
3524 * @x: a first float or double value
3525 * @y: a second float or double value
3526 *
3527 * Compare 2 values
3528 *
3529 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3530 * case of error
3531 */
3532static int
3533xmlSchemaCompareFloats(xmlSchemaValPtr x, xmlSchemaValPtr y) {
3534 double d1, d2;
3535
3536 if ((x == NULL) || (y == NULL))
3537 return(-2);
3538
3539 /*
3540 * Cast everything to doubles.
3541 */
3542 if (x->type == XML_SCHEMAS_DOUBLE)
3543 d1 = x->value.d;
3544 else if (x->type == XML_SCHEMAS_FLOAT)
3545 d1 = x->value.f;
3546 else
3547 return(-2);
3548
3549 if (y->type == XML_SCHEMAS_DOUBLE)
3550 d2 = y->value.d;
3551 else if (y->type == XML_SCHEMAS_FLOAT)
3552 d2 = y->value.f;
3553 else
3554 return(-2);
3555
3556 /*
3557 * Check for special cases.
3558 */
3559 if (xmlXPathIsNaN(d1)) {
3560 if (xmlXPathIsNaN(d2))
3561 return(0);
3562 return(1);
3563 }
3564 if (xmlXPathIsNaN(d2))
3565 return(-1);
3566 if (d1 == xmlXPathPINF) {
3567 if (d2 == xmlXPathPINF)
3568 return(0);
3569 return(1);
3570 }
3571 if (d2 == xmlXPathPINF)
3572 return(-1);
3573 if (d1 == xmlXPathNINF) {
3574 if (d2 == xmlXPathNINF)
3575 return(0);
3576 return(-1);
3577 }
3578 if (d2 == xmlXPathNINF)
3579 return(1);
3580
3581 /*
3582 * basic tests, the last one we should have equality, but
3583 * portability is more important than speed and handling
3584 * NaN or Inf in a portable way is always a challenge, so ...
3585 */
3586 if (d1 < d2)
3587 return(-1);
3588 if (d1 > d2)
3589 return(1);
3590 if (d1 == d2)
3591 return(0);
3592 return(2);
3593}
3594
3595/**
Daniel Veillard4255d502002-04-16 15:50:10 +00003596 * xmlSchemaCompareValues:
3597 * @x: a first value
3598 * @y: a second value
3599 *
3600 * Compare 2 values
3601 *
Daniel Veillard5a872412002-05-22 06:40:27 +00003602 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3603 * case of error
Daniel Veillard4255d502002-04-16 15:50:10 +00003604 */
Daniel Veillard80b19092003-03-28 13:29:53 +00003605int
Daniel Veillard4255d502002-04-16 15:50:10 +00003606xmlSchemaCompareValues(xmlSchemaValPtr x, xmlSchemaValPtr y) {
3607 if ((x == NULL) || (y == NULL))
3608 return(-2);
3609
3610 switch (x->type) {
Daniel Veillard80b19092003-03-28 13:29:53 +00003611 case XML_SCHEMAS_UNKNOWN:
William M. Brack2f2a6632004-08-20 23:09:47 +00003612 case XML_SCHEMAS_ANYTYPE:
3613 case XML_SCHEMAS_ANYSIMPLETYPE:
Daniel Veillard80b19092003-03-28 13:29:53 +00003614 return(-2);
3615 case XML_SCHEMAS_INTEGER:
3616 case XML_SCHEMAS_NPINTEGER:
3617 case XML_SCHEMAS_NINTEGER:
3618 case XML_SCHEMAS_NNINTEGER:
3619 case XML_SCHEMAS_PINTEGER:
3620 case XML_SCHEMAS_INT:
3621 case XML_SCHEMAS_UINT:
3622 case XML_SCHEMAS_LONG:
3623 case XML_SCHEMAS_ULONG:
3624 case XML_SCHEMAS_SHORT:
3625 case XML_SCHEMAS_USHORT:
3626 case XML_SCHEMAS_BYTE:
3627 case XML_SCHEMAS_UBYTE:
Daniel Veillard4255d502002-04-16 15:50:10 +00003628 case XML_SCHEMAS_DECIMAL:
Daniel Veillard80b19092003-03-28 13:29:53 +00003629 if (y->type == x->type)
3630 return(xmlSchemaCompareDecimals(x, y));
3631 if ((y->type == XML_SCHEMAS_DECIMAL) ||
3632 (y->type == XML_SCHEMAS_INTEGER) ||
3633 (y->type == XML_SCHEMAS_NPINTEGER) ||
3634 (y->type == XML_SCHEMAS_NINTEGER) ||
3635 (y->type == XML_SCHEMAS_NNINTEGER) ||
3636 (y->type == XML_SCHEMAS_PINTEGER) ||
3637 (y->type == XML_SCHEMAS_INT) ||
3638 (y->type == XML_SCHEMAS_UINT) ||
3639 (y->type == XML_SCHEMAS_LONG) ||
3640 (y->type == XML_SCHEMAS_ULONG) ||
3641 (y->type == XML_SCHEMAS_SHORT) ||
3642 (y->type == XML_SCHEMAS_USHORT) ||
3643 (y->type == XML_SCHEMAS_BYTE) ||
3644 (y->type == XML_SCHEMAS_UBYTE))
Daniel Veillard4255d502002-04-16 15:50:10 +00003645 return(xmlSchemaCompareDecimals(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00003646 return(-2);
Daniel Veillard070803b2002-05-03 07:29:38 +00003647 case XML_SCHEMAS_DURATION:
3648 if (y->type == XML_SCHEMAS_DURATION)
3649 return(xmlSchemaCompareDurations(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00003650 return(-2);
3651 case XML_SCHEMAS_TIME:
3652 case XML_SCHEMAS_GDAY:
3653 case XML_SCHEMAS_GMONTH:
3654 case XML_SCHEMAS_GMONTHDAY:
3655 case XML_SCHEMAS_GYEAR:
3656 case XML_SCHEMAS_GYEARMONTH:
3657 case XML_SCHEMAS_DATE:
3658 case XML_SCHEMAS_DATETIME:
3659 if ((y->type == XML_SCHEMAS_DATETIME) ||
3660 (y->type == XML_SCHEMAS_TIME) ||
3661 (y->type == XML_SCHEMAS_GDAY) ||
3662 (y->type == XML_SCHEMAS_GMONTH) ||
3663 (y->type == XML_SCHEMAS_GMONTHDAY) ||
3664 (y->type == XML_SCHEMAS_GYEAR) ||
3665 (y->type == XML_SCHEMAS_DATE) ||
3666 (y->type == XML_SCHEMAS_GYEARMONTH))
3667 return (xmlSchemaCompareDates(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00003668 return (-2);
Daniel Veillard80b19092003-03-28 13:29:53 +00003669 case XML_SCHEMAS_NORMSTRING:
Daniel Veillard80b19092003-03-28 13:29:53 +00003670 case XML_SCHEMAS_TOKEN:
3671 case XML_SCHEMAS_LANGUAGE:
3672 case XML_SCHEMAS_NMTOKEN:
Daniel Veillard80b19092003-03-28 13:29:53 +00003673 case XML_SCHEMAS_NAME:
Daniel Veillard80b19092003-03-28 13:29:53 +00003674 case XML_SCHEMAS_NCNAME:
3675 case XML_SCHEMAS_ID:
3676 case XML_SCHEMAS_IDREF:
Daniel Veillard80b19092003-03-28 13:29:53 +00003677 case XML_SCHEMAS_ENTITY:
Daniel Veillard80b19092003-03-28 13:29:53 +00003678 case XML_SCHEMAS_NOTATION:
3679 case XML_SCHEMAS_ANYURI:
Daniel Veillardc4c21552003-03-29 10:53:38 +00003680 if ((y->type == XML_SCHEMAS_NORMSTRING) ||
3681 (y->type == XML_SCHEMAS_TOKEN) ||
3682 (y->type == XML_SCHEMAS_LANGUAGE) ||
3683 (y->type == XML_SCHEMAS_NMTOKEN) ||
3684 (y->type == XML_SCHEMAS_NAME) ||
3685 (y->type == XML_SCHEMAS_QNAME) ||
3686 (y->type == XML_SCHEMAS_NCNAME) ||
3687 (y->type == XML_SCHEMAS_ID) ||
3688 (y->type == XML_SCHEMAS_IDREF) ||
3689 (y->type == XML_SCHEMAS_ENTITY) ||
3690 (y->type == XML_SCHEMAS_NOTATION) ||
3691 (y->type == XML_SCHEMAS_ANYURI))
3692 return (xmlSchemaCompareNormStrings(x, y));
3693 return (-2);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003694 case XML_SCHEMAS_QNAME:
3695 if (y->type == XML_SCHEMAS_QNAME) {
3696 if ((xmlStrEqual(x->value.qname.name, y->value.qname.name)) &&
3697 (xmlStrEqual(x->value.qname.uri, y->value.qname.uri)))
3698 return(0);
3699 return(2);
3700 }
3701 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00003702 case XML_SCHEMAS_FLOAT:
3703 case XML_SCHEMAS_DOUBLE:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003704 if ((y->type == XML_SCHEMAS_FLOAT) ||
3705 (y->type == XML_SCHEMAS_DOUBLE))
3706 return (xmlSchemaCompareFloats(x, y));
3707 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00003708 case XML_SCHEMAS_BOOLEAN:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003709 if (y->type == XML_SCHEMAS_BOOLEAN) {
3710 if (x->value.b == y->value.b)
3711 return(0);
3712 if (x->value.b == 0)
3713 return(-1);
3714 return(1);
3715 }
3716 return (-2);
Daniel Veillard560c2a42003-07-06 21:13:49 +00003717 case XML_SCHEMAS_HEXBINARY:
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00003718 if (y->type == XML_SCHEMAS_HEXBINARY) {
3719 if (x->value.hex.total == y->value.hex.total) {
3720 int ret = xmlStrcmp(x->value.hex.str, y->value.hex.str);
3721 if (ret > 0)
3722 return(1);
3723 else if (ret == 0)
3724 return(0);
3725 }
3726 else if (x->value.hex.total > y->value.hex.total)
3727 return(1);
3728
3729 return(-1);
3730 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00003731 return (-2);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003732 case XML_SCHEMAS_BASE64BINARY:
3733 if (y->type == XML_SCHEMAS_BASE64BINARY) {
3734 if (x->value.base64.total == y->value.base64.total) {
3735 int ret = xmlStrcmp(x->value.base64.str,
3736 y->value.base64.str);
3737 if (ret > 0)
3738 return(1);
3739 else if (ret == 0)
3740 return(0);
3741 }
3742 else if (x->value.base64.total > y->value.base64.total)
3743 return(1);
3744 else
3745 return(-1);
3746 }
3747 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00003748 case XML_SCHEMAS_STRING:
3749 case XML_SCHEMAS_IDREFS:
3750 case XML_SCHEMAS_ENTITIES:
3751 case XML_SCHEMAS_NMTOKENS:
3752 TODO
3753 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00003754 }
Daniel Veillard5a872412002-05-22 06:40:27 +00003755 return -2;
Daniel Veillard4255d502002-04-16 15:50:10 +00003756}
3757
3758/**
Daniel Veillardc4c21552003-03-29 10:53:38 +00003759 * xmlSchemaNormLen:
3760 * @value: a string
3761 *
3762 * Computes the UTF8 length of the normalized value of the string
3763 *
3764 * Returns the length or -1 in case of error.
3765 */
3766static int
3767xmlSchemaNormLen(const xmlChar *value) {
3768 const xmlChar *utf;
3769 int ret = 0;
3770
3771 if (value == NULL)
3772 return(-1);
3773 utf = value;
William M. Brack76e95df2003-10-18 16:20:14 +00003774 while (IS_BLANK_CH(*utf)) utf++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003775 while (*utf != 0) {
3776 if (utf[0] & 0x80) {
3777 if ((utf[1] & 0xc0) != 0x80)
3778 return(-1);
3779 if ((utf[0] & 0xe0) == 0xe0) {
3780 if ((utf[2] & 0xc0) != 0x80)
3781 return(-1);
3782 if ((utf[0] & 0xf0) == 0xf0) {
3783 if ((utf[0] & 0xf8) != 0xf0 || (utf[3] & 0xc0) != 0x80)
3784 return(-1);
3785 utf += 4;
3786 } else {
3787 utf += 3;
3788 }
3789 } else {
3790 utf += 2;
3791 }
William M. Brack76e95df2003-10-18 16:20:14 +00003792 } else if (IS_BLANK_CH(*utf)) {
3793 while (IS_BLANK_CH(*utf)) utf++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003794 if (*utf == 0)
3795 break;
3796 } else {
3797 utf++;
3798 }
3799 ret++;
3800 }
3801 return(ret);
3802}
3803
Daniel Veillard6927b102004-10-27 17:29:04 +00003804/**
3805 * xmlSchemaGetFacetValueAsULong:
3806 * @facet: an schemas type facet
3807 *
3808 * Extract the value of a facet
3809 *
3810 * Returns the value as a long
3811 */
Daniel Veillardc0826a72004-08-10 14:17:33 +00003812unsigned long
3813xmlSchemaGetFacetValueAsULong(xmlSchemaFacetPtr facet)
3814{
3815 /*
3816 * TODO: Check if this is a decimal.
3817 */
William M. Brack094dd862004-11-14 14:28:34 +00003818 if (facet == NULL)
3819 return 0;
Daniel Veillardc0826a72004-08-10 14:17:33 +00003820 return ((unsigned long) facet->val->value.decimal.lo);
3821}
3822
Daniel Veillardc4c21552003-03-29 10:53:38 +00003823/**
Daniel Veillard01fa6152004-06-29 17:04:39 +00003824 * xmlSchemaValidateListSimpleTypeFacet:
3825 * @facet: the facet to check
3826 * @value: the lexical repr of the value to validate
3827 * @actualLen: the number of list items
3828 * @expectedLen: the resulting expected number of list items
3829 *
3830 * Checks the value of a list simple type against a facet.
3831 *
3832 * Returns 0 if the value is valid, a positive error code
3833 * number otherwise and -1 in case of an internal error.
3834 */
3835int
3836xmlSchemaValidateListSimpleTypeFacet(xmlSchemaFacetPtr facet,
3837 const xmlChar *value,
3838 unsigned long actualLen,
3839 unsigned long *expectedLen)
3840{
Daniel Veillardce682bc2004-11-05 17:22:25 +00003841 if (facet == NULL)
3842 return(-1);
Daniel Veillard01fa6152004-06-29 17:04:39 +00003843 /*
3844 * TODO: Check if this will work with large numbers.
3845 * (compare value.decimal.mi and value.decimal.hi as well?).
3846 */
3847 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
3848 if (actualLen != facet->val->value.decimal.lo) {
Daniel Veillardc0826a72004-08-10 14:17:33 +00003849 if (expectedLen != 0)
3850 *expectedLen = facet->val->value.decimal.lo;
Daniel Veillard01fa6152004-06-29 17:04:39 +00003851 return (XML_SCHEMAV_CVC_LENGTH_VALID);
3852 }
3853 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
3854 if (actualLen < facet->val->value.decimal.lo) {
Daniel Veillardc0826a72004-08-10 14:17:33 +00003855 if (expectedLen != 0)
3856 *expectedLen = facet->val->value.decimal.lo;
Daniel Veillard01fa6152004-06-29 17:04:39 +00003857 return (XML_SCHEMAV_CVC_MINLENGTH_VALID);
3858 }
3859 } else if (facet->type == XML_SCHEMA_FACET_MAXLENGTH) {
3860 if (actualLen > facet->val->value.decimal.lo) {
Daniel Veillardc0826a72004-08-10 14:17:33 +00003861 if (expectedLen != 0)
3862 *expectedLen = facet->val->value.decimal.lo;
Daniel Veillard01fa6152004-06-29 17:04:39 +00003863 return (XML_SCHEMAV_CVC_MAXLENGTH_VALID);
3864 }
3865 } else
3866 /*
3867 * NOTE: That we can pass NULL as xmlSchemaValPtr to
3868 * xmlSchemaValidateFacet, since the remaining facet types
3869 * are: XML_SCHEMA_FACET_PATTERN, XML_SCHEMA_FACET_ENUMERATION.
3870 */
3871 return(xmlSchemaValidateFacet(NULL, facet, value, NULL));
3872 return (0);
3873}
3874
3875/**
Daniel Veillard6927b102004-10-27 17:29:04 +00003876 * xmlSchemaValidateLengthFacet:
Daniel Veillardc0826a72004-08-10 14:17:33 +00003877 * @type: the built-in type
3878 * @facet: the facet to check
3879 * @value: the lexical repr. of the value to be validated
3880 * @val: the precomputed value
3881 * @length: the actual length of the value
3882 *
3883 * Checka a value against a "length", "minLength" and "maxLength"
3884 * facet; sets @length to the computed length of @value.
3885 *
3886 * Returns 0 if the value is valid, a positive error code
3887 * otherwise and -1 in case of an internal or API error.
3888 */
3889int
3890xmlSchemaValidateLengthFacet(xmlSchemaTypePtr type,
3891 xmlSchemaFacetPtr facet,
3892 const xmlChar *value,
3893 xmlSchemaValPtr val,
3894 unsigned long *length)
3895{
3896 unsigned int len = 0;
3897
Daniel Veillardce682bc2004-11-05 17:22:25 +00003898 if ((length == NULL) || (facet == NULL) || (type == NULL))
3899 return (-1);
Daniel Veillardc0826a72004-08-10 14:17:33 +00003900 *length = 0;
3901 if ((facet->type != XML_SCHEMA_FACET_LENGTH) &&
3902 (facet->type != XML_SCHEMA_FACET_MAXLENGTH) &&
3903 (facet->type != XML_SCHEMA_FACET_MINLENGTH))
3904 return (-1);
3905
3906 if ((facet->val == NULL) ||
3907 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
3908 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
3909 (facet->val->value.decimal.frac != 0)) {
3910 return(-1);
3911 }
3912 if ((val != NULL) && (val->type == XML_SCHEMAS_HEXBINARY))
3913 len = val->value.hex.total;
3914 else if ((val != NULL) && (val->type == XML_SCHEMAS_BASE64BINARY))
3915 len = val->value.base64.total;
3916 else {
3917 switch (type->builtInType) {
3918 case XML_SCHEMAS_IDREF:
3919 case XML_SCHEMAS_NORMSTRING:
3920 case XML_SCHEMAS_TOKEN:
3921 case XML_SCHEMAS_LANGUAGE:
3922 case XML_SCHEMAS_NMTOKEN:
3923 case XML_SCHEMAS_NAME:
3924 case XML_SCHEMAS_NCNAME:
3925 case XML_SCHEMAS_ID:
3926 len = xmlSchemaNormLen(value);
3927 break;
3928 case XML_SCHEMAS_STRING:
3929 /*
3930 * FIXME: What exactly to do with anyURI?
3931 */
3932 case XML_SCHEMAS_ANYURI:
3933 if (value != NULL)
3934 len = xmlUTF8Strlen(value);
3935 break;
3936 default:
3937 TODO
3938 }
3939 }
3940 *length = (unsigned long) len;
3941 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
3942 if (len != facet->val->value.decimal.lo)
3943 return(XML_SCHEMAV_CVC_LENGTH_VALID);
3944 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
3945 if (len < facet->val->value.decimal.lo)
3946 return(XML_SCHEMAV_CVC_MINLENGTH_VALID);
3947 } else {
3948 if (len > facet->val->value.decimal.lo)
3949 return(XML_SCHEMAV_CVC_MAXLENGTH_VALID);
3950 }
3951
3952 return (0);
3953}
3954
3955/**
3956 * xmlSchemaValidateFacet:
Daniel Veillard01c13b52002-12-10 15:19:08 +00003957 * @base: the base type
Daniel Veillard4255d502002-04-16 15:50:10 +00003958 * @facet: the facet to check
3959 * @value: the lexical repr of the value to validate
3960 * @val: the precomputed value
3961 *
3962 * Check a value against a facet condition
3963 *
3964 * Returns 0 if the element is schemas valid, a positive error code
3965 * number otherwise and -1 in case of internal or API error.
3966 */
3967int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00003968xmlSchemaValidateFacet(xmlSchemaTypePtr base ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +00003969 xmlSchemaFacetPtr facet,
Daniel Veillard4255d502002-04-16 15:50:10 +00003970 const xmlChar *value, xmlSchemaValPtr val)
3971{
3972 int ret;
3973
Daniel Veillardce682bc2004-11-05 17:22:25 +00003974 if ((facet == NULL) || (value == NULL))
3975 return(-1);
Daniel Veillard4255d502002-04-16 15:50:10 +00003976 switch (facet->type) {
3977 case XML_SCHEMA_FACET_PATTERN:
3978 ret = xmlRegexpExec(facet->regexp, value);
3979 if (ret == 1)
3980 return(0);
3981 if (ret == 0) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00003982 return(XML_SCHEMAV_CVC_PATTERN_VALID);
Daniel Veillard4255d502002-04-16 15:50:10 +00003983 }
3984 return(ret);
3985 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
3986 ret = xmlSchemaCompareValues(val, facet->val);
3987 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003988 /* TODO error code */
Daniel Veillard4255d502002-04-16 15:50:10 +00003989 return(-1);
3990 }
3991 if (ret == -1)
3992 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00003993 /* error code */
Daniel Veillard01fa6152004-06-29 17:04:39 +00003994 return(XML_SCHEMAV_CVC_MAXEXCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00003995 case XML_SCHEMA_FACET_MAXINCLUSIVE:
3996 ret = xmlSchemaCompareValues(val, facet->val);
3997 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003998 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00003999 return(-1);
4000 }
4001 if ((ret == -1) || (ret == 0))
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_MAXINCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00004005 case XML_SCHEMA_FACET_MINEXCLUSIVE:
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)
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_MINEXCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00004015 case XML_SCHEMA_FACET_MININCLUSIVE:
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) || (ret == 0))
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_MININCLUSIVE_VALID);
Daniel Veillard8651f532002-04-17 09:06:27 +00004025 case XML_SCHEMA_FACET_WHITESPACE:
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004026 /* TODO whitespaces */
Daniel Veillard01fa6152004-06-29 17:04:39 +00004027 /*
4028 * NOTE: Whitespace should be handled to normalize
4029 * the value to be validated against a the facets;
4030 * not to normalize the value in-between.
4031 */
Daniel Veillard8651f532002-04-17 09:06:27 +00004032 return(0);
Daniel Veillard88c58912002-04-23 07:12:20 +00004033 case XML_SCHEMA_FACET_ENUMERATION:
4034 if ((facet->value != NULL) &&
4035 (xmlStrEqual(facet->value, value)))
4036 return(0);
Daniel Veillard01fa6152004-06-29 17:04:39 +00004037 return(XML_SCHEMAV_CVC_ENUMERATION_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004038 case XML_SCHEMA_FACET_LENGTH:
4039 case XML_SCHEMA_FACET_MAXLENGTH:
4040 case XML_SCHEMA_FACET_MINLENGTH: {
4041 unsigned int len = 0;
4042
4043 if ((facet->val == NULL) ||
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004044 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
4045 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004046 (facet->val->value.decimal.frac != 0)) {
4047 return(-1);
4048 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00004049 if ((val != NULL) && (val->type == XML_SCHEMAS_HEXBINARY))
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004050 len = val->value.hex.total;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00004051 else if ((val != NULL) && (val->type == XML_SCHEMAS_BASE64BINARY))
4052 len = val->value.base64.total;
4053 else {
Daniel Veillard01fa6152004-06-29 17:04:39 +00004054 switch (base->builtInType) {
Daniel Veillard560c2a42003-07-06 21:13:49 +00004055 case XML_SCHEMAS_IDREF:
4056 case XML_SCHEMAS_NORMSTRING:
4057 case XML_SCHEMAS_TOKEN:
4058 case XML_SCHEMAS_LANGUAGE:
4059 case XML_SCHEMAS_NMTOKEN:
4060 case XML_SCHEMAS_NAME:
4061 case XML_SCHEMAS_NCNAME:
4062 case XML_SCHEMAS_ID:
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004063 len = xmlSchemaNormLen(value);
4064 break;
Daniel Veillard560c2a42003-07-06 21:13:49 +00004065 case XML_SCHEMAS_STRING:
Daniel Veillard01fa6152004-06-29 17:04:39 +00004066 /*
4067 * FIXME: What exactly to do with anyURI?
4068 */
4069 case XML_SCHEMAS_ANYURI:
William M. Brackfbf2c5e2004-02-03 17:55:56 +00004070 if (value != NULL)
4071 len = xmlUTF8Strlen(value);
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004072 break;
Daniel Veillard560c2a42003-07-06 21:13:49 +00004073 default:
4074 TODO
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004075 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004076 }
4077 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004078 if (len != facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004079 return(XML_SCHEMAV_CVC_LENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004080 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004081 if (len < facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004082 return(XML_SCHEMAV_CVC_MINLENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004083 } else {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004084 if (len > facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004085 return(XML_SCHEMAV_CVC_MAXLENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004086 }
4087 break;
4088 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00004089 case XML_SCHEMA_FACET_TOTALDIGITS:
4090 case XML_SCHEMA_FACET_FRACTIONDIGITS:
4091
4092 if ((facet->val == NULL) ||
4093 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
4094 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
4095 (facet->val->value.decimal.frac != 0)) {
4096 return(-1);
4097 }
4098 if ((val == NULL) ||
4099 ((val->type != XML_SCHEMAS_DECIMAL) &&
4100 (val->type != XML_SCHEMAS_INTEGER) &&
4101 (val->type != XML_SCHEMAS_NPINTEGER) &&
4102 (val->type != XML_SCHEMAS_NINTEGER) &&
4103 (val->type != XML_SCHEMAS_NNINTEGER) &&
4104 (val->type != XML_SCHEMAS_PINTEGER) &&
4105 (val->type != XML_SCHEMAS_INT) &&
4106 (val->type != XML_SCHEMAS_UINT) &&
4107 (val->type != XML_SCHEMAS_LONG) &&
4108 (val->type != XML_SCHEMAS_ULONG) &&
4109 (val->type != XML_SCHEMAS_SHORT) &&
4110 (val->type != XML_SCHEMAS_USHORT) &&
4111 (val->type != XML_SCHEMAS_BYTE) &&
4112 (val->type != XML_SCHEMAS_UBYTE))) {
4113 return(-1);
4114 }
4115 if (facet->type == XML_SCHEMA_FACET_TOTALDIGITS) {
4116 if (val->value.decimal.total > facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004117 return(XML_SCHEMAV_CVC_TOTALDIGITS_VALID);
Daniel Veillard560c2a42003-07-06 21:13:49 +00004118
4119 } else if (facet->type == XML_SCHEMA_FACET_FRACTIONDIGITS) {
4120 if (val->value.decimal.frac > facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004121 return(XML_SCHEMAV_CVC_FRACTIONDIGITS_VALID);
Daniel Veillard560c2a42003-07-06 21:13:49 +00004122 }
4123 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00004124 default:
4125 TODO
4126 }
4127 return(0);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00004128
Daniel Veillard4255d502002-04-16 15:50:10 +00004129}
4130
4131#endif /* LIBXML_SCHEMAS_ENABLED */