blob: 84556b75c55bf4a4d273a20445a5b637904ce3b2 [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 }
1659 cur = val;
1660 /*
1661 * Split the list
1662 */
William M. Brack76e95df2003-10-18 16:20:14 +00001663 while (IS_BLANK_CH(*cur)) *cur++ = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001664 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00001665 if (IS_BLANK_CH(*cur)) {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001666 *cur = 0;
1667 cur++;
William M. Brack76e95df2003-10-18 16:20:14 +00001668 while (IS_BLANK_CH(*cur)) *cur++ = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001669 } else {
1670 nb_values++;
1671 cur++;
William M. Brack76e95df2003-10-18 16:20:14 +00001672 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001673 }
1674 }
1675 if (nb_values == 0) {
1676 if (ret != NULL) {
1677 TODO
1678 }
1679 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 }
1692 xmlFree(val);
1693 if (ret != NULL) {
1694 TODO
1695 }
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001696 if (tmp == 0)
1697 return(nb_values);
1698 return(-1);
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001699}
1700
1701/**
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001702 * xmlSchemaParseUInt:
1703 * @str: pointer to the string R/W
1704 * @llo: pointer to the low result
1705 * @lmi: pointer to the mid result
1706 * @lhi: pointer to the high result
1707 *
1708 * Parse an unsigned long into 3 fields.
1709 *
1710 * Returns the number of chars parsed or -1 if overflow of the capacity
1711 */
1712static int
1713xmlSchemaParseUInt(const xmlChar **str, unsigned long *llo,
1714 unsigned long *lmi, unsigned long *lhi) {
1715 unsigned long lo = 0, mi = 0, hi = 0;
1716 const xmlChar *tmp, *cur = *str;
1717 int ret = 0, i = 0;
1718
1719 while (*cur == '0') {
1720 ret++;
1721 cur++;
1722 }
1723 tmp = cur;
1724 while ((*tmp != 0) && (*tmp >= '0') && (*tmp <= '9')) {
1725 i++;tmp++;ret++;
1726 }
1727 if (i > 24) {
1728 *str = tmp;
1729 return(-1);
1730 }
1731 while (i > 16) {
1732 hi = hi * 10 + (*cur++ - '0');
1733 i--;
1734 }
1735 while (i > 8) {
1736 mi = mi * 10 + (*cur++ - '0');
1737 i--;
1738 }
1739 while (i > 0) {
1740 lo = lo * 10 + (*cur++ - '0');
1741 i--;
1742 }
1743
1744 *str = cur;
1745 *llo = lo;
1746 *lmi = mi;
1747 *lhi = hi;
1748 return(ret);
1749}
1750
1751/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001752 * xmlSchemaValAtomicType:
1753 * @type: the predefined type
1754 * @value: the value to check
1755 * @val: the return computed value
1756 * @node: the node containing the value
1757 * flags: flags to control the vlidation
1758 *
1759 * Check that a value conforms to the lexical space of the atomic type.
1760 * if true a value is computed and returned in @val.
Daniel Veillard01fa6152004-06-29 17:04:39 +00001761 * This checks the value space for list types as well (IDREFS, NMTOKENS).
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001762 *
1763 * Returns 0 if this validates, a positive error code number otherwise
1764 * and -1 in case of internal or API error.
1765 */
1766static int
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001767xmlSchemaValAtomicType(xmlSchemaTypePtr type, const xmlChar * value,
1768 xmlSchemaValPtr * val, xmlNodePtr node, int flags)
1769{
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001770 xmlSchemaValPtr v;
1771 xmlChar *norm = NULL;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001772 int ret = 0;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001773
1774 if (xmlSchemaTypesInitialized == 0)
Daniel Veillard01fa6152004-06-29 17:04:39 +00001775 xmlSchemaInitTypes();
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001776 if (type == NULL)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001777 return (-1);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001778
Daniel Veillardeebd6332004-08-26 10:30:44 +00001779 /*
1780 * validating a non existant text node is similar to validating
1781 * an empty one.
1782 */
1783 if (value == NULL)
1784 value = BAD_CAST "";
1785
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001786 if (val != NULL)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001787 *val = NULL;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001788 if ((flags == 0) && (value != NULL)) {
Kasimier T. Buchcik91feaf82004-11-12 14:04:58 +00001789
Daniel Veillard01fa6152004-06-29 17:04:39 +00001790 if ((type->builtInType != XML_SCHEMAS_STRING) &&
Kasimier T. Buchcik91feaf82004-11-12 14:04:58 +00001791 (type->builtInType != XML_SCHEMAS_ANYTYPE) &&
1792 (type->builtInType != XML_SCHEMAS_ANYSIMPLETYPE)) {
1793 if (type->builtInType == XML_SCHEMAS_NORMSTRING)
1794 norm = xmlSchemaWhiteSpaceReplace(value);
1795 else
1796 norm = xmlSchemaCollapseString(value);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001797 if (norm != NULL)
1798 value = norm;
1799 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001800 }
1801
Daniel Veillard01fa6152004-06-29 17:04:39 +00001802 switch (type->builtInType) {
William M. Brack2f2a6632004-08-20 23:09:47 +00001803 case XML_SCHEMAS_UNKNOWN:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001804 goto error;
William M. Brack2f2a6632004-08-20 23:09:47 +00001805 case XML_SCHEMAS_ANYTYPE:
1806 case XML_SCHEMAS_ANYSIMPLETYPE:
1807 goto return0;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001808 case XML_SCHEMAS_STRING:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001809 goto return0;
Daniel Veillard1516d5b2004-01-22 07:27:45 +00001810 case XML_SCHEMAS_NORMSTRING:{
1811 const xmlChar *cur = value;
1812
1813 while (*cur != 0) {
1814 if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) {
1815 goto return1;
1816 } else {
1817 cur++;
1818 }
1819 }
1820 if (val != NULL) {
1821 v = xmlSchemaNewValue(XML_SCHEMAS_NORMSTRING);
1822 if (v != NULL) {
1823 v->value.str = xmlStrdup(value);
1824 *val = v;
1825 } else {
1826 goto error;
1827 }
1828 }
1829 goto return0;
1830 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001831 case XML_SCHEMAS_DECIMAL:{
1832 const xmlChar *cur = value, *tmp;
1833 unsigned int frac = 0, len, neg = 0;
1834 unsigned long base = 0;
1835
1836 if (cur == NULL)
1837 goto return1;
1838 if (*cur == '+')
1839 cur++;
1840 else if (*cur == '-') {
1841 neg = 1;
1842 cur++;
1843 }
1844 tmp = cur;
1845 while ((*cur >= '0') && (*cur <= '9')) {
1846 base = base * 10 + (*cur - '0');
1847 cur++;
1848 }
1849 len = cur - tmp;
1850 if (*cur == '.') {
1851 cur++;
1852 tmp = cur;
1853 while ((*cur >= '0') && (*cur <= '9')) {
1854 base = base * 10 + (*cur - '0');
1855 cur++;
1856 }
1857 frac = cur - tmp;
1858 }
1859 if (*cur != 0)
1860 goto return1;
1861 if (val != NULL) {
1862 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
1863 if (v != NULL) {
1864 v->value.decimal.lo = base;
1865 v->value.decimal.sign = neg;
1866 v->value.decimal.frac = frac;
1867 v->value.decimal.total = frac + len;
1868 *val = v;
1869 }
1870 }
1871 goto return0;
1872 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001873 case XML_SCHEMAS_TIME:
1874 case XML_SCHEMAS_GDAY:
1875 case XML_SCHEMAS_GMONTH:
1876 case XML_SCHEMAS_GMONTHDAY:
1877 case XML_SCHEMAS_GYEAR:
1878 case XML_SCHEMAS_GYEARMONTH:
1879 case XML_SCHEMAS_DATE:
1880 case XML_SCHEMAS_DATETIME:
Daniel Veillard01fa6152004-06-29 17:04:39 +00001881 ret = xmlSchemaValidateDates(type->builtInType, value, val);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001882 break;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001883 case XML_SCHEMAS_DURATION:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001884 ret = xmlSchemaValidateDuration(type, value, val);
1885 break;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001886 case XML_SCHEMAS_FLOAT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001887 case XML_SCHEMAS_DOUBLE:{
1888 const xmlChar *cur = value;
1889 int neg = 0;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001890
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001891 if (cur == NULL)
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00001892 goto return1;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001893 if ((cur[0] == 'N') && (cur[1] == 'a') && (cur[2] == 'N')) {
1894 cur += 3;
1895 if (*cur != 0)
1896 goto return1;
1897 if (val != NULL) {
1898 if (type == xmlSchemaTypeFloatDef) {
1899 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1900 if (v != NULL) {
1901 v->value.f = (float) xmlXPathNAN;
1902 } else {
1903 xmlSchemaFreeValue(v);
1904 goto error;
1905 }
1906 } else {
1907 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1908 if (v != NULL) {
1909 v->value.d = xmlXPathNAN;
1910 } else {
1911 xmlSchemaFreeValue(v);
1912 goto error;
1913 }
1914 }
1915 *val = v;
1916 }
1917 goto return0;
1918 }
1919 if (*cur == '-') {
1920 neg = 1;
1921 cur++;
1922 }
1923 if ((cur[0] == 'I') && (cur[1] == 'N') && (cur[2] == 'F')) {
1924 cur += 3;
1925 if (*cur != 0)
1926 goto return1;
1927 if (val != NULL) {
1928 if (type == xmlSchemaTypeFloatDef) {
1929 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1930 if (v != NULL) {
1931 if (neg)
1932 v->value.f = (float) xmlXPathNINF;
1933 else
1934 v->value.f = (float) xmlXPathPINF;
1935 } else {
1936 xmlSchemaFreeValue(v);
1937 goto error;
1938 }
1939 } else {
1940 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1941 if (v != NULL) {
1942 if (neg)
1943 v->value.d = xmlXPathNINF;
1944 else
1945 v->value.d = xmlXPathPINF;
1946 } else {
1947 xmlSchemaFreeValue(v);
1948 goto error;
1949 }
1950 }
1951 *val = v;
1952 }
1953 goto return0;
1954 }
1955 if ((neg == 0) && (*cur == '+'))
1956 cur++;
1957 if ((cur[0] == 0) || (cur[0] == '+') || (cur[0] == '-'))
1958 goto return1;
1959 while ((*cur >= '0') && (*cur <= '9')) {
1960 cur++;
1961 }
1962 if (*cur == '.') {
1963 cur++;
1964 while ((*cur >= '0') && (*cur <= '9'))
1965 cur++;
1966 }
1967 if ((*cur == 'e') || (*cur == 'E')) {
1968 cur++;
1969 if ((*cur == '-') || (*cur == '+'))
1970 cur++;
1971 while ((*cur >= '0') && (*cur <= '9'))
1972 cur++;
1973 }
1974 if (*cur != 0)
1975 goto return1;
1976 if (val != NULL) {
1977 if (type == xmlSchemaTypeFloatDef) {
1978 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1979 if (v != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001980 if (sscanf((const char *) value, "%f",
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001981 &(v->value.f)) == 1) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00001982 *val = v;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001983 } else {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001984 xmlSchemaFreeValue(v);
1985 goto return1;
1986 }
1987 } else {
1988 goto error;
1989 }
1990 } else {
1991 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1992 if (v != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001993 if (sscanf((const char *) value, "%lf",
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001994 &(v->value.d)) == 1) {
1995 *val = v;
1996 } else {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001997 xmlSchemaFreeValue(v);
1998 goto return1;
1999 }
2000 } else {
2001 goto error;
2002 }
2003 }
2004 }
2005 goto return0;
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00002006 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002007 case XML_SCHEMAS_BOOLEAN:{
2008 const xmlChar *cur = value;
2009
2010 if ((cur[0] == '0') && (cur[1] == 0))
2011 ret = 0;
2012 else if ((cur[0] == '1') && (cur[1] == 0))
2013 ret = 1;
2014 else if ((cur[0] == 't') && (cur[1] == 'r')
2015 && (cur[2] == 'u') && (cur[3] == 'e')
2016 && (cur[4] == 0))
2017 ret = 1;
2018 else if ((cur[0] == 'f') && (cur[1] == 'a')
2019 && (cur[2] == 'l') && (cur[3] == 's')
2020 && (cur[4] == 'e') && (cur[5] == 0))
2021 ret = 0;
2022 else
2023 goto return1;
2024 if (val != NULL) {
2025 v = xmlSchemaNewValue(XML_SCHEMAS_BOOLEAN);
2026 if (v != NULL) {
2027 v->value.b = ret;
2028 *val = v;
2029 } else {
2030 goto error;
2031 }
2032 }
2033 goto return0;
2034 }
2035 case XML_SCHEMAS_TOKEN:{
2036 const xmlChar *cur = value;
2037
William M. Brack76e95df2003-10-18 16:20:14 +00002038 if (IS_BLANK_CH(*cur))
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002039 goto return1;
2040
2041 while (*cur != 0) {
2042 if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) {
2043 goto return1;
2044 } else if (*cur == ' ') {
2045 cur++;
2046 if (*cur == 0)
2047 goto return1;
2048 if (*cur == ' ')
2049 goto return1;
2050 } else {
2051 cur++;
2052 }
2053 }
2054 if (val != NULL) {
2055 v = xmlSchemaNewValue(XML_SCHEMAS_TOKEN);
2056 if (v != NULL) {
2057 v->value.str = xmlStrdup(value);
2058 *val = v;
2059 } else {
2060 goto error;
2061 }
2062 }
2063 goto return0;
2064 }
2065 case XML_SCHEMAS_LANGUAGE:
2066 if (xmlCheckLanguageID(value) == 1) {
2067 if (val != NULL) {
2068 v = xmlSchemaNewValue(XML_SCHEMAS_LANGUAGE);
2069 if (v != NULL) {
2070 v->value.str = xmlStrdup(value);
2071 *val = v;
2072 } else {
2073 goto error;
2074 }
2075 }
2076 goto return0;
2077 }
2078 goto return1;
2079 case XML_SCHEMAS_NMTOKEN:
2080 if (xmlValidateNMToken(value, 1) == 0) {
2081 if (val != NULL) {
2082 v = xmlSchemaNewValue(XML_SCHEMAS_NMTOKEN);
2083 if (v != NULL) {
2084 v->value.str = xmlStrdup(value);
2085 *val = v;
2086 } else {
2087 goto error;
2088 }
2089 }
2090 goto return0;
2091 }
2092 goto return1;
2093 case XML_SCHEMAS_NMTOKENS:
2094 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeNmtokenDef,
2095 value, val, node);
2096 if (ret > 0)
2097 ret = 0;
2098 else
2099 ret = 1;
2100 goto done;
2101 case XML_SCHEMAS_NAME:
2102 ret = xmlValidateName(value, 1);
2103 if ((ret == 0) && (val != NULL)) {
2104 TODO;
2105 }
2106 goto done;
2107 case XML_SCHEMAS_QNAME:{
2108 xmlChar *uri = NULL;
2109 xmlChar *local = NULL;
2110
2111 ret = xmlValidateQName(value, 1);
2112 if ((ret == 0) && (node != NULL)) {
2113 xmlChar *prefix;
2114
2115 local = xmlSplitQName2(value, &prefix);
2116 if (prefix != NULL) {
2117 xmlNsPtr ns;
2118
2119 ns = xmlSearchNs(node->doc, node, prefix);
2120 if (ns == NULL)
2121 ret = 1;
2122 else if (val != NULL)
2123 uri = xmlStrdup(ns->href);
2124 }
2125 if ((local != NULL) && ((val == NULL) || (ret != 0)))
2126 xmlFree(local);
2127 if (prefix != NULL)
2128 xmlFree(prefix);
2129 }
2130 if ((ret == 0) && (val != NULL)) {
2131 v = xmlSchemaNewValue(XML_SCHEMAS_QNAME);
2132 if (v != NULL) {
2133 if (local != NULL)
2134 v->value.qname.name = local;
2135 else
2136 v->value.qname.name = xmlStrdup(value);
2137 if (uri != NULL)
2138 v->value.qname.uri = uri;
2139
2140 *val = v;
2141 } else {
2142 if (local != NULL)
2143 xmlFree(local);
2144 if (uri != NULL)
2145 xmlFree(uri);
2146 goto error;
2147 }
2148 }
2149 goto done;
2150 }
2151 case XML_SCHEMAS_NCNAME:
2152 ret = xmlValidateNCName(value, 1);
2153 if ((ret == 0) && (val != NULL)) {
2154 v = xmlSchemaNewValue(XML_SCHEMAS_NCNAME);
2155 if (v != NULL) {
2156 v->value.str = xmlStrdup(value);
2157 *val = v;
2158 } else {
2159 goto error;
2160 }
2161 }
2162 goto done;
2163 case XML_SCHEMAS_ID:
2164 ret = xmlValidateNCName(value, 1);
2165 if ((ret == 0) && (val != NULL)) {
2166 v = xmlSchemaNewValue(XML_SCHEMAS_ID);
2167 if (v != NULL) {
2168 v->value.str = xmlStrdup(value);
2169 *val = v;
2170 } else {
2171 goto error;
2172 }
2173 }
2174 if ((ret == 0) && (node != NULL) &&
2175 (node->type == XML_ATTRIBUTE_NODE)) {
2176 xmlAttrPtr attr = (xmlAttrPtr) node;
2177
2178 /*
2179 * NOTE: the IDness might have already be declared in the DTD
2180 */
2181 if (attr->atype != XML_ATTRIBUTE_ID) {
2182 xmlIDPtr res;
2183 xmlChar *strip;
2184
2185 strip = xmlSchemaStrip(value);
2186 if (strip != NULL) {
2187 res = xmlAddID(NULL, node->doc, strip, attr);
2188 xmlFree(strip);
2189 } else
2190 res = xmlAddID(NULL, node->doc, value, attr);
2191 if (res == NULL) {
2192 ret = 2;
2193 } else {
2194 attr->atype = XML_ATTRIBUTE_ID;
2195 }
2196 }
2197 }
2198 goto done;
2199 case XML_SCHEMAS_IDREF:
2200 ret = xmlValidateNCName(value, 1);
2201 if ((ret == 0) && (val != NULL)) {
2202 TODO;
2203 }
2204 if ((ret == 0) && (node != NULL) &&
2205 (node->type == XML_ATTRIBUTE_NODE)) {
2206 xmlAttrPtr attr = (xmlAttrPtr) node;
2207 xmlChar *strip;
2208
2209 strip = xmlSchemaStrip(value);
2210 if (strip != NULL) {
2211 xmlAddRef(NULL, node->doc, strip, attr);
2212 xmlFree(strip);
2213 } else
2214 xmlAddRef(NULL, node->doc, value, attr);
2215 attr->atype = XML_ATTRIBUTE_IDREF;
2216 }
2217 goto done;
2218 case XML_SCHEMAS_IDREFS:
2219 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeIdrefDef,
2220 value, val, node);
2221 if (ret < 0)
2222 ret = 2;
2223 else
2224 ret = 0;
2225 if ((ret == 0) && (node != NULL) &&
2226 (node->type == XML_ATTRIBUTE_NODE)) {
2227 xmlAttrPtr attr = (xmlAttrPtr) node;
2228
2229 attr->atype = XML_ATTRIBUTE_IDREFS;
2230 }
2231 goto done;
2232 case XML_SCHEMAS_ENTITY:{
2233 xmlChar *strip;
2234
2235 ret = xmlValidateNCName(value, 1);
2236 if ((node == NULL) || (node->doc == NULL))
2237 ret = 3;
2238 if (ret == 0) {
2239 xmlEntityPtr ent;
2240
2241 strip = xmlSchemaStrip(value);
2242 if (strip != NULL) {
2243 ent = xmlGetDocEntity(node->doc, strip);
2244 xmlFree(strip);
2245 } else {
2246 ent = xmlGetDocEntity(node->doc, value);
2247 }
2248 if ((ent == NULL) ||
2249 (ent->etype !=
2250 XML_EXTERNAL_GENERAL_UNPARSED_ENTITY))
2251 ret = 4;
2252 }
2253 if ((ret == 0) && (val != NULL)) {
2254 TODO;
2255 }
2256 if ((ret == 0) && (node != NULL) &&
2257 (node->type == XML_ATTRIBUTE_NODE)) {
2258 xmlAttrPtr attr = (xmlAttrPtr) node;
2259
2260 attr->atype = XML_ATTRIBUTE_ENTITY;
2261 }
2262 goto done;
2263 }
2264 case XML_SCHEMAS_ENTITIES:
2265 if ((node == NULL) || (node->doc == NULL))
2266 goto return3;
2267 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeEntityDef,
2268 value, val, node);
2269 if (ret <= 0)
2270 ret = 1;
2271 else
2272 ret = 0;
2273 if ((ret == 0) && (node != NULL) &&
2274 (node->type == XML_ATTRIBUTE_NODE)) {
2275 xmlAttrPtr attr = (xmlAttrPtr) node;
2276
2277 attr->atype = XML_ATTRIBUTE_ENTITIES;
2278 }
2279 goto done;
2280 case XML_SCHEMAS_NOTATION:{
2281 xmlChar *uri = NULL;
2282 xmlChar *local = NULL;
2283
2284 ret = xmlValidateQName(value, 1);
2285 if ((ret == 0) && (node != NULL)) {
2286 xmlChar *prefix;
2287
2288 local = xmlSplitQName2(value, &prefix);
2289 if (prefix != NULL) {
2290 xmlNsPtr ns;
2291
2292 ns = xmlSearchNs(node->doc, node, prefix);
2293 if (ns == NULL)
2294 ret = 1;
2295 else if (val != NULL)
2296 uri = xmlStrdup(ns->href);
2297 }
2298 if ((local != NULL) && ((val == NULL) || (ret != 0)))
2299 xmlFree(local);
2300 if (prefix != NULL)
2301 xmlFree(prefix);
2302 }
2303 if ((node == NULL) || (node->doc == NULL))
2304 ret = 3;
2305 if (ret == 0) {
2306 ret = xmlValidateNotationUse(NULL, node->doc, value);
2307 if (ret == 1)
2308 ret = 0;
2309 else
2310 ret = 1;
2311 }
2312 if ((ret == 0) && (val != NULL)) {
2313 v = xmlSchemaNewValue(XML_SCHEMAS_NOTATION);
2314 if (v != NULL) {
2315 if (local != NULL)
2316 v->value.qname.name = local;
2317 else
2318 v->value.qname.name = xmlStrdup(value);
2319 if (uri != NULL)
2320 v->value.qname.uri = uri;
2321
2322 *val = v;
2323 } else {
2324 if (local != NULL)
2325 xmlFree(local);
2326 if (uri != NULL)
2327 xmlFree(uri);
2328 goto error;
2329 }
2330 }
2331 goto done;
2332 }
2333 case XML_SCHEMAS_ANYURI:{
Daniel Veillard11c466a2004-03-14 12:20:15 +00002334 if (*value != 0) {
2335 xmlURIPtr uri = xmlParseURI((const char *) value);
2336 if (uri == NULL)
2337 goto return1;
2338 xmlFreeURI(uri);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002339 }
Daniel Veillard11c466a2004-03-14 12:20:15 +00002340
2341 if (val != NULL) {
2342 v = xmlSchemaNewValue(XML_SCHEMAS_ANYURI);
2343 if (v == NULL)
2344 goto error;
2345 v->value.str = xmlStrdup(value);
2346 *val = v;
2347 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002348 goto return0;
2349 }
2350 case XML_SCHEMAS_HEXBINARY:{
2351 const xmlChar *cur = value;
2352 xmlChar *base;
2353 int total, i = 0;
2354
Daniel Veillardf34a20e2004-08-31 08:42:17 +00002355 if (cur == NULL)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002356 goto return1;
2357
2358 while (((*cur >= '0') && (*cur <= '9')) ||
2359 ((*cur >= 'A') && (*cur <= 'F')) ||
2360 ((*cur >= 'a') && (*cur <= 'f'))) {
2361 i++;
2362 cur++;
2363 }
2364
2365 if (*cur != 0)
2366 goto return1;
2367 if ((i % 2) != 0)
2368 goto return1;
2369
2370 if (val != NULL) {
2371
2372 v = xmlSchemaNewValue(XML_SCHEMAS_HEXBINARY);
2373 if (v == NULL)
2374 goto error;
2375
2376 cur = xmlStrdup(value);
2377 if (cur == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002378 xmlSchemaTypeErrMemory(node, "allocating hexbin data");
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002379 xmlFree(v);
2380 goto return1;
2381 }
2382
2383 total = i / 2; /* number of octets */
2384
2385 base = (xmlChar *) cur;
2386 while (i-- > 0) {
2387 if (*base >= 'a')
2388 *base = *base - ('a' - 'A');
2389 base++;
2390 }
2391
2392 v->value.hex.str = (xmlChar *) cur;
2393 v->value.hex.total = total;
2394 *val = v;
2395 }
2396 goto return0;
2397 }
2398 case XML_SCHEMAS_BASE64BINARY:{
2399 /* ISSUE:
2400 *
2401 * Ignore all stray characters? (yes, currently)
2402 * Worry about long lines? (no, currently)
2403 *
2404 * rfc2045.txt:
2405 *
2406 * "The encoded output stream must be represented in lines of
2407 * no more than 76 characters each. All line breaks or other
2408 * characters not found in Table 1 must be ignored by decoding
2409 * software. In base64 data, characters other than those in
2410 * Table 1, line breaks, and other white space probably
2411 * indicate a transmission error, about which a warning
2412 * message or even a message rejection might be appropriate
2413 * under some circumstances." */
2414 const xmlChar *cur = value;
2415 xmlChar *base;
2416 int total, i = 0, pad = 0;
2417
2418 if (cur == NULL)
2419 goto return1;
2420
2421 for (; *cur; ++cur) {
2422 int decc;
2423
2424 decc = _xmlSchemaBase64Decode(*cur);
2425 if (decc < 0) ;
2426 else if (decc < 64)
2427 i++;
2428 else
2429 break;
2430 }
2431 for (; *cur; ++cur) {
2432 int decc;
2433
2434 decc = _xmlSchemaBase64Decode(*cur);
2435 if (decc < 0) ;
2436 else if (decc < 64)
2437 goto return1;
2438 if (decc == 64)
2439 pad++;
2440 }
2441
2442 /* rfc2045.txt: "Special processing is performed if fewer than
2443 * 24 bits are available at the end of the data being encoded.
2444 * A full encoding quantum is always completed at the end of a
2445 * body. When fewer than 24 input bits are available in an
2446 * input group, zero bits are added (on the right) to form an
2447 * integral number of 6-bit groups. Padding at the end of the
2448 * data is performed using the "=" character. Since all
2449 * base64 input is an integral number of octets, only the
2450 * following cases can arise: (1) the final quantum of
2451 * encoding input is an integral multiple of 24 bits; here,
2452 * the final unit of encoded output will be an integral
2453 * multiple ofindent: Standard input:701: Warning:old style
2454 * assignment ambiguity in "=*". Assuming "= *" 4 characters
2455 * with no "=" padding, (2) the final
2456 * quantum of encoding input is exactly 8 bits; here, the
2457 * final unit of encoded output will be two characters
2458 * followed by two "=" padding characters, or (3) the final
2459 * quantum of encoding input is exactly 16 bits; here, the
2460 * final unit of encoded output will be three characters
2461 * followed by one "=" padding character." */
2462
2463 total = 3 * (i / 4);
2464 if (pad == 0) {
2465 if (i % 4 != 0)
2466 goto return1;
2467 } else if (pad == 1) {
2468 int decc;
2469
2470 if (i % 4 != 3)
2471 goto return1;
2472 for (decc = _xmlSchemaBase64Decode(*cur);
2473 (decc < 0) || (decc > 63);
2474 decc = _xmlSchemaBase64Decode(*cur))
2475 --cur;
2476 /* 16bits in 24bits means 2 pad bits: nnnnnn nnmmmm mmmm00*/
2477 /* 00111100 -> 0x3c */
2478 if (decc & ~0x3c)
2479 goto return1;
2480 total += 2;
2481 } else if (pad == 2) {
2482 int decc;
2483
2484 if (i % 4 != 2)
2485 goto return1;
2486 for (decc = _xmlSchemaBase64Decode(*cur);
2487 (decc < 0) || (decc > 63);
2488 decc = _xmlSchemaBase64Decode(*cur))
2489 --cur;
2490 /* 8bits in 12bits means 4 pad bits: nnnnnn nn0000 */
2491 /* 00110000 -> 0x30 */
2492 if (decc & ~0x30)
2493 goto return1;
2494 total += 1;
2495 } else
2496 goto return1;
2497
2498 if (val != NULL) {
2499 v = xmlSchemaNewValue(XML_SCHEMAS_BASE64BINARY);
2500 if (v == NULL)
2501 goto error;
2502 base =
2503 (xmlChar *) xmlMallocAtomic((i + pad + 1) *
2504 sizeof(xmlChar));
2505 if (base == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002506 xmlSchemaTypeErrMemory(node, "allocating base64 data");
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002507 xmlFree(v);
2508 goto return1;
2509 }
2510 v->value.base64.str = base;
2511 for (cur = value; *cur; ++cur)
2512 if (_xmlSchemaBase64Decode(*cur) >= 0) {
2513 *base = *cur;
2514 ++base;
2515 }
2516 *base = 0;
2517 v->value.base64.total = total;
2518 *val = v;
2519 }
2520 goto return0;
2521 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002522 case XML_SCHEMAS_INTEGER:
2523 case XML_SCHEMAS_PINTEGER:
2524 case XML_SCHEMAS_NPINTEGER:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002525 case XML_SCHEMAS_NINTEGER:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002526 case XML_SCHEMAS_NNINTEGER:{
2527 const xmlChar *cur = value;
2528 unsigned long lo, mi, hi;
2529 int sign = 0;
2530
2531 if (cur == NULL)
2532 goto return1;
2533 if (*cur == '-') {
2534 sign = 1;
2535 cur++;
2536 } else if (*cur == '+')
2537 cur++;
2538 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2539 if (ret == 0)
2540 goto return1;
2541 if (*cur != 0)
2542 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002543 if (type->builtInType == XML_SCHEMAS_NPINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002544 if ((sign == 0) &&
2545 ((hi != 0) || (mi != 0) || (lo != 0)))
2546 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002547 } else if (type->builtInType == XML_SCHEMAS_PINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002548 if (sign == 1)
2549 goto return1;
2550 if ((hi == 0) && (mi == 0) && (lo == 0))
2551 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002552 } else if (type->builtInType == XML_SCHEMAS_NINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002553 if (sign == 0)
2554 goto return1;
2555 if ((hi == 0) && (mi == 0) && (lo == 0))
2556 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002557 } else if (type->builtInType == XML_SCHEMAS_NNINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002558 if ((sign == 1) &&
2559 ((hi != 0) || (mi != 0) || (lo != 0)))
2560 goto return1;
2561 }
2562 /*
2563 * We can store a value only if no overflow occured
2564 */
2565 if ((ret > 0) && (val != NULL)) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00002566 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002567 if (v != NULL) {
2568 v->value.decimal.lo = lo;
2569 v->value.decimal.mi = lo;
2570 v->value.decimal.hi = lo;
2571 v->value.decimal.sign = sign;
2572 v->value.decimal.frac = 0;
2573 v->value.decimal.total = cur - value;
2574 *val = v;
2575 }
2576 }
2577 goto return0;
2578 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002579 case XML_SCHEMAS_LONG:
2580 case XML_SCHEMAS_BYTE:
2581 case XML_SCHEMAS_SHORT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002582 case XML_SCHEMAS_INT:{
2583 const xmlChar *cur = value;
2584 unsigned long lo, mi, hi;
2585 int total = 0;
2586 int sign = 0;
2587
2588 if (cur == NULL)
2589 goto return1;
2590 if (*cur == '-') {
2591 sign = 1;
2592 cur++;
2593 } else if (*cur == '+')
2594 cur++;
2595 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2596 if (ret <= 0)
2597 goto return1;
2598 if (*cur != 0)
2599 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002600 if (type->builtInType == XML_SCHEMAS_LONG) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002601 if (hi >= 922) {
2602 if (hi > 922)
2603 goto return1;
2604 if (mi >= 33720368) {
2605 if (mi > 33720368)
2606 goto return1;
2607 if ((sign == 0) && (lo > 54775807))
2608 goto return1;
2609 if ((sign == 1) && (lo > 54775808))
2610 goto return1;
2611 }
2612 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002613 } else if (type->builtInType == XML_SCHEMAS_INT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002614 if (hi != 0)
2615 goto return1;
2616 if (mi >= 21) {
2617 if (mi > 21)
2618 goto return1;
2619 if ((sign == 0) && (lo > 47483647))
2620 goto return1;
2621 if ((sign == 1) && (lo > 47483648))
2622 goto return1;
2623 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002624 } else if (type->builtInType == XML_SCHEMAS_SHORT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002625 if ((mi != 0) || (hi != 0))
2626 goto return1;
2627 if ((sign == 1) && (lo > 32768))
2628 goto return1;
2629 if ((sign == 0) && (lo > 32767))
2630 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002631 } else if (type->builtInType == XML_SCHEMAS_BYTE) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002632 if ((mi != 0) || (hi != 0))
2633 goto return1;
2634 if ((sign == 1) && (lo > 128))
2635 goto return1;
2636 if ((sign == 0) && (lo > 127))
2637 goto return1;
2638 }
2639 if (val != NULL) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00002640 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002641 if (v != NULL) {
2642 v->value.decimal.lo = lo;
2643 v->value.decimal.mi = lo;
2644 v->value.decimal.hi = lo;
2645 v->value.decimal.sign = sign;
2646 v->value.decimal.frac = 0;
2647 v->value.decimal.total = total;
2648 *val = v;
2649 }
2650 }
2651 goto return0;
2652 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002653 case XML_SCHEMAS_UINT:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002654 case XML_SCHEMAS_ULONG:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002655 case XML_SCHEMAS_USHORT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002656 case XML_SCHEMAS_UBYTE:{
2657 const xmlChar *cur = value;
2658 unsigned long lo, mi, hi;
2659 int total = 0;
2660
2661 if (cur == NULL)
2662 goto return1;
2663 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2664 if (ret <= 0)
2665 goto return1;
2666 if (*cur != 0)
2667 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002668 if (type->builtInType == XML_SCHEMAS_ULONG) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002669 if (hi >= 1844) {
2670 if (hi > 1844)
2671 goto return1;
2672 if (mi >= 67440737) {
2673 if (mi > 67440737)
2674 goto return1;
2675 if (lo > 9551615)
2676 goto return1;
2677 }
2678 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002679 } else if (type->builtInType == XML_SCHEMAS_UINT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002680 if (hi != 0)
2681 goto return1;
2682 if (mi >= 42) {
2683 if (mi > 42)
2684 goto return1;
2685 if (lo > 94967295)
2686 goto return1;
2687 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002688 } else if (type->builtInType == XML_SCHEMAS_USHORT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002689 if ((mi != 0) || (hi != 0))
2690 goto return1;
2691 if (lo > 65535)
2692 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002693 } else if (type->builtInType == XML_SCHEMAS_UBYTE) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002694 if ((mi != 0) || (hi != 0))
2695 goto return1;
2696 if (lo > 255)
2697 goto return1;
2698 }
2699 if (val != NULL) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00002700 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002701 if (v != NULL) {
2702 v->value.decimal.lo = lo;
2703 v->value.decimal.mi = mi;
2704 v->value.decimal.hi = hi;
2705 v->value.decimal.sign = 0;
2706 v->value.decimal.frac = 0;
2707 v->value.decimal.total = total;
2708 *val = v;
2709 }
2710 }
2711 goto return0;
2712 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002713 }
2714
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002715 done:
2716 if (norm != NULL)
2717 xmlFree(norm);
2718 return (ret);
2719 return3:
2720 if (norm != NULL)
2721 xmlFree(norm);
2722 return (3);
2723 return1:
2724 if (norm != NULL)
2725 xmlFree(norm);
2726 return (1);
2727 return0:
2728 if (norm != NULL)
2729 xmlFree(norm);
2730 return (0);
2731 error:
2732 if (norm != NULL)
2733 xmlFree(norm);
2734 return (-1);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002735}
2736
2737/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002738 * xmlSchemaValPredefTypeNode:
Daniel Veillard4255d502002-04-16 15:50:10 +00002739 * @type: the predefined type
2740 * @value: the value to check
2741 * @val: the return computed value
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002742 * @node: the node containing the value
Daniel Veillard4255d502002-04-16 15:50:10 +00002743 *
2744 * Check that a value conforms to the lexical space of the predefined type.
2745 * if true a value is computed and returned in @val.
2746 *
2747 * Returns 0 if this validates, a positive error code number otherwise
2748 * and -1 in case of internal or API error.
2749 */
2750int
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002751xmlSchemaValPredefTypeNode(xmlSchemaTypePtr type, const xmlChar *value,
2752 xmlSchemaValPtr *val, xmlNodePtr node) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002753 return(xmlSchemaValAtomicType(type, value, val, node, 0));
Daniel Veillard4255d502002-04-16 15:50:10 +00002754}
2755
2756/**
Daniel Veillardc0826a72004-08-10 14:17:33 +00002757 * xmlSchemaValPredefTypeNodeNoNorm:
2758 * @type: the predefined type
2759 * @value: the value to check
2760 * @val: the return computed value
2761 * @node: the node containing the value
2762 *
2763 * Check that a value conforms to the lexical space of the predefined type.
2764 * if true a value is computed and returned in @val.
2765 * This one does apply any normalization to the value.
2766 *
2767 * Returns 0 if this validates, a positive error code number otherwise
2768 * and -1 in case of internal or API error.
2769 */
2770int
2771xmlSchemaValPredefTypeNodeNoNorm(xmlSchemaTypePtr type, const xmlChar *value,
2772 xmlSchemaValPtr *val, xmlNodePtr node) {
2773 return(xmlSchemaValAtomicType(type, value, val, node, 1));
2774}
2775
2776/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002777 * xmlSchemaValidatePredefinedType:
2778 * @type: the predefined type
2779 * @value: the value to check
2780 * @val: the return computed value
2781 *
2782 * Check that a value conforms to the lexical space of the predefined type.
2783 * if true a value is computed and returned in @val.
2784 *
2785 * Returns 0 if this validates, a positive error code number otherwise
2786 * and -1 in case of internal or API error.
2787 */
2788int
2789xmlSchemaValidatePredefinedType(xmlSchemaTypePtr type, const xmlChar *value,
2790 xmlSchemaValPtr *val) {
2791 return(xmlSchemaValPredefTypeNode(type, value, val, NULL));
2792}
2793
2794/**
Daniel Veillard4255d502002-04-16 15:50:10 +00002795 * xmlSchemaCompareDecimals:
2796 * @x: a first decimal value
2797 * @y: a second decimal value
2798 *
2799 * Compare 2 decimals
2800 *
2801 * Returns -1 if x < y, 0 if x == y, 1 if x > y and -2 in case of error
2802 */
2803static int
2804xmlSchemaCompareDecimals(xmlSchemaValPtr x, xmlSchemaValPtr y)
2805{
2806 xmlSchemaValPtr swp;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002807 int order = 1, p;
Daniel Veillard4255d502002-04-16 15:50:10 +00002808 unsigned long tmp;
2809
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002810 if ((x->value.decimal.sign) &&
2811 ((x->value.decimal.lo != 0) ||
2812 (x->value.decimal.mi != 0) ||
2813 (x->value.decimal.hi != 0))) {
2814 if ((y->value.decimal.sign) &&
2815 ((y->value.decimal.lo != 0) ||
2816 (y->value.decimal.mi != 0) ||
2817 (y->value.decimal.hi != 0)))
Daniel Veillard80b19092003-03-28 13:29:53 +00002818 order = -1;
2819 else
2820 return (-1);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002821 } else if ((y->value.decimal.sign) &&
2822 ((y->value.decimal.lo != 0) ||
2823 (y->value.decimal.mi != 0) ||
2824 (y->value.decimal.hi != 0))) {
Daniel Veillard4255d502002-04-16 15:50:10 +00002825 return (1);
Daniel Veillard80b19092003-03-28 13:29:53 +00002826 }
Daniel Veillard4255d502002-04-16 15:50:10 +00002827 if (x->value.decimal.frac == y->value.decimal.frac) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002828 if (x->value.decimal.hi < y->value.decimal.hi)
2829 return (-order);
Daniel Veillard01fa6152004-06-29 17:04:39 +00002830 if (x->value.decimal.hi > y->value.decimal.hi)
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002831 return (order);
2832 if (x->value.decimal.mi < y->value.decimal.mi)
2833 return (-order);
Daniel Veillard01fa6152004-06-29 17:04:39 +00002834 if (x->value.decimal.mi > y->value.decimal.mi)
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002835 return (order);
2836 if (x->value.decimal.lo < y->value.decimal.lo)
Daniel Veillard80b19092003-03-28 13:29:53 +00002837 return (-order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002838 if (x->value.decimal.lo > y->value.decimal.lo)
Daniel Veillard80b19092003-03-28 13:29:53 +00002839 return(order);
2840 return(0);
Daniel Veillard4255d502002-04-16 15:50:10 +00002841 }
2842 if (y->value.decimal.frac > x->value.decimal.frac) {
2843 swp = y;
2844 y = x;
2845 x = swp;
2846 order = -order;
2847 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002848 p = powten[x->value.decimal.frac - y->value.decimal.frac];
2849 tmp = x->value.decimal.lo / p;
2850 if (tmp > y->value.decimal.lo)
Daniel Veillard4255d502002-04-16 15:50:10 +00002851 return (order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002852 if (tmp < y->value.decimal.lo)
Daniel Veillard4255d502002-04-16 15:50:10 +00002853 return (-order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002854 tmp = y->value.decimal.lo * p;
2855 if (x->value.decimal.lo < tmp)
Daniel Veillard4255d502002-04-16 15:50:10 +00002856 return (-order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002857 if (x->value.decimal.lo == tmp)
Daniel Veillard4255d502002-04-16 15:50:10 +00002858 return (0);
2859 return (order);
2860}
2861
2862/**
Daniel Veillard070803b2002-05-03 07:29:38 +00002863 * xmlSchemaCompareDurations:
2864 * @x: a first duration value
2865 * @y: a second duration value
2866 *
2867 * Compare 2 durations
2868 *
2869 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
2870 * case of error
2871 */
2872static int
2873xmlSchemaCompareDurations(xmlSchemaValPtr x, xmlSchemaValPtr y)
2874{
2875 long carry, mon, day;
2876 double sec;
Daniel Veillard80b19092003-03-28 13:29:53 +00002877 int invert = 1;
2878 long xmon, xday, myear, minday, maxday;
Daniel Veillard070803b2002-05-03 07:29:38 +00002879 static const long dayRange [2][12] = {
2880 { 0, 28, 59, 89, 120, 150, 181, 212, 242, 273, 303, 334, },
2881 { 0, 31, 62, 92, 123, 153, 184, 215, 245, 276, 306, 337} };
2882
2883 if ((x == NULL) || (y == NULL))
Daniel Veillard5a872412002-05-22 06:40:27 +00002884 return -2;
Daniel Veillard070803b2002-05-03 07:29:38 +00002885
2886 /* months */
2887 mon = x->value.dur.mon - y->value.dur.mon;
2888
2889 /* seconds */
2890 sec = x->value.dur.sec - y->value.dur.sec;
2891 carry = (long)sec / SECS_PER_DAY;
2892 sec -= (double)(carry * SECS_PER_DAY);
2893
2894 /* days */
2895 day = x->value.dur.day - y->value.dur.day + carry;
2896
2897 /* easy test */
2898 if (mon == 0) {
2899 if (day == 0)
2900 if (sec == 0.0)
2901 return 0;
2902 else if (sec < 0.0)
2903 return -1;
2904 else
2905 return 1;
2906 else if (day < 0)
2907 return -1;
2908 else
2909 return 1;
2910 }
2911
2912 if (mon > 0) {
2913 if ((day >= 0) && (sec >= 0.0))
2914 return 1;
2915 else {
2916 xmon = mon;
2917 xday = -day;
2918 }
2919 } else if ((day <= 0) && (sec <= 0.0)) {
2920 return -1;
2921 } else {
Daniel Veillard80b19092003-03-28 13:29:53 +00002922 invert = -1;
Daniel Veillard070803b2002-05-03 07:29:38 +00002923 xmon = -mon;
2924 xday = day;
2925 }
2926
2927 myear = xmon / 12;
Daniel Veillard80b19092003-03-28 13:29:53 +00002928 if (myear == 0) {
2929 minday = 0;
2930 maxday = 0;
2931 } else {
2932 maxday = 366 * ((myear + 3) / 4) +
2933 365 * ((myear - 1) % 4);
2934 minday = maxday - 1;
2935 }
2936
Daniel Veillard070803b2002-05-03 07:29:38 +00002937 xmon = xmon % 12;
2938 minday += dayRange[0][xmon];
2939 maxday += dayRange[1][xmon];
2940
Daniel Veillard80b19092003-03-28 13:29:53 +00002941 if ((maxday == minday) && (maxday == xday))
2942 return(0); /* can this really happen ? */
Daniel Veillard070803b2002-05-03 07:29:38 +00002943 if (maxday < xday)
Daniel Veillard80b19092003-03-28 13:29:53 +00002944 return(-invert);
2945 if (minday > xday)
2946 return(invert);
Daniel Veillard070803b2002-05-03 07:29:38 +00002947
2948 /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00002949 return 2;
2950}
2951
2952/*
2953 * macros for adding date/times and durations
2954 */
2955#define FQUOTIENT(a,b) (floor(((double)a/(double)b)))
2956#define MODULO(a,b) (a - FQUOTIENT(a,b) * b)
2957#define FQUOTIENT_RANGE(a,low,high) (FQUOTIENT((a-low),(high-low)))
2958#define MODULO_RANGE(a,low,high) ((MODULO((a-low),(high-low)))+low)
2959
2960/**
Daniel Veillard669adfc2004-05-29 20:12:46 +00002961 * xmlSchemaDupVal:
2962 * @v: the #xmlSchemaValPtr value to duplicate
2963 *
2964 * Makes a copy of @v. The calling program is responsible for freeing
2965 * the returned value.
2966 *
2967 * returns a pointer to a duplicated #xmlSchemaValPtr or NULL if error.
2968 */
2969static xmlSchemaValPtr
2970xmlSchemaDupVal (xmlSchemaValPtr v)
2971{
2972 xmlSchemaValPtr ret = xmlSchemaNewValue(v->type);
2973 if (ret == NULL)
2974 return NULL;
2975
2976 memcpy(ret, v, sizeof(xmlSchemaVal));
2977 return ret;
2978}
2979
2980/**
Daniel Veillard5a872412002-05-22 06:40:27 +00002981 * _xmlSchemaDateAdd:
2982 * @dt: an #xmlSchemaValPtr
2983 * @dur: an #xmlSchemaValPtr of type #XS_DURATION
2984 *
2985 * Compute a new date/time from @dt and @dur. This function assumes @dt
2986 * is either #XML_SCHEMAS_DATETIME, #XML_SCHEMAS_DATE, #XML_SCHEMAS_GYEARMONTH,
Daniel Veillard669adfc2004-05-29 20:12:46 +00002987 * or #XML_SCHEMAS_GYEAR. The returned #xmlSchemaVal is the same type as
2988 * @dt. The calling program is responsible for freeing the returned value.
Daniel Veillard5a872412002-05-22 06:40:27 +00002989 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00002990 * Returns a pointer to a new #xmlSchemaVal or NULL if error.
Daniel Veillard5a872412002-05-22 06:40:27 +00002991 */
2992static xmlSchemaValPtr
2993_xmlSchemaDateAdd (xmlSchemaValPtr dt, xmlSchemaValPtr dur)
2994{
Daniel Veillard669adfc2004-05-29 20:12:46 +00002995 xmlSchemaValPtr ret, tmp;
Daniel Veillard5a872412002-05-22 06:40:27 +00002996 long carry, tempdays, temp;
2997 xmlSchemaValDatePtr r, d;
2998 xmlSchemaValDurationPtr u;
2999
3000 if ((dt == NULL) || (dur == NULL))
3001 return NULL;
3002
3003 ret = xmlSchemaNewValue(dt->type);
3004 if (ret == NULL)
3005 return NULL;
3006
Daniel Veillard669adfc2004-05-29 20:12:46 +00003007 /* make a copy so we don't alter the original value */
3008 tmp = xmlSchemaDupVal(dt);
3009 if (tmp == NULL) {
3010 xmlSchemaFreeValue(ret);
3011 return NULL;
3012 }
3013
Daniel Veillard5a872412002-05-22 06:40:27 +00003014 r = &(ret->value.date);
Daniel Veillard669adfc2004-05-29 20:12:46 +00003015 d = &(tmp->value.date);
Daniel Veillard5a872412002-05-22 06:40:27 +00003016 u = &(dur->value.dur);
3017
3018 /* normalization */
3019 if (d->mon == 0)
3020 d->mon = 1;
3021
3022 /* normalize for time zone offset */
3023 u->sec -= (d->tzo * 60);
3024 d->tzo = 0;
3025
3026 /* normalization */
3027 if (d->day == 0)
3028 d->day = 1;
3029
3030 /* month */
3031 carry = d->mon + u->mon;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003032 r->mon = (unsigned int) MODULO_RANGE(carry, 1, 13);
3033 carry = (long) FQUOTIENT_RANGE(carry, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00003034
3035 /* year (may be modified later) */
3036 r->year = d->year + carry;
3037 if (r->year == 0) {
3038 if (d->year > 0)
3039 r->year--;
3040 else
3041 r->year++;
3042 }
3043
3044 /* time zone */
3045 r->tzo = d->tzo;
3046 r->tz_flag = d->tz_flag;
3047
3048 /* seconds */
3049 r->sec = d->sec + u->sec;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003050 carry = (long) FQUOTIENT((long)r->sec, 60);
Daniel Veillard5a872412002-05-22 06:40:27 +00003051 if (r->sec != 0.0) {
3052 r->sec = MODULO(r->sec, 60.0);
3053 }
3054
3055 /* minute */
3056 carry += d->min;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003057 r->min = (unsigned int) MODULO(carry, 60);
3058 carry = (long) FQUOTIENT(carry, 60);
Daniel Veillard5a872412002-05-22 06:40:27 +00003059
3060 /* hours */
3061 carry += d->hour;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003062 r->hour = (unsigned int) MODULO(carry, 24);
3063 carry = (long)FQUOTIENT(carry, 24);
Daniel Veillard5a872412002-05-22 06:40:27 +00003064
3065 /*
3066 * days
3067 * Note we use tempdays because the temporary values may need more
3068 * than 5 bits
3069 */
3070 if ((VALID_YEAR(r->year)) && (VALID_MONTH(r->mon)) &&
3071 (d->day > MAX_DAYINMONTH(r->year, r->mon)))
3072 tempdays = MAX_DAYINMONTH(r->year, r->mon);
3073 else if (d->day < 1)
3074 tempdays = 1;
3075 else
3076 tempdays = d->day;
3077
3078 tempdays += u->day + carry;
3079
3080 while (1) {
3081 if (tempdays < 1) {
Daniel Veillardebe25d42004-03-25 09:35:49 +00003082 long tmon = (long) MODULO_RANGE(r->mon-1, 1, 13);
3083 long tyr = r->year + (long)FQUOTIENT_RANGE(r->mon-1, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00003084 if (tyr == 0)
3085 tyr--;
3086 tempdays += MAX_DAYINMONTH(tyr, tmon);
3087 carry = -1;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003088 } else if (tempdays > (long) MAX_DAYINMONTH(r->year, r->mon)) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003089 tempdays = tempdays - MAX_DAYINMONTH(r->year, r->mon);
3090 carry = 1;
3091 } else
3092 break;
3093
3094 temp = r->mon + carry;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003095 r->mon = (unsigned int) MODULO_RANGE(temp, 1, 13);
3096 r->year = r->year + (unsigned int) FQUOTIENT_RANGE(temp, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00003097 if (r->year == 0) {
3098 if (temp < 1)
3099 r->year--;
3100 else
3101 r->year++;
3102 }
3103 }
3104
3105 r->day = tempdays;
3106
3107 /*
3108 * adjust the date/time type to the date values
3109 */
3110 if (ret->type != XML_SCHEMAS_DATETIME) {
3111 if ((r->hour) || (r->min) || (r->sec))
3112 ret->type = XML_SCHEMAS_DATETIME;
3113 else if (ret->type != XML_SCHEMAS_DATE) {
3114 if ((r->mon != 1) && (r->day != 1))
3115 ret->type = XML_SCHEMAS_DATE;
3116 else if ((ret->type != XML_SCHEMAS_GYEARMONTH) && (r->mon != 1))
3117 ret->type = XML_SCHEMAS_GYEARMONTH;
3118 }
3119 }
3120
Daniel Veillard669adfc2004-05-29 20:12:46 +00003121 xmlSchemaFreeValue(tmp);
Daniel Veillard5a872412002-05-22 06:40:27 +00003122
Daniel Veillard5a872412002-05-22 06:40:27 +00003123 return ret;
3124}
3125
3126/**
3127 * xmlSchemaDateNormalize:
Daniel Veillard669adfc2004-05-29 20:12:46 +00003128 * @dt: an #xmlSchemaValPtr of a date/time type value.
3129 * @offset: number of seconds to adjust @dt by.
Daniel Veillard5a872412002-05-22 06:40:27 +00003130 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00003131 * Normalize @dt to GMT time. The @offset parameter is subtracted from
3132 * the return value is a time-zone offset is present on @dt.
Daniel Veillard5a872412002-05-22 06:40:27 +00003133 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00003134 * Returns a normalized copy of @dt or NULL if error.
Daniel Veillard5a872412002-05-22 06:40:27 +00003135 */
3136static xmlSchemaValPtr
3137xmlSchemaDateNormalize (xmlSchemaValPtr dt, double offset)
3138{
3139 xmlSchemaValPtr dur, ret;
3140
3141 if (dt == NULL)
3142 return NULL;
3143
3144 if (((dt->type != XML_SCHEMAS_TIME) &&
3145 (dt->type != XML_SCHEMAS_DATETIME)) || (dt->value.date.tzo == 0))
3146 return xmlSchemaDupVal(dt);
3147
3148 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
3149 if (dur == NULL)
3150 return NULL;
3151
3152 dur->value.date.sec -= offset;
3153
3154 ret = _xmlSchemaDateAdd(dt, dur);
3155 if (ret == NULL)
3156 return NULL;
3157
3158 xmlSchemaFreeValue(dur);
3159
3160 /* ret->value.date.tzo = 0; */
3161 return ret;
3162}
3163
3164/**
3165 * _xmlSchemaDateCastYMToDays:
3166 * @dt: an #xmlSchemaValPtr
3167 *
3168 * Convert mon and year of @dt to total number of days. Take the
3169 * number of years since (or before) 1 AD and add the number of leap
3170 * years. This is a function because negative
3171 * years must be handled a little differently and there is no zero year.
3172 *
3173 * Returns number of days.
3174 */
3175static long
3176_xmlSchemaDateCastYMToDays (const xmlSchemaValPtr dt)
3177{
3178 long ret;
Daniel Veillard49e89632004-09-23 16:24:36 +00003179 int mon;
Daniel Veillard5a872412002-05-22 06:40:27 +00003180
Daniel Veillard49e89632004-09-23 16:24:36 +00003181 mon = dt->value.date.mon;
3182 if (mon <= 0) mon = 1; /* normalization */
3183
3184 if (dt->value.date.year <= 0)
Daniel Veillard5a872412002-05-22 06:40:27 +00003185 ret = (dt->value.date.year * 365) +
3186 (((dt->value.date.year+1)/4)-((dt->value.date.year+1)/100)+
3187 ((dt->value.date.year+1)/400)) +
Daniel Veillard49e89632004-09-23 16:24:36 +00003188 DAY_IN_YEAR(0, mon, dt->value.date.year);
Daniel Veillard5a872412002-05-22 06:40:27 +00003189 else
3190 ret = ((dt->value.date.year-1) * 365) +
3191 (((dt->value.date.year-1)/4)-((dt->value.date.year-1)/100)+
3192 ((dt->value.date.year-1)/400)) +
Daniel Veillard49e89632004-09-23 16:24:36 +00003193 DAY_IN_YEAR(0, mon, dt->value.date.year);
Daniel Veillard5a872412002-05-22 06:40:27 +00003194
3195 return ret;
3196}
3197
3198/**
3199 * TIME_TO_NUMBER:
3200 * @dt: an #xmlSchemaValPtr
3201 *
3202 * Calculates the number of seconds in the time portion of @dt.
3203 *
3204 * Returns seconds.
3205 */
3206#define TIME_TO_NUMBER(dt) \
3207 ((double)((dt->value.date.hour * SECS_PER_HOUR) + \
Daniel Veillardb3721c22003-03-31 11:22:25 +00003208 (dt->value.date.min * SECS_PER_MIN) + \
3209 (dt->value.date.tzo * SECS_PER_MIN)) + \
3210 dt->value.date.sec)
Daniel Veillard5a872412002-05-22 06:40:27 +00003211
3212/**
3213 * xmlSchemaCompareDates:
3214 * @x: a first date/time value
3215 * @y: a second date/time value
3216 *
3217 * Compare 2 date/times
3218 *
3219 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3220 * case of error
3221 */
3222static int
3223xmlSchemaCompareDates (xmlSchemaValPtr x, xmlSchemaValPtr y)
3224{
3225 unsigned char xmask, ymask, xor_mask, and_mask;
3226 xmlSchemaValPtr p1, p2, q1, q2;
3227 long p1d, p2d, q1d, q2d;
3228
3229 if ((x == NULL) || (y == NULL))
3230 return -2;
3231
3232 if (x->value.date.tz_flag) {
3233
3234 if (!y->value.date.tz_flag) {
3235 p1 = xmlSchemaDateNormalize(x, 0);
3236 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3237 /* normalize y + 14:00 */
3238 q1 = xmlSchemaDateNormalize(y, (14 * SECS_PER_HOUR));
3239
3240 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003241 if (p1d < q1d) {
3242 xmlSchemaFreeValue(p1);
3243 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003244 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003245 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003246 double sec;
3247
3248 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00003249 if (sec < 0.0) {
3250 xmlSchemaFreeValue(p1);
3251 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003252 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003253 } else {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003254 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003255 /* normalize y - 14:00 */
3256 q2 = xmlSchemaDateNormalize(y, -(14 * SECS_PER_HOUR));
3257 q2d = _xmlSchemaDateCastYMToDays(q2) + q2->value.date.day;
3258 if (p1d > q2d)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003259 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003260 else if (p1d == q2d) {
3261 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q2);
3262 if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003263 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003264 else
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003265 ret = 2; /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00003266 }
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003267 xmlSchemaFreeValue(p1);
3268 xmlSchemaFreeValue(q1);
3269 xmlSchemaFreeValue(q2);
3270 if (ret != 0)
3271 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003272 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00003273 } else {
3274 xmlSchemaFreeValue(p1);
3275 xmlSchemaFreeValue(q1);
3276 }
Daniel Veillard5a872412002-05-22 06:40:27 +00003277 }
3278 } else if (y->value.date.tz_flag) {
3279 q1 = xmlSchemaDateNormalize(y, 0);
3280 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
3281
3282 /* normalize x - 14:00 */
3283 p1 = xmlSchemaDateNormalize(x, -(14 * SECS_PER_HOUR));
3284 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3285
Daniel Veillardfdc91562002-07-01 21:52:03 +00003286 if (p1d < q1d) {
3287 xmlSchemaFreeValue(p1);
3288 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003289 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003290 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003291 double sec;
3292
3293 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00003294 if (sec < 0.0) {
3295 xmlSchemaFreeValue(p1);
3296 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003297 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003298 } else {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003299 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003300 /* normalize x + 14:00 */
3301 p2 = xmlSchemaDateNormalize(x, (14 * SECS_PER_HOUR));
3302 p2d = _xmlSchemaDateCastYMToDays(p2) + p2->value.date.day;
3303
Daniel Veillard6560a422003-03-27 21:25:38 +00003304 if (p2d > q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003305 ret = 1;
Daniel Veillard6560a422003-03-27 21:25:38 +00003306 } else if (p2d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003307 sec = TIME_TO_NUMBER(p2) - TIME_TO_NUMBER(q1);
3308 if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003309 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003310 else
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003311 ret = 2; /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00003312 }
Daniel Veillard6560a422003-03-27 21:25:38 +00003313 xmlSchemaFreeValue(p1);
3314 xmlSchemaFreeValue(q1);
3315 xmlSchemaFreeValue(p2);
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003316 if (ret != 0)
3317 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003318 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00003319 } else {
3320 xmlSchemaFreeValue(p1);
3321 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003322 }
3323 }
3324
3325 /*
3326 * if the same type then calculate the difference
3327 */
3328 if (x->type == y->type) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003329 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003330 q1 = xmlSchemaDateNormalize(y, 0);
3331 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
3332
3333 p1 = xmlSchemaDateNormalize(x, 0);
3334 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3335
Daniel Veillardfdc91562002-07-01 21:52:03 +00003336 if (p1d < q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003337 ret = -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003338 } else if (p1d > q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003339 ret = 1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003340 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00003341 double sec;
3342
3343 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
3344 if (sec < 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003345 ret = -1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003346 else if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003347 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003348
3349 }
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003350 xmlSchemaFreeValue(p1);
3351 xmlSchemaFreeValue(q1);
3352 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003353 }
3354
3355 switch (x->type) {
3356 case XML_SCHEMAS_DATETIME:
3357 xmask = 0xf;
3358 break;
3359 case XML_SCHEMAS_DATE:
3360 xmask = 0x7;
3361 break;
3362 case XML_SCHEMAS_GYEAR:
3363 xmask = 0x1;
3364 break;
3365 case XML_SCHEMAS_GMONTH:
3366 xmask = 0x2;
3367 break;
3368 case XML_SCHEMAS_GDAY:
3369 xmask = 0x3;
3370 break;
3371 case XML_SCHEMAS_GYEARMONTH:
3372 xmask = 0x3;
3373 break;
3374 case XML_SCHEMAS_GMONTHDAY:
3375 xmask = 0x6;
3376 break;
3377 case XML_SCHEMAS_TIME:
3378 xmask = 0x8;
3379 break;
3380 default:
3381 xmask = 0;
3382 break;
3383 }
3384
3385 switch (y->type) {
3386 case XML_SCHEMAS_DATETIME:
3387 ymask = 0xf;
3388 break;
3389 case XML_SCHEMAS_DATE:
3390 ymask = 0x7;
3391 break;
3392 case XML_SCHEMAS_GYEAR:
3393 ymask = 0x1;
3394 break;
3395 case XML_SCHEMAS_GMONTH:
3396 ymask = 0x2;
3397 break;
3398 case XML_SCHEMAS_GDAY:
3399 ymask = 0x3;
3400 break;
3401 case XML_SCHEMAS_GYEARMONTH:
3402 ymask = 0x3;
3403 break;
3404 case XML_SCHEMAS_GMONTHDAY:
3405 ymask = 0x6;
3406 break;
3407 case XML_SCHEMAS_TIME:
3408 ymask = 0x8;
3409 break;
3410 default:
3411 ymask = 0;
3412 break;
3413 }
3414
3415 xor_mask = xmask ^ ymask; /* mark type differences */
3416 and_mask = xmask & ymask; /* mark field specification */
3417
3418 /* year */
3419 if (xor_mask & 1)
3420 return 2; /* indeterminate */
3421 else if (and_mask & 1) {
3422 if (x->value.date.year < y->value.date.year)
3423 return -1;
3424 else if (x->value.date.year > y->value.date.year)
3425 return 1;
3426 }
3427
3428 /* month */
3429 if (xor_mask & 2)
3430 return 2; /* indeterminate */
3431 else if (and_mask & 2) {
3432 if (x->value.date.mon < y->value.date.mon)
3433 return -1;
3434 else if (x->value.date.mon > y->value.date.mon)
3435 return 1;
3436 }
3437
3438 /* day */
3439 if (xor_mask & 4)
3440 return 2; /* indeterminate */
3441 else if (and_mask & 4) {
3442 if (x->value.date.day < y->value.date.day)
3443 return -1;
3444 else if (x->value.date.day > y->value.date.day)
3445 return 1;
3446 }
3447
3448 /* time */
3449 if (xor_mask & 8)
3450 return 2; /* indeterminate */
3451 else if (and_mask & 8) {
3452 if (x->value.date.hour < y->value.date.hour)
3453 return -1;
3454 else if (x->value.date.hour > y->value.date.hour)
3455 return 1;
3456 else if (x->value.date.min < y->value.date.min)
3457 return -1;
3458 else if (x->value.date.min > y->value.date.min)
3459 return 1;
3460 else if (x->value.date.sec < y->value.date.sec)
3461 return -1;
3462 else if (x->value.date.sec > y->value.date.sec)
3463 return 1;
3464 }
3465
Daniel Veillard070803b2002-05-03 07:29:38 +00003466 return 0;
3467}
3468
3469/**
Daniel Veillardc4c21552003-03-29 10:53:38 +00003470 * xmlSchemaCompareNormStrings:
3471 * @x: a first string value
3472 * @y: a second string value
3473 *
3474 * Compare 2 string for their normalized values.
3475 *
3476 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
3477 * case of error
3478 */
3479static int
3480xmlSchemaCompareNormStrings(xmlSchemaValPtr x, xmlSchemaValPtr y) {
3481 const xmlChar *utf1;
3482 const xmlChar *utf2;
3483 int tmp;
3484
3485 if ((x == NULL) || (y == NULL))
3486 return(-2);
3487 utf1 = x->value.str;
3488 utf2 = y->value.str;
3489
William M. Brack76e95df2003-10-18 16:20:14 +00003490 while (IS_BLANK_CH(*utf1)) utf1++;
3491 while (IS_BLANK_CH(*utf2)) utf2++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003492 while ((*utf1 != 0) && (*utf2 != 0)) {
William M. Brack76e95df2003-10-18 16:20:14 +00003493 if (IS_BLANK_CH(*utf1)) {
3494 if (!IS_BLANK_CH(*utf2)) {
Daniel Veillardc4c21552003-03-29 10:53:38 +00003495 tmp = *utf1 - *utf2;
3496 return(tmp);
3497 }
William M. Brack76e95df2003-10-18 16:20:14 +00003498 while (IS_BLANK_CH(*utf1)) utf1++;
3499 while (IS_BLANK_CH(*utf2)) utf2++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003500 } else {
3501 tmp = *utf1++ - *utf2++;
3502 if (tmp < 0)
3503 return(-1);
3504 if (tmp > 0)
3505 return(1);
3506 }
3507 }
3508 if (*utf1 != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00003509 while (IS_BLANK_CH(*utf1)) utf1++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003510 if (*utf1 != 0)
3511 return(1);
3512 }
3513 if (*utf2 != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00003514 while (IS_BLANK_CH(*utf2)) utf2++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003515 if (*utf2 != 0)
3516 return(-1);
3517 }
3518 return(0);
3519}
3520
3521/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003522 * xmlSchemaCompareFloats:
3523 * @x: a first float or double value
3524 * @y: a second float or double value
3525 *
3526 * Compare 2 values
3527 *
3528 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3529 * case of error
3530 */
3531static int
3532xmlSchemaCompareFloats(xmlSchemaValPtr x, xmlSchemaValPtr y) {
3533 double d1, d2;
3534
3535 if ((x == NULL) || (y == NULL))
3536 return(-2);
3537
3538 /*
3539 * Cast everything to doubles.
3540 */
3541 if (x->type == XML_SCHEMAS_DOUBLE)
3542 d1 = x->value.d;
3543 else if (x->type == XML_SCHEMAS_FLOAT)
3544 d1 = x->value.f;
3545 else
3546 return(-2);
3547
3548 if (y->type == XML_SCHEMAS_DOUBLE)
3549 d2 = y->value.d;
3550 else if (y->type == XML_SCHEMAS_FLOAT)
3551 d2 = y->value.f;
3552 else
3553 return(-2);
3554
3555 /*
3556 * Check for special cases.
3557 */
3558 if (xmlXPathIsNaN(d1)) {
3559 if (xmlXPathIsNaN(d2))
3560 return(0);
3561 return(1);
3562 }
3563 if (xmlXPathIsNaN(d2))
3564 return(-1);
3565 if (d1 == xmlXPathPINF) {
3566 if (d2 == xmlXPathPINF)
3567 return(0);
3568 return(1);
3569 }
3570 if (d2 == xmlXPathPINF)
3571 return(-1);
3572 if (d1 == xmlXPathNINF) {
3573 if (d2 == xmlXPathNINF)
3574 return(0);
3575 return(-1);
3576 }
3577 if (d2 == xmlXPathNINF)
3578 return(1);
3579
3580 /*
3581 * basic tests, the last one we should have equality, but
3582 * portability is more important than speed and handling
3583 * NaN or Inf in a portable way is always a challenge, so ...
3584 */
3585 if (d1 < d2)
3586 return(-1);
3587 if (d1 > d2)
3588 return(1);
3589 if (d1 == d2)
3590 return(0);
3591 return(2);
3592}
3593
3594/**
Daniel Veillard4255d502002-04-16 15:50:10 +00003595 * xmlSchemaCompareValues:
3596 * @x: a first value
3597 * @y: a second value
3598 *
3599 * Compare 2 values
3600 *
Daniel Veillard5a872412002-05-22 06:40:27 +00003601 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3602 * case of error
Daniel Veillard4255d502002-04-16 15:50:10 +00003603 */
Daniel Veillard80b19092003-03-28 13:29:53 +00003604int
Daniel Veillard4255d502002-04-16 15:50:10 +00003605xmlSchemaCompareValues(xmlSchemaValPtr x, xmlSchemaValPtr y) {
3606 if ((x == NULL) || (y == NULL))
3607 return(-2);
3608
3609 switch (x->type) {
Daniel Veillard80b19092003-03-28 13:29:53 +00003610 case XML_SCHEMAS_UNKNOWN:
William M. Brack2f2a6632004-08-20 23:09:47 +00003611 case XML_SCHEMAS_ANYTYPE:
3612 case XML_SCHEMAS_ANYSIMPLETYPE:
Daniel Veillard80b19092003-03-28 13:29:53 +00003613 return(-2);
3614 case XML_SCHEMAS_INTEGER:
3615 case XML_SCHEMAS_NPINTEGER:
3616 case XML_SCHEMAS_NINTEGER:
3617 case XML_SCHEMAS_NNINTEGER:
3618 case XML_SCHEMAS_PINTEGER:
3619 case XML_SCHEMAS_INT:
3620 case XML_SCHEMAS_UINT:
3621 case XML_SCHEMAS_LONG:
3622 case XML_SCHEMAS_ULONG:
3623 case XML_SCHEMAS_SHORT:
3624 case XML_SCHEMAS_USHORT:
3625 case XML_SCHEMAS_BYTE:
3626 case XML_SCHEMAS_UBYTE:
Daniel Veillard4255d502002-04-16 15:50:10 +00003627 case XML_SCHEMAS_DECIMAL:
Daniel Veillard80b19092003-03-28 13:29:53 +00003628 if (y->type == x->type)
3629 return(xmlSchemaCompareDecimals(x, y));
3630 if ((y->type == XML_SCHEMAS_DECIMAL) ||
3631 (y->type == XML_SCHEMAS_INTEGER) ||
3632 (y->type == XML_SCHEMAS_NPINTEGER) ||
3633 (y->type == XML_SCHEMAS_NINTEGER) ||
3634 (y->type == XML_SCHEMAS_NNINTEGER) ||
3635 (y->type == XML_SCHEMAS_PINTEGER) ||
3636 (y->type == XML_SCHEMAS_INT) ||
3637 (y->type == XML_SCHEMAS_UINT) ||
3638 (y->type == XML_SCHEMAS_LONG) ||
3639 (y->type == XML_SCHEMAS_ULONG) ||
3640 (y->type == XML_SCHEMAS_SHORT) ||
3641 (y->type == XML_SCHEMAS_USHORT) ||
3642 (y->type == XML_SCHEMAS_BYTE) ||
3643 (y->type == XML_SCHEMAS_UBYTE))
Daniel Veillard4255d502002-04-16 15:50:10 +00003644 return(xmlSchemaCompareDecimals(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00003645 return(-2);
Daniel Veillard070803b2002-05-03 07:29:38 +00003646 case XML_SCHEMAS_DURATION:
3647 if (y->type == XML_SCHEMAS_DURATION)
3648 return(xmlSchemaCompareDurations(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00003649 return(-2);
3650 case XML_SCHEMAS_TIME:
3651 case XML_SCHEMAS_GDAY:
3652 case XML_SCHEMAS_GMONTH:
3653 case XML_SCHEMAS_GMONTHDAY:
3654 case XML_SCHEMAS_GYEAR:
3655 case XML_SCHEMAS_GYEARMONTH:
3656 case XML_SCHEMAS_DATE:
3657 case XML_SCHEMAS_DATETIME:
3658 if ((y->type == XML_SCHEMAS_DATETIME) ||
3659 (y->type == XML_SCHEMAS_TIME) ||
3660 (y->type == XML_SCHEMAS_GDAY) ||
3661 (y->type == XML_SCHEMAS_GMONTH) ||
3662 (y->type == XML_SCHEMAS_GMONTHDAY) ||
3663 (y->type == XML_SCHEMAS_GYEAR) ||
3664 (y->type == XML_SCHEMAS_DATE) ||
3665 (y->type == XML_SCHEMAS_GYEARMONTH))
3666 return (xmlSchemaCompareDates(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00003667 return (-2);
Daniel Veillard80b19092003-03-28 13:29:53 +00003668 case XML_SCHEMAS_NORMSTRING:
Daniel Veillard80b19092003-03-28 13:29:53 +00003669 case XML_SCHEMAS_TOKEN:
3670 case XML_SCHEMAS_LANGUAGE:
3671 case XML_SCHEMAS_NMTOKEN:
Daniel Veillard80b19092003-03-28 13:29:53 +00003672 case XML_SCHEMAS_NAME:
Daniel Veillard80b19092003-03-28 13:29:53 +00003673 case XML_SCHEMAS_NCNAME:
3674 case XML_SCHEMAS_ID:
3675 case XML_SCHEMAS_IDREF:
Daniel Veillard80b19092003-03-28 13:29:53 +00003676 case XML_SCHEMAS_ENTITY:
Daniel Veillard80b19092003-03-28 13:29:53 +00003677 case XML_SCHEMAS_NOTATION:
3678 case XML_SCHEMAS_ANYURI:
Daniel Veillardc4c21552003-03-29 10:53:38 +00003679 if ((y->type == XML_SCHEMAS_NORMSTRING) ||
3680 (y->type == XML_SCHEMAS_TOKEN) ||
3681 (y->type == XML_SCHEMAS_LANGUAGE) ||
3682 (y->type == XML_SCHEMAS_NMTOKEN) ||
3683 (y->type == XML_SCHEMAS_NAME) ||
3684 (y->type == XML_SCHEMAS_QNAME) ||
3685 (y->type == XML_SCHEMAS_NCNAME) ||
3686 (y->type == XML_SCHEMAS_ID) ||
3687 (y->type == XML_SCHEMAS_IDREF) ||
3688 (y->type == XML_SCHEMAS_ENTITY) ||
3689 (y->type == XML_SCHEMAS_NOTATION) ||
3690 (y->type == XML_SCHEMAS_ANYURI))
3691 return (xmlSchemaCompareNormStrings(x, y));
3692 return (-2);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003693 case XML_SCHEMAS_QNAME:
3694 if (y->type == XML_SCHEMAS_QNAME) {
3695 if ((xmlStrEqual(x->value.qname.name, y->value.qname.name)) &&
3696 (xmlStrEqual(x->value.qname.uri, y->value.qname.uri)))
3697 return(0);
3698 return(2);
3699 }
3700 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00003701 case XML_SCHEMAS_FLOAT:
3702 case XML_SCHEMAS_DOUBLE:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003703 if ((y->type == XML_SCHEMAS_FLOAT) ||
3704 (y->type == XML_SCHEMAS_DOUBLE))
3705 return (xmlSchemaCompareFloats(x, y));
3706 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00003707 case XML_SCHEMAS_BOOLEAN:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003708 if (y->type == XML_SCHEMAS_BOOLEAN) {
3709 if (x->value.b == y->value.b)
3710 return(0);
3711 if (x->value.b == 0)
3712 return(-1);
3713 return(1);
3714 }
3715 return (-2);
Daniel Veillard560c2a42003-07-06 21:13:49 +00003716 case XML_SCHEMAS_HEXBINARY:
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00003717 if (y->type == XML_SCHEMAS_HEXBINARY) {
3718 if (x->value.hex.total == y->value.hex.total) {
3719 int ret = xmlStrcmp(x->value.hex.str, y->value.hex.str);
3720 if (ret > 0)
3721 return(1);
3722 else if (ret == 0)
3723 return(0);
3724 }
3725 else if (x->value.hex.total > y->value.hex.total)
3726 return(1);
3727
3728 return(-1);
3729 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00003730 return (-2);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003731 case XML_SCHEMAS_BASE64BINARY:
3732 if (y->type == XML_SCHEMAS_BASE64BINARY) {
3733 if (x->value.base64.total == y->value.base64.total) {
3734 int ret = xmlStrcmp(x->value.base64.str,
3735 y->value.base64.str);
3736 if (ret > 0)
3737 return(1);
3738 else if (ret == 0)
3739 return(0);
3740 }
3741 else if (x->value.base64.total > y->value.base64.total)
3742 return(1);
3743 else
3744 return(-1);
3745 }
3746 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00003747 case XML_SCHEMAS_STRING:
3748 case XML_SCHEMAS_IDREFS:
3749 case XML_SCHEMAS_ENTITIES:
3750 case XML_SCHEMAS_NMTOKENS:
3751 TODO
3752 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00003753 }
Daniel Veillard5a872412002-05-22 06:40:27 +00003754 return -2;
Daniel Veillard4255d502002-04-16 15:50:10 +00003755}
3756
3757/**
Daniel Veillardc4c21552003-03-29 10:53:38 +00003758 * xmlSchemaNormLen:
3759 * @value: a string
3760 *
3761 * Computes the UTF8 length of the normalized value of the string
3762 *
3763 * Returns the length or -1 in case of error.
3764 */
3765static int
3766xmlSchemaNormLen(const xmlChar *value) {
3767 const xmlChar *utf;
3768 int ret = 0;
3769
3770 if (value == NULL)
3771 return(-1);
3772 utf = value;
William M. Brack76e95df2003-10-18 16:20:14 +00003773 while (IS_BLANK_CH(*utf)) utf++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003774 while (*utf != 0) {
3775 if (utf[0] & 0x80) {
3776 if ((utf[1] & 0xc0) != 0x80)
3777 return(-1);
3778 if ((utf[0] & 0xe0) == 0xe0) {
3779 if ((utf[2] & 0xc0) != 0x80)
3780 return(-1);
3781 if ((utf[0] & 0xf0) == 0xf0) {
3782 if ((utf[0] & 0xf8) != 0xf0 || (utf[3] & 0xc0) != 0x80)
3783 return(-1);
3784 utf += 4;
3785 } else {
3786 utf += 3;
3787 }
3788 } else {
3789 utf += 2;
3790 }
William M. Brack76e95df2003-10-18 16:20:14 +00003791 } else if (IS_BLANK_CH(*utf)) {
3792 while (IS_BLANK_CH(*utf)) utf++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003793 if (*utf == 0)
3794 break;
3795 } else {
3796 utf++;
3797 }
3798 ret++;
3799 }
3800 return(ret);
3801}
3802
Daniel Veillard6927b102004-10-27 17:29:04 +00003803/**
3804 * xmlSchemaGetFacetValueAsULong:
3805 * @facet: an schemas type facet
3806 *
3807 * Extract the value of a facet
3808 *
3809 * Returns the value as a long
3810 */
Daniel Veillardc0826a72004-08-10 14:17:33 +00003811unsigned long
3812xmlSchemaGetFacetValueAsULong(xmlSchemaFacetPtr facet)
3813{
3814 /*
3815 * TODO: Check if this is a decimal.
3816 */
3817 return ((unsigned long) facet->val->value.decimal.lo);
3818}
3819
Daniel Veillardc4c21552003-03-29 10:53:38 +00003820/**
Daniel Veillard01fa6152004-06-29 17:04:39 +00003821 * xmlSchemaValidateListSimpleTypeFacet:
3822 * @facet: the facet to check
3823 * @value: the lexical repr of the value to validate
3824 * @actualLen: the number of list items
3825 * @expectedLen: the resulting expected number of list items
3826 *
3827 * Checks the value of a list simple type against a facet.
3828 *
3829 * Returns 0 if the value is valid, a positive error code
3830 * number otherwise and -1 in case of an internal error.
3831 */
3832int
3833xmlSchemaValidateListSimpleTypeFacet(xmlSchemaFacetPtr facet,
3834 const xmlChar *value,
3835 unsigned long actualLen,
3836 unsigned long *expectedLen)
3837{
Daniel Veillardce682bc2004-11-05 17:22:25 +00003838 if (facet == NULL)
3839 return(-1);
Daniel Veillard01fa6152004-06-29 17:04:39 +00003840 /*
3841 * TODO: Check if this will work with large numbers.
3842 * (compare value.decimal.mi and value.decimal.hi as well?).
3843 */
3844 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
3845 if (actualLen != facet->val->value.decimal.lo) {
Daniel Veillardc0826a72004-08-10 14:17:33 +00003846 if (expectedLen != 0)
3847 *expectedLen = facet->val->value.decimal.lo;
Daniel Veillard01fa6152004-06-29 17:04:39 +00003848 return (XML_SCHEMAV_CVC_LENGTH_VALID);
3849 }
3850 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
3851 if (actualLen < facet->val->value.decimal.lo) {
Daniel Veillardc0826a72004-08-10 14:17:33 +00003852 if (expectedLen != 0)
3853 *expectedLen = facet->val->value.decimal.lo;
Daniel Veillard01fa6152004-06-29 17:04:39 +00003854 return (XML_SCHEMAV_CVC_MINLENGTH_VALID);
3855 }
3856 } else if (facet->type == XML_SCHEMA_FACET_MAXLENGTH) {
3857 if (actualLen > facet->val->value.decimal.lo) {
Daniel Veillardc0826a72004-08-10 14:17:33 +00003858 if (expectedLen != 0)
3859 *expectedLen = facet->val->value.decimal.lo;
Daniel Veillard01fa6152004-06-29 17:04:39 +00003860 return (XML_SCHEMAV_CVC_MAXLENGTH_VALID);
3861 }
3862 } else
3863 /*
3864 * NOTE: That we can pass NULL as xmlSchemaValPtr to
3865 * xmlSchemaValidateFacet, since the remaining facet types
3866 * are: XML_SCHEMA_FACET_PATTERN, XML_SCHEMA_FACET_ENUMERATION.
3867 */
3868 return(xmlSchemaValidateFacet(NULL, facet, value, NULL));
3869 return (0);
3870}
3871
3872/**
Daniel Veillard6927b102004-10-27 17:29:04 +00003873 * xmlSchemaValidateLengthFacet:
Daniel Veillardc0826a72004-08-10 14:17:33 +00003874 * @type: the built-in type
3875 * @facet: the facet to check
3876 * @value: the lexical repr. of the value to be validated
3877 * @val: the precomputed value
3878 * @length: the actual length of the value
3879 *
3880 * Checka a value against a "length", "minLength" and "maxLength"
3881 * facet; sets @length to the computed length of @value.
3882 *
3883 * Returns 0 if the value is valid, a positive error code
3884 * otherwise and -1 in case of an internal or API error.
3885 */
3886int
3887xmlSchemaValidateLengthFacet(xmlSchemaTypePtr type,
3888 xmlSchemaFacetPtr facet,
3889 const xmlChar *value,
3890 xmlSchemaValPtr val,
3891 unsigned long *length)
3892{
3893 unsigned int len = 0;
3894
Daniel Veillardce682bc2004-11-05 17:22:25 +00003895 if ((length == NULL) || (facet == NULL) || (type == NULL))
3896 return (-1);
Daniel Veillardc0826a72004-08-10 14:17:33 +00003897 *length = 0;
3898 if ((facet->type != XML_SCHEMA_FACET_LENGTH) &&
3899 (facet->type != XML_SCHEMA_FACET_MAXLENGTH) &&
3900 (facet->type != XML_SCHEMA_FACET_MINLENGTH))
3901 return (-1);
3902
3903 if ((facet->val == NULL) ||
3904 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
3905 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
3906 (facet->val->value.decimal.frac != 0)) {
3907 return(-1);
3908 }
3909 if ((val != NULL) && (val->type == XML_SCHEMAS_HEXBINARY))
3910 len = val->value.hex.total;
3911 else if ((val != NULL) && (val->type == XML_SCHEMAS_BASE64BINARY))
3912 len = val->value.base64.total;
3913 else {
3914 switch (type->builtInType) {
3915 case XML_SCHEMAS_IDREF:
3916 case XML_SCHEMAS_NORMSTRING:
3917 case XML_SCHEMAS_TOKEN:
3918 case XML_SCHEMAS_LANGUAGE:
3919 case XML_SCHEMAS_NMTOKEN:
3920 case XML_SCHEMAS_NAME:
3921 case XML_SCHEMAS_NCNAME:
3922 case XML_SCHEMAS_ID:
3923 len = xmlSchemaNormLen(value);
3924 break;
3925 case XML_SCHEMAS_STRING:
3926 /*
3927 * FIXME: What exactly to do with anyURI?
3928 */
3929 case XML_SCHEMAS_ANYURI:
3930 if (value != NULL)
3931 len = xmlUTF8Strlen(value);
3932 break;
3933 default:
3934 TODO
3935 }
3936 }
3937 *length = (unsigned long) len;
3938 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
3939 if (len != facet->val->value.decimal.lo)
3940 return(XML_SCHEMAV_CVC_LENGTH_VALID);
3941 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
3942 if (len < facet->val->value.decimal.lo)
3943 return(XML_SCHEMAV_CVC_MINLENGTH_VALID);
3944 } else {
3945 if (len > facet->val->value.decimal.lo)
3946 return(XML_SCHEMAV_CVC_MAXLENGTH_VALID);
3947 }
3948
3949 return (0);
3950}
3951
3952/**
3953 * xmlSchemaValidateFacet:
Daniel Veillard01c13b52002-12-10 15:19:08 +00003954 * @base: the base type
Daniel Veillard4255d502002-04-16 15:50:10 +00003955 * @facet: the facet to check
3956 * @value: the lexical repr of the value to validate
3957 * @val: the precomputed value
3958 *
3959 * Check a value against a facet condition
3960 *
3961 * Returns 0 if the element is schemas valid, a positive error code
3962 * number otherwise and -1 in case of internal or API error.
3963 */
3964int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00003965xmlSchemaValidateFacet(xmlSchemaTypePtr base ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +00003966 xmlSchemaFacetPtr facet,
Daniel Veillard4255d502002-04-16 15:50:10 +00003967 const xmlChar *value, xmlSchemaValPtr val)
3968{
3969 int ret;
3970
Daniel Veillardce682bc2004-11-05 17:22:25 +00003971 if ((facet == NULL) || (value == NULL))
3972 return(-1);
Daniel Veillard4255d502002-04-16 15:50:10 +00003973 switch (facet->type) {
3974 case XML_SCHEMA_FACET_PATTERN:
3975 ret = xmlRegexpExec(facet->regexp, value);
3976 if (ret == 1)
3977 return(0);
3978 if (ret == 0) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00003979 return(XML_SCHEMAV_CVC_PATTERN_VALID);
Daniel Veillard4255d502002-04-16 15:50:10 +00003980 }
3981 return(ret);
3982 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
3983 ret = xmlSchemaCompareValues(val, facet->val);
3984 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003985 /* TODO error code */
Daniel Veillard4255d502002-04-16 15:50:10 +00003986 return(-1);
3987 }
3988 if (ret == -1)
3989 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00003990 /* error code */
Daniel Veillard01fa6152004-06-29 17:04:39 +00003991 return(XML_SCHEMAV_CVC_MAXEXCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00003992 case XML_SCHEMA_FACET_MAXINCLUSIVE:
3993 ret = xmlSchemaCompareValues(val, facet->val);
3994 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003995 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00003996 return(-1);
3997 }
3998 if ((ret == -1) || (ret == 0))
3999 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00004000 /* error code */
Daniel Veillard01fa6152004-06-29 17:04:39 +00004001 return(XML_SCHEMAV_CVC_MAXINCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00004002 case XML_SCHEMA_FACET_MINEXCLUSIVE:
4003 ret = xmlSchemaCompareValues(val, facet->val);
4004 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004005 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00004006 return(-1);
4007 }
4008 if (ret == 1)
4009 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00004010 /* error code */
Daniel Veillard01fa6152004-06-29 17:04:39 +00004011 return(XML_SCHEMAV_CVC_MINEXCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00004012 case XML_SCHEMA_FACET_MININCLUSIVE:
4013 ret = xmlSchemaCompareValues(val, facet->val);
4014 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004015 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00004016 return(-1);
4017 }
4018 if ((ret == 1) || (ret == 0))
4019 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00004020 /* error code */
Daniel Veillard01fa6152004-06-29 17:04:39 +00004021 return(XML_SCHEMAV_CVC_MININCLUSIVE_VALID);
Daniel Veillard8651f532002-04-17 09:06:27 +00004022 case XML_SCHEMA_FACET_WHITESPACE:
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004023 /* TODO whitespaces */
Daniel Veillard01fa6152004-06-29 17:04:39 +00004024 /*
4025 * NOTE: Whitespace should be handled to normalize
4026 * the value to be validated against a the facets;
4027 * not to normalize the value in-between.
4028 */
Daniel Veillard8651f532002-04-17 09:06:27 +00004029 return(0);
Daniel Veillard88c58912002-04-23 07:12:20 +00004030 case XML_SCHEMA_FACET_ENUMERATION:
4031 if ((facet->value != NULL) &&
4032 (xmlStrEqual(facet->value, value)))
4033 return(0);
Daniel Veillard01fa6152004-06-29 17:04:39 +00004034 return(XML_SCHEMAV_CVC_ENUMERATION_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004035 case XML_SCHEMA_FACET_LENGTH:
4036 case XML_SCHEMA_FACET_MAXLENGTH:
4037 case XML_SCHEMA_FACET_MINLENGTH: {
4038 unsigned int len = 0;
4039
4040 if ((facet->val == NULL) ||
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004041 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
4042 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004043 (facet->val->value.decimal.frac != 0)) {
4044 return(-1);
4045 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00004046 if ((val != NULL) && (val->type == XML_SCHEMAS_HEXBINARY))
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004047 len = val->value.hex.total;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00004048 else if ((val != NULL) && (val->type == XML_SCHEMAS_BASE64BINARY))
4049 len = val->value.base64.total;
4050 else {
Daniel Veillard01fa6152004-06-29 17:04:39 +00004051 switch (base->builtInType) {
Daniel Veillard560c2a42003-07-06 21:13:49 +00004052 case XML_SCHEMAS_IDREF:
4053 case XML_SCHEMAS_NORMSTRING:
4054 case XML_SCHEMAS_TOKEN:
4055 case XML_SCHEMAS_LANGUAGE:
4056 case XML_SCHEMAS_NMTOKEN:
4057 case XML_SCHEMAS_NAME:
4058 case XML_SCHEMAS_NCNAME:
4059 case XML_SCHEMAS_ID:
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004060 len = xmlSchemaNormLen(value);
4061 break;
Daniel Veillard560c2a42003-07-06 21:13:49 +00004062 case XML_SCHEMAS_STRING:
Daniel Veillard01fa6152004-06-29 17:04:39 +00004063 /*
4064 * FIXME: What exactly to do with anyURI?
4065 */
4066 case XML_SCHEMAS_ANYURI:
William M. Brackfbf2c5e2004-02-03 17:55:56 +00004067 if (value != NULL)
4068 len = xmlUTF8Strlen(value);
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004069 break;
Daniel Veillard560c2a42003-07-06 21:13:49 +00004070 default:
4071 TODO
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004072 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004073 }
4074 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004075 if (len != facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004076 return(XML_SCHEMAV_CVC_LENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004077 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
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_MINLENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004080 } else {
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_MAXLENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004083 }
4084 break;
4085 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00004086 case XML_SCHEMA_FACET_TOTALDIGITS:
4087 case XML_SCHEMA_FACET_FRACTIONDIGITS:
4088
4089 if ((facet->val == NULL) ||
4090 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
4091 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
4092 (facet->val->value.decimal.frac != 0)) {
4093 return(-1);
4094 }
4095 if ((val == NULL) ||
4096 ((val->type != XML_SCHEMAS_DECIMAL) &&
4097 (val->type != XML_SCHEMAS_INTEGER) &&
4098 (val->type != XML_SCHEMAS_NPINTEGER) &&
4099 (val->type != XML_SCHEMAS_NINTEGER) &&
4100 (val->type != XML_SCHEMAS_NNINTEGER) &&
4101 (val->type != XML_SCHEMAS_PINTEGER) &&
4102 (val->type != XML_SCHEMAS_INT) &&
4103 (val->type != XML_SCHEMAS_UINT) &&
4104 (val->type != XML_SCHEMAS_LONG) &&
4105 (val->type != XML_SCHEMAS_ULONG) &&
4106 (val->type != XML_SCHEMAS_SHORT) &&
4107 (val->type != XML_SCHEMAS_USHORT) &&
4108 (val->type != XML_SCHEMAS_BYTE) &&
4109 (val->type != XML_SCHEMAS_UBYTE))) {
4110 return(-1);
4111 }
4112 if (facet->type == XML_SCHEMA_FACET_TOTALDIGITS) {
4113 if (val->value.decimal.total > facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004114 return(XML_SCHEMAV_CVC_TOTALDIGITS_VALID);
Daniel Veillard560c2a42003-07-06 21:13:49 +00004115
4116 } else if (facet->type == XML_SCHEMA_FACET_FRACTIONDIGITS) {
4117 if (val->value.decimal.frac > facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004118 return(XML_SCHEMAV_CVC_FRACTIONDIGITS_VALID);
Daniel Veillard560c2a42003-07-06 21:13:49 +00004119 }
4120 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00004121 default:
4122 TODO
4123 }
4124 return(0);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00004125
Daniel Veillard4255d502002-04-16 15:50:10 +00004126}
4127
4128#endif /* LIBXML_SCHEMAS_ENABLED */