blob: 83aaa7b691d37d7de064967590cc18e143bd1b97 [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
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +000048#define IS_WSP_REPLACE_CH(c) ((((c) == 0x9) || ((c) == 0xa)) || \
49 ((c) == 0xd))
50
51#define IS_WSP_SPACE_CH(c) ((c) == 0x20)
52
Daniel Veillard4255d502002-04-16 15:50:10 +000053
Daniel Veillard5f704af2003-03-05 10:01:43 +000054static unsigned long powten[10] = {
Daniel Veillard4255d502002-04-16 15:50:10 +000055 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000L,
56 100000000L, 1000000000L
57};
58
Daniel Veillard01fa6152004-06-29 17:04:39 +000059
Daniel Veillard070803b2002-05-03 07:29:38 +000060/* Date value */
61typedef struct _xmlSchemaValDate xmlSchemaValDate;
62typedef xmlSchemaValDate *xmlSchemaValDatePtr;
63struct _xmlSchemaValDate {
64 long year;
65 unsigned int mon :4; /* 1 <= mon <= 12 */
66 unsigned int day :5; /* 1 <= day <= 31 */
67 unsigned int hour :5; /* 0 <= hour <= 23 */
68 unsigned int min :6; /* 0 <= min <= 59 */
69 double sec;
Daniel Veillarda77cf712003-05-09 23:09:55 +000070 unsigned int tz_flag :1; /* is tzo explicitely set? */
Daniel Veillard070803b2002-05-03 07:29:38 +000071 int tzo :11; /* -1440 <= tzo <= 1440 */
72};
73
74/* Duration value */
75typedef struct _xmlSchemaValDuration xmlSchemaValDuration;
76typedef xmlSchemaValDuration *xmlSchemaValDurationPtr;
77struct _xmlSchemaValDuration {
78 long mon; /* mon stores years also */
79 long day;
80 double sec; /* sec stores min and hour also */
81};
82
Daniel Veillard4255d502002-04-16 15:50:10 +000083typedef struct _xmlSchemaValDecimal xmlSchemaValDecimal;
84typedef xmlSchemaValDecimal *xmlSchemaValDecimalPtr;
85struct _xmlSchemaValDecimal {
86 /* would use long long but not portable */
Daniel Veillarde637c4a2003-03-30 21:10:09 +000087 unsigned long lo;
88 unsigned long mi;
89 unsigned long hi;
Daniel Veillard4255d502002-04-16 15:50:10 +000090 unsigned int extra;
Daniel Veillard5a872412002-05-22 06:40:27 +000091 unsigned int sign:1;
William M. Brackc1939562003-08-05 15:52:22 +000092 unsigned int frac:7;
93 unsigned int total:8;
Daniel Veillard4255d502002-04-16 15:50:10 +000094};
95
Daniel Veillarde637c4a2003-03-30 21:10:09 +000096typedef struct _xmlSchemaValQName xmlSchemaValQName;
97typedef xmlSchemaValQName *xmlSchemaValQNamePtr;
98struct _xmlSchemaValQName {
99 xmlChar *name;
100 xmlChar *uri;
101};
102
Daniel Veillard70bcb0e2003-08-08 14:00:28 +0000103typedef struct _xmlSchemaValHex xmlSchemaValHex;
104typedef xmlSchemaValHex *xmlSchemaValHexPtr;
105struct _xmlSchemaValHex {
106 xmlChar *str;
107 unsigned int total;
108};
109
Daniel Veillard1ac24d32003-08-27 14:15:15 +0000110typedef struct _xmlSchemaValBase64 xmlSchemaValBase64;
111typedef xmlSchemaValBase64 *xmlSchemaValBase64Ptr;
112struct _xmlSchemaValBase64 {
113 xmlChar *str;
114 unsigned int total;
115};
116
Daniel Veillard4255d502002-04-16 15:50:10 +0000117struct _xmlSchemaVal {
118 xmlSchemaValType type;
119 union {
Daniel Veillard5a872412002-05-22 06:40:27 +0000120 xmlSchemaValDecimal decimal;
Daniel Veillard070803b2002-05-03 07:29:38 +0000121 xmlSchemaValDate date;
122 xmlSchemaValDuration dur;
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000123 xmlSchemaValQName qname;
Daniel Veillard70bcb0e2003-08-08 14:00:28 +0000124 xmlSchemaValHex hex;
Daniel Veillard1ac24d32003-08-27 14:15:15 +0000125 xmlSchemaValBase64 base64;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000126 float f;
127 double d;
Daniel Veillardc5a70f22003-02-06 23:41:59 +0000128 int b;
Daniel Veillardc4c21552003-03-29 10:53:38 +0000129 xmlChar *str;
Daniel Veillard4255d502002-04-16 15:50:10 +0000130 } value;
131};
132
133static int xmlSchemaTypesInitialized = 0;
134static xmlHashTablePtr xmlSchemaTypesBank = NULL;
135
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000136/*
137 * Basic types
138 */
Daniel Veillard4255d502002-04-16 15:50:10 +0000139static xmlSchemaTypePtr xmlSchemaTypeStringDef = NULL;
140static xmlSchemaTypePtr xmlSchemaTypeAnyTypeDef = NULL;
141static xmlSchemaTypePtr xmlSchemaTypeAnySimpleTypeDef = NULL;
142static xmlSchemaTypePtr xmlSchemaTypeDecimalDef = NULL;
Daniel Veillard070803b2002-05-03 07:29:38 +0000143static xmlSchemaTypePtr xmlSchemaTypeDatetimeDef = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +0000144static xmlSchemaTypePtr xmlSchemaTypeDateDef = NULL;
Daniel Veillard070803b2002-05-03 07:29:38 +0000145static xmlSchemaTypePtr xmlSchemaTypeTimeDef = NULL;
146static xmlSchemaTypePtr xmlSchemaTypeGYearDef = NULL;
147static xmlSchemaTypePtr xmlSchemaTypeGYearMonthDef = NULL;
148static xmlSchemaTypePtr xmlSchemaTypeGDayDef = NULL;
149static xmlSchemaTypePtr xmlSchemaTypeGMonthDayDef = NULL;
150static xmlSchemaTypePtr xmlSchemaTypeGMonthDef = NULL;
151static xmlSchemaTypePtr xmlSchemaTypeDurationDef = NULL;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000152static xmlSchemaTypePtr xmlSchemaTypeFloatDef = NULL;
Daniel Veillardc5a70f22003-02-06 23:41:59 +0000153static xmlSchemaTypePtr xmlSchemaTypeBooleanDef = NULL;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000154static xmlSchemaTypePtr xmlSchemaTypeDoubleDef = NULL;
Daniel Veillard560c2a42003-07-06 21:13:49 +0000155static xmlSchemaTypePtr xmlSchemaTypeHexBinaryDef = NULL;
Daniel Veillard1ac24d32003-08-27 14:15:15 +0000156static xmlSchemaTypePtr xmlSchemaTypeBase64BinaryDef = NULL;
Daniel Veillarde5b110b2003-02-04 14:43:39 +0000157static xmlSchemaTypePtr xmlSchemaTypeAnyURIDef = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +0000158
159/*
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000160 * Derived types
161 */
162static xmlSchemaTypePtr xmlSchemaTypePositiveIntegerDef = NULL;
163static xmlSchemaTypePtr xmlSchemaTypeNonPositiveIntegerDef = NULL;
164static xmlSchemaTypePtr xmlSchemaTypeNegativeIntegerDef = NULL;
165static xmlSchemaTypePtr xmlSchemaTypeNonNegativeIntegerDef = NULL;
166static xmlSchemaTypePtr xmlSchemaTypeIntegerDef = NULL;
167static xmlSchemaTypePtr xmlSchemaTypeLongDef = NULL;
168static xmlSchemaTypePtr xmlSchemaTypeIntDef = NULL;
169static xmlSchemaTypePtr xmlSchemaTypeShortDef = NULL;
170static xmlSchemaTypePtr xmlSchemaTypeByteDef = NULL;
171static xmlSchemaTypePtr xmlSchemaTypeUnsignedLongDef = NULL;
172static xmlSchemaTypePtr xmlSchemaTypeUnsignedIntDef = NULL;
173static xmlSchemaTypePtr xmlSchemaTypeUnsignedShortDef = NULL;
174static xmlSchemaTypePtr xmlSchemaTypeUnsignedByteDef = NULL;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000175static xmlSchemaTypePtr xmlSchemaTypeNormStringDef = NULL;
176static xmlSchemaTypePtr xmlSchemaTypeTokenDef = NULL;
177static xmlSchemaTypePtr xmlSchemaTypeLanguageDef = NULL;
178static xmlSchemaTypePtr xmlSchemaTypeNameDef = NULL;
179static xmlSchemaTypePtr xmlSchemaTypeQNameDef = NULL;
Daniel Veillarde5b110b2003-02-04 14:43:39 +0000180static xmlSchemaTypePtr xmlSchemaTypeNCNameDef = NULL;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000181static xmlSchemaTypePtr xmlSchemaTypeIdDef = NULL;
182static xmlSchemaTypePtr xmlSchemaTypeIdrefDef = NULL;
183static xmlSchemaTypePtr xmlSchemaTypeIdrefsDef = NULL;
Daniel Veillarda1a9d042003-03-18 16:53:17 +0000184static xmlSchemaTypePtr xmlSchemaTypeEntityDef = NULL;
185static xmlSchemaTypePtr xmlSchemaTypeEntitiesDef = NULL;
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000186static xmlSchemaTypePtr xmlSchemaTypeNotationDef = NULL;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000187static xmlSchemaTypePtr xmlSchemaTypeNmtokenDef = NULL;
188static xmlSchemaTypePtr xmlSchemaTypeNmtokensDef = NULL;
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000189
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000190/************************************************************************
191 * *
192 * Datatype error handlers *
193 * *
194 ************************************************************************/
195/**
196 * xmlSchemaTypeErrMemory:
197 * @extra: extra informations
198 *
199 * Handle an out of memory condition
200 */
201static void
202xmlSchemaTypeErrMemory(xmlNodePtr node, const char *extra)
203{
204 __xmlSimpleError(XML_FROM_DATATYPE, XML_ERR_NO_MEMORY, node, NULL, extra);
205}
206
207/************************************************************************
208 * *
209 * Base types support *
210 * *
211 ************************************************************************/
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000212/*
Daniel Veillard4255d502002-04-16 15:50:10 +0000213 * xmlSchemaInitBasicType:
214 * @name: the type name
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000215 * @type: the value type associated
Daniel Veillard4255d502002-04-16 15:50:10 +0000216 *
Daniel Veillard01fa6152004-06-29 17:04:39 +0000217 * Initialize one primitive built-in type
Daniel Veillard4255d502002-04-16 15:50:10 +0000218 */
219static xmlSchemaTypePtr
Daniel Veillard01fa6152004-06-29 17:04:39 +0000220xmlSchemaInitBasicType(const char *name, xmlSchemaValType type,
221 xmlSchemaTypePtr baseType) {
Daniel Veillard4255d502002-04-16 15:50:10 +0000222 xmlSchemaTypePtr ret;
223
224 ret = (xmlSchemaTypePtr) xmlMalloc(sizeof(xmlSchemaType));
225 if (ret == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000226 xmlSchemaTypeErrMemory(NULL, "could not initialize basic types");
Daniel Veillard4255d502002-04-16 15:50:10 +0000227 return(NULL);
228 }
229 memset(ret, 0, sizeof(xmlSchemaType));
Daniel Veillardbe9c6322003-11-22 20:37:51 +0000230 ret->name = (const xmlChar *)name;
Daniel Veillard4255d502002-04-16 15:50:10 +0000231 ret->type = XML_SCHEMA_TYPE_BASIC;
Daniel Veillard01fa6152004-06-29 17:04:39 +0000232 ret->baseType = baseType;
233 /*
234 * Hack to reflect the variety.
235 */
236 if ((type == XML_SCHEMAS_IDREFS) ||
237 (type == XML_SCHEMAS_NMTOKENS) ||
238 (type == XML_SCHEMAS_ENTITIES))
239 ret->flags |= XML_SCHEMAS_TYPE_VARIETY_LIST;
William M. Brack2f2a6632004-08-20 23:09:47 +0000240 else if ((type != XML_SCHEMAS_ANYTYPE) &&
241 (type != XML_SCHEMAS_ANYSIMPLETYPE))
Daniel Veillard01fa6152004-06-29 17:04:39 +0000242 ret->flags |= XML_SCHEMAS_TYPE_VARIETY_ATOMIC;
Daniel Veillard4255d502002-04-16 15:50:10 +0000243 ret->contentType = XML_SCHEMA_CONTENT_BASIC;
Daniel Veillard01fa6152004-06-29 17:04:39 +0000244 switch (type) {
245 case XML_SCHEMAS_STRING:
246 case XML_SCHEMAS_DECIMAL:
247 case XML_SCHEMAS_DATE:
248 case XML_SCHEMAS_DATETIME:
249 case XML_SCHEMAS_TIME:
250 case XML_SCHEMAS_GYEAR:
251 case XML_SCHEMAS_GYEARMONTH:
252 case XML_SCHEMAS_GMONTH:
253 case XML_SCHEMAS_GMONTHDAY:
254 case XML_SCHEMAS_GDAY:
255 case XML_SCHEMAS_DURATION:
256 case XML_SCHEMAS_FLOAT:
257 case XML_SCHEMAS_DOUBLE:
258 case XML_SCHEMAS_BOOLEAN:
259 case XML_SCHEMAS_ANYURI:
260 case XML_SCHEMAS_HEXBINARY:
261 case XML_SCHEMAS_BASE64BINARY:
262 case XML_SCHEMAS_QNAME:
263 case XML_SCHEMAS_NOTATION:
264 ret->flags |= XML_SCHEMAS_TYPE_BUILTIN_PRIMITIVE;
William M. Brack96d2eff2004-06-30 11:48:47 +0000265 default:
266 break;
Daniel Veillard01fa6152004-06-29 17:04:39 +0000267 }
268
Daniel Veillard4255d502002-04-16 15:50:10 +0000269 xmlHashAddEntry2(xmlSchemaTypesBank, ret->name,
270 XML_SCHEMAS_NAMESPACE_NAME, ret);
Daniel Veillard01fa6152004-06-29 17:04:39 +0000271 ret->builtInType = type;
Daniel Veillard4255d502002-04-16 15:50:10 +0000272 return(ret);
273}
274
275/*
276 * xmlSchemaInitTypes:
277 *
278 * Initialize the default XML Schemas type library
279 */
280void
Daniel Veillard6560a422003-03-27 21:25:38 +0000281xmlSchemaInitTypes(void)
282{
Daniel Veillard4255d502002-04-16 15:50:10 +0000283 if (xmlSchemaTypesInitialized != 0)
Daniel Veillard6560a422003-03-27 21:25:38 +0000284 return;
Daniel Veillard4255d502002-04-16 15:50:10 +0000285 xmlSchemaTypesBank = xmlHashCreate(40);
Daniel Veillard6560a422003-03-27 21:25:38 +0000286
Daniel Veillard01fa6152004-06-29 17:04:39 +0000287
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000288 /*
Daniel Veillard01fa6152004-06-29 17:04:39 +0000289 * 3.4.7 Built-in Complex Type Definition
290 */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000291 xmlSchemaTypeAnyTypeDef = xmlSchemaInitBasicType("anyType",
William M. Brack2f2a6632004-08-20 23:09:47 +0000292 XML_SCHEMAS_ANYTYPE,
Daniel Veillard01fa6152004-06-29 17:04:39 +0000293 NULL);
294 xmlSchemaTypeAnyTypeDef->baseType = xmlSchemaTypeAnyTypeDef;
295 xmlSchemaTypeAnyTypeDef->contentType = XML_SCHEMA_CONTENT_MIXED;
296 {
297 xmlSchemaWildcardPtr wild;
298
299 wild = (xmlSchemaWildcardPtr) xmlMalloc(sizeof(xmlSchemaWildcard));
300 if (wild == NULL) {
William M. Brack2f2a6632004-08-20 23:09:47 +0000301 xmlSchemaTypeErrMemory(NULL, "could not create an attribute wildcard on anyType");
Daniel Veillard01fa6152004-06-29 17:04:39 +0000302 return;
303 }
304 memset(wild, 0, sizeof(xmlSchemaWildcard));
305 wild->any = 1;
306 wild->processContents = XML_SCHEMAS_ANY_LAX;
307 wild->minOccurs = 1;
308 wild->maxOccurs = 1;
309 xmlSchemaTypeAnyTypeDef->attributeWildcard = wild;
310 }
311 xmlSchemaTypeAnySimpleTypeDef = xmlSchemaInitBasicType("anySimpleType",
William M. Brack2f2a6632004-08-20 23:09:47 +0000312 XML_SCHEMAS_ANYSIMPLETYPE,
Daniel Veillard01fa6152004-06-29 17:04:39 +0000313 xmlSchemaTypeAnyTypeDef);
314 /*
315 * primitive datatypes
316 */
317 xmlSchemaTypeStringDef = xmlSchemaInitBasicType("string",
318 XML_SCHEMAS_STRING,
319 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000320 xmlSchemaTypeDecimalDef = xmlSchemaInitBasicType("decimal",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000321 XML_SCHEMAS_DECIMAL,
322 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000323 xmlSchemaTypeDateDef = xmlSchemaInitBasicType("date",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000324 XML_SCHEMAS_DATE,
325 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000326 xmlSchemaTypeDatetimeDef = xmlSchemaInitBasicType("dateTime",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000327 XML_SCHEMAS_DATETIME,
328 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000329 xmlSchemaTypeTimeDef = xmlSchemaInitBasicType("time",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000330 XML_SCHEMAS_TIME,
331 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000332 xmlSchemaTypeGYearDef = xmlSchemaInitBasicType("gYear",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000333 XML_SCHEMAS_GYEAR,
334 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000335 xmlSchemaTypeGYearMonthDef = xmlSchemaInitBasicType("gYearMonth",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000336 XML_SCHEMAS_GYEARMONTH,
337 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000338 xmlSchemaTypeGMonthDef = xmlSchemaInitBasicType("gMonth",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000339 XML_SCHEMAS_GMONTH,
340 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000341 xmlSchemaTypeGMonthDayDef = xmlSchemaInitBasicType("gMonthDay",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000342 XML_SCHEMAS_GMONTHDAY,
343 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000344 xmlSchemaTypeGDayDef = xmlSchemaInitBasicType("gDay",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000345 XML_SCHEMAS_GDAY,
346 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000347 xmlSchemaTypeDurationDef = xmlSchemaInitBasicType("duration",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000348 XML_SCHEMAS_DURATION,
349 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000350 xmlSchemaTypeFloatDef = xmlSchemaInitBasicType("float",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000351 XML_SCHEMAS_FLOAT,
352 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000353 xmlSchemaTypeDoubleDef = xmlSchemaInitBasicType("double",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000354 XML_SCHEMAS_DOUBLE,
355 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000356 xmlSchemaTypeBooleanDef = xmlSchemaInitBasicType("boolean",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000357 XML_SCHEMAS_BOOLEAN,
358 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000359 xmlSchemaTypeAnyURIDef = xmlSchemaInitBasicType("anyURI",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000360 XML_SCHEMAS_ANYURI,
361 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard560c2a42003-07-06 21:13:49 +0000362 xmlSchemaTypeHexBinaryDef = xmlSchemaInitBasicType("hexBinary",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000363 XML_SCHEMAS_HEXBINARY,
364 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard1ac24d32003-08-27 14:15:15 +0000365 xmlSchemaTypeBase64BinaryDef
Daniel Veillard01fa6152004-06-29 17:04:39 +0000366 = xmlSchemaInitBasicType("base64Binary", XML_SCHEMAS_BASE64BINARY,
367 xmlSchemaTypeAnySimpleTypeDef);
368 xmlSchemaTypeNotationDef = xmlSchemaInitBasicType("NOTATION",
369 XML_SCHEMAS_NOTATION,
370 xmlSchemaTypeAnySimpleTypeDef);
371 xmlSchemaTypeQNameDef = xmlSchemaInitBasicType("QName",
372 XML_SCHEMAS_QNAME,
373 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard4255d502002-04-16 15:50:10 +0000374
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000375 /*
376 * derived datatypes
377 */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000378 xmlSchemaTypeIntegerDef = xmlSchemaInitBasicType("integer",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000379 XML_SCHEMAS_INTEGER,
380 xmlSchemaTypeDecimalDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000381 xmlSchemaTypeNonPositiveIntegerDef =
382 xmlSchemaInitBasicType("nonPositiveInteger",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000383 XML_SCHEMAS_NPINTEGER,
384 xmlSchemaTypeIntegerDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000385 xmlSchemaTypeNegativeIntegerDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000386 xmlSchemaInitBasicType("negativeInteger", XML_SCHEMAS_NINTEGER,
387 xmlSchemaTypeNonPositiveIntegerDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000388 xmlSchemaTypeLongDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000389 xmlSchemaInitBasicType("long", XML_SCHEMAS_LONG,
390 xmlSchemaTypeIntegerDef);
391 xmlSchemaTypeIntDef = xmlSchemaInitBasicType("int", XML_SCHEMAS_INT,
392 xmlSchemaTypeLongDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000393 xmlSchemaTypeShortDef = xmlSchemaInitBasicType("short",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000394 XML_SCHEMAS_SHORT,
395 xmlSchemaTypeIntDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000396 xmlSchemaTypeByteDef = xmlSchemaInitBasicType("byte",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000397 XML_SCHEMAS_BYTE,
398 xmlSchemaTypeShortDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000399 xmlSchemaTypeNonNegativeIntegerDef =
400 xmlSchemaInitBasicType("nonNegativeInteger",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000401 XML_SCHEMAS_NNINTEGER,
402 xmlSchemaTypeIntegerDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000403 xmlSchemaTypeUnsignedLongDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000404 xmlSchemaInitBasicType("unsignedLong", XML_SCHEMAS_ULONG,
405 xmlSchemaTypeNonNegativeIntegerDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000406 xmlSchemaTypeUnsignedIntDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000407 xmlSchemaInitBasicType("unsignedInt", XML_SCHEMAS_UINT,
408 xmlSchemaTypeUnsignedLongDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000409 xmlSchemaTypeUnsignedShortDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000410 xmlSchemaInitBasicType("unsignedShort", XML_SCHEMAS_USHORT,
411 xmlSchemaTypeUnsignedIntDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000412 xmlSchemaTypeUnsignedByteDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000413 xmlSchemaInitBasicType("unsignedByte", XML_SCHEMAS_UBYTE,
414 xmlSchemaTypeUnsignedShortDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000415 xmlSchemaTypePositiveIntegerDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000416 xmlSchemaInitBasicType("positiveInteger", XML_SCHEMAS_PINTEGER,
417 xmlSchemaTypeNonNegativeIntegerDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000418 xmlSchemaTypeNormStringDef = xmlSchemaInitBasicType("normalizedString",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000419 XML_SCHEMAS_NORMSTRING,
420 xmlSchemaTypeStringDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000421 xmlSchemaTypeTokenDef = xmlSchemaInitBasicType("token",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000422 XML_SCHEMAS_TOKEN,
423 xmlSchemaTypeNormStringDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000424 xmlSchemaTypeLanguageDef = xmlSchemaInitBasicType("language",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000425 XML_SCHEMAS_LANGUAGE,
426 xmlSchemaTypeTokenDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000427 xmlSchemaTypeNameDef = xmlSchemaInitBasicType("Name",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000428 XML_SCHEMAS_NAME,
429 xmlSchemaTypeTokenDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000430 xmlSchemaTypeNmtokenDef = xmlSchemaInitBasicType("NMTOKEN",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000431 XML_SCHEMAS_NMTOKEN,
432 xmlSchemaTypeTokenDef);
433 xmlSchemaTypeNCNameDef = xmlSchemaInitBasicType("NCName",
434 XML_SCHEMAS_NCNAME,
435 xmlSchemaTypeNameDef);
436 xmlSchemaTypeIdDef = xmlSchemaInitBasicType("ID", XML_SCHEMAS_ID,
437 xmlSchemaTypeNCNameDef);
438 xmlSchemaTypeIdrefDef = xmlSchemaInitBasicType("IDREF",
439 XML_SCHEMAS_IDREF,
440 xmlSchemaTypeNCNameDef);
441 xmlSchemaTypeIdrefsDef = xmlSchemaInitBasicType("IDREFS",
442 XML_SCHEMAS_IDREFS,
443 xmlSchemaTypeIdrefDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000444 xmlSchemaTypeNmtokensDef = xmlSchemaInitBasicType("NMTOKENS",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000445 XML_SCHEMAS_NMTOKENS,
446 xmlSchemaTypeNmtokenDef);
447 xmlSchemaTypeEntityDef = xmlSchemaInitBasicType("ENTITY",
448 XML_SCHEMAS_ENTITY,
449 xmlSchemaTypeNCNameDef);
450 xmlSchemaTypeEntitiesDef = xmlSchemaInitBasicType("ENTITIES",
451 XML_SCHEMAS_ENTITIES,
452 xmlSchemaTypeNCNameDef);
Daniel Veillard4255d502002-04-16 15:50:10 +0000453 xmlSchemaTypesInitialized = 1;
454}
455
456/**
457 * xmlSchemaCleanupTypes:
458 *
459 * Cleanup the default XML Schemas type library
460 */
461void
462xmlSchemaCleanupTypes(void) {
463 if (xmlSchemaTypesInitialized == 0)
464 return;
Daniel Veillard01fa6152004-06-29 17:04:39 +0000465 xmlSchemaFreeWildcard(xmlSchemaTypeAnyTypeDef->attributeWildcard);
Daniel Veillard4255d502002-04-16 15:50:10 +0000466 xmlHashFree(xmlSchemaTypesBank, (xmlHashDeallocator) xmlSchemaFreeType);
467 xmlSchemaTypesInitialized = 0;
468}
469
470/**
Daniel Veillard6927b102004-10-27 17:29:04 +0000471 * xmlSchemaIsBuiltInTypeFacet:
Daniel Veillard01fa6152004-06-29 17:04:39 +0000472 * @type: the built-in type
473 * @facetType: the facet type
474 *
475 * Evaluates if a specific facet can be
476 * used in conjunction with a type.
477 *
478 * Returns 1 if the facet can be used with the given built-in type,
479 * 0 otherwise and -1 in case the type is not a built-in type.
480 */
481int
482xmlSchemaIsBuiltInTypeFacet(xmlSchemaTypePtr type, int facetType)
483{
Daniel Veillardce682bc2004-11-05 17:22:25 +0000484 if (type == NULL)
485 return (-1);
Daniel Veillard01fa6152004-06-29 17:04:39 +0000486 if (type->type != XML_SCHEMA_TYPE_BASIC)
487 return (-1);
488 switch (type->builtInType) {
489 case XML_SCHEMAS_BOOLEAN:
490 if ((facetType == XML_SCHEMA_FACET_PATTERN) ||
491 (facetType == XML_SCHEMA_FACET_WHITESPACE))
492 return (1);
493 else
494 return (0);
495 case XML_SCHEMAS_STRING:
496 case XML_SCHEMAS_NOTATION:
497 case XML_SCHEMAS_QNAME:
498 case XML_SCHEMAS_ANYURI:
499 case XML_SCHEMAS_BASE64BINARY:
500 case XML_SCHEMAS_HEXBINARY:
501 if ((facetType == XML_SCHEMA_FACET_LENGTH) ||
502 (facetType == XML_SCHEMA_FACET_MINLENGTH) ||
503 (facetType == XML_SCHEMA_FACET_MAXLENGTH) ||
504 (facetType == XML_SCHEMA_FACET_PATTERN) ||
505 (facetType == XML_SCHEMA_FACET_ENUMERATION) ||
506 (facetType == XML_SCHEMA_FACET_WHITESPACE))
507 return (1);
508 else
509 return (0);
510 case XML_SCHEMAS_DECIMAL:
511 if ((facetType == XML_SCHEMA_FACET_TOTALDIGITS) ||
512 (facetType == XML_SCHEMA_FACET_FRACTIONDIGITS) ||
513 (facetType == XML_SCHEMA_FACET_PATTERN) ||
514 (facetType == XML_SCHEMA_FACET_WHITESPACE) ||
515 (facetType == XML_SCHEMA_FACET_ENUMERATION) ||
516 (facetType == XML_SCHEMA_FACET_MAXINCLUSIVE) ||
517 (facetType == XML_SCHEMA_FACET_MAXEXCLUSIVE) ||
518 (facetType == XML_SCHEMA_FACET_MININCLUSIVE) ||
519 (facetType == XML_SCHEMA_FACET_MINEXCLUSIVE))
520 return (1);
521 else
522 return (0);
523 case XML_SCHEMAS_TIME:
524 case XML_SCHEMAS_GDAY:
525 case XML_SCHEMAS_GMONTH:
526 case XML_SCHEMAS_GMONTHDAY:
527 case XML_SCHEMAS_GYEAR:
528 case XML_SCHEMAS_GYEARMONTH:
529 case XML_SCHEMAS_DATE:
530 case XML_SCHEMAS_DATETIME:
531 case XML_SCHEMAS_DURATION:
532 case XML_SCHEMAS_FLOAT:
533 case XML_SCHEMAS_DOUBLE:
534 if ((facetType == XML_SCHEMA_FACET_PATTERN) ||
535 (facetType == XML_SCHEMA_FACET_ENUMERATION) ||
536 (facetType == XML_SCHEMA_FACET_WHITESPACE) ||
537 (facetType == XML_SCHEMA_FACET_MAXINCLUSIVE) ||
538 (facetType == XML_SCHEMA_FACET_MAXEXCLUSIVE) ||
539 (facetType == XML_SCHEMA_FACET_MININCLUSIVE) ||
540 (facetType == XML_SCHEMA_FACET_MINEXCLUSIVE))
541 return (1);
542 else
543 return (0);
544 default:
Daniel Veillardc7e3cc42004-09-28 12:33:52 +0000545 break;
Daniel Veillard01fa6152004-06-29 17:04:39 +0000546 }
547 return (0);
548}
549
550/**
551 * xmlSchemaGetBuiltInType:
552 * @type: the type of the built in type
553 *
554 * Gives you the type struct for a built-in
555 * type by its type id.
556 *
557 * Returns the type if found, NULL otherwise.
558 */
559xmlSchemaTypePtr
560xmlSchemaGetBuiltInType(xmlSchemaValType type)
561{
562 if (xmlSchemaTypesInitialized == 0)
563 xmlSchemaInitTypes();
564 switch (type) {
565
566 case XML_SCHEMAS_ANYSIMPLETYPE:
567 return (xmlSchemaTypeAnySimpleTypeDef);
568 case XML_SCHEMAS_STRING:
569 return (xmlSchemaTypeStringDef);
570 case XML_SCHEMAS_NORMSTRING:
571 return (xmlSchemaTypeNormStringDef);
572 case XML_SCHEMAS_DECIMAL:
573 return (xmlSchemaTypeDecimalDef);
574 case XML_SCHEMAS_TIME:
575 return (xmlSchemaTypeTimeDef);
576 case XML_SCHEMAS_GDAY:
577 return (xmlSchemaTypeGDayDef);
578 case XML_SCHEMAS_GMONTH:
579 return (xmlSchemaTypeGMonthDef);
580 case XML_SCHEMAS_GMONTHDAY:
581 return (xmlSchemaTypeGMonthDayDef);
582 case XML_SCHEMAS_GYEAR:
583 return (xmlSchemaTypeGYearDef);
584 case XML_SCHEMAS_GYEARMONTH:
585 return (xmlSchemaTypeGYearMonthDef);
586 case XML_SCHEMAS_DATE:
587 return (xmlSchemaTypeDateDef);
588 case XML_SCHEMAS_DATETIME:
589 return (xmlSchemaTypeDatetimeDef);
590 case XML_SCHEMAS_DURATION:
591 return (xmlSchemaTypeDurationDef);
592 case XML_SCHEMAS_FLOAT:
593 return (xmlSchemaTypeFloatDef);
594 case XML_SCHEMAS_DOUBLE:
595 return (xmlSchemaTypeDoubleDef);
596 case XML_SCHEMAS_BOOLEAN:
597 return (xmlSchemaTypeBooleanDef);
598 case XML_SCHEMAS_TOKEN:
599 return (xmlSchemaTypeTokenDef);
600 case XML_SCHEMAS_LANGUAGE:
601 return (xmlSchemaTypeLanguageDef);
602 case XML_SCHEMAS_NMTOKEN:
603 return (xmlSchemaTypeNmtokenDef);
604 case XML_SCHEMAS_NMTOKENS:
605 return (xmlSchemaTypeNmtokensDef);
606 case XML_SCHEMAS_NAME:
607 return (xmlSchemaTypeNameDef);
608 case XML_SCHEMAS_QNAME:
609 return (xmlSchemaTypeQNameDef);
610 case XML_SCHEMAS_NCNAME:
611 return (xmlSchemaTypeNCNameDef);
612 case XML_SCHEMAS_ID:
613 return (xmlSchemaTypeIdDef);
614 case XML_SCHEMAS_IDREF:
615 return (xmlSchemaTypeIdrefDef);
616 case XML_SCHEMAS_IDREFS:
617 return (xmlSchemaTypeIdrefsDef);
618 case XML_SCHEMAS_ENTITY:
619 return (xmlSchemaTypeEntityDef);
620 case XML_SCHEMAS_ENTITIES:
621 return (xmlSchemaTypeEntitiesDef);
622 case XML_SCHEMAS_NOTATION:
623 return (xmlSchemaTypeNotationDef);
624 case XML_SCHEMAS_ANYURI:
625 return (xmlSchemaTypeAnyURIDef);
626 case XML_SCHEMAS_INTEGER:
627 return (xmlSchemaTypeIntegerDef);
628 case XML_SCHEMAS_NPINTEGER:
629 return (xmlSchemaTypeNonPositiveIntegerDef);
630 case XML_SCHEMAS_NINTEGER:
631 return (xmlSchemaTypeNegativeIntegerDef);
632 case XML_SCHEMAS_NNINTEGER:
633 return (xmlSchemaTypeNonNegativeIntegerDef);
634 case XML_SCHEMAS_PINTEGER:
635 return (xmlSchemaTypePositiveIntegerDef);
636 case XML_SCHEMAS_INT:
637 return (xmlSchemaTypeIntDef);
638 case XML_SCHEMAS_UINT:
639 return (xmlSchemaTypeUnsignedIntDef);
640 case XML_SCHEMAS_LONG:
641 return (xmlSchemaTypeLongDef);
642 case XML_SCHEMAS_ULONG:
643 return (xmlSchemaTypeUnsignedLongDef);
644 case XML_SCHEMAS_SHORT:
645 return (xmlSchemaTypeShortDef);
646 case XML_SCHEMAS_USHORT:
647 return (xmlSchemaTypeUnsignedShortDef);
648 case XML_SCHEMAS_BYTE:
649 return (xmlSchemaTypeByteDef);
650 case XML_SCHEMAS_UBYTE:
651 return (xmlSchemaTypeUnsignedByteDef);
652 case XML_SCHEMAS_HEXBINARY:
653 return (xmlSchemaTypeHexBinaryDef);
654 case XML_SCHEMAS_BASE64BINARY:
655 return (xmlSchemaTypeBase64BinaryDef);
656 case XML_SCHEMAS_ANYTYPE:
657 return (xmlSchemaTypeAnyTypeDef);
658 default:
659 return (NULL);
660 }
661}
662
663/**
Daniel Veillard4255d502002-04-16 15:50:10 +0000664 * xmlSchemaNewValue:
665 * @type: the value type
666 *
667 * Allocate a new simple type value
668 *
669 * Returns a pointer to the new value or NULL in case of error
670 */
671static xmlSchemaValPtr
672xmlSchemaNewValue(xmlSchemaValType type) {
673 xmlSchemaValPtr value;
674
675 value = (xmlSchemaValPtr) xmlMalloc(sizeof(xmlSchemaVal));
676 if (value == NULL) {
677 return(NULL);
678 }
679 memset(value, 0, sizeof(xmlSchemaVal));
680 value->type = type;
681 return(value);
682}
683
684/**
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +0000685 * xmlSchemaNewStringValue:
686 * @type: the value type
687 *
688 * Allocate a new simple type value. The type can be
689 * of XML_SCHEMAS_STRING.
690 *
691 * Returns a pointer to the new value or NULL in case of error
692 */
693xmlSchemaValPtr
694xmlSchemaNewStringValue(xmlSchemaValType type,
695 const xmlChar *value)
696{
697 xmlSchemaValPtr val;
698
699 if (type != XML_SCHEMAS_STRING)
700 return(NULL);
701 val = (xmlSchemaValPtr) xmlMalloc(sizeof(xmlSchemaVal));
702 if (val == NULL) {
703 return(NULL);
704 }
705 memset(val, 0, sizeof(xmlSchemaVal));
706 val->type = type;
707 val->value.str = (xmlChar *) value;
708 return(val);
709}
710
711
712/**
Daniel Veillard4255d502002-04-16 15:50:10 +0000713 * xmlSchemaFreeValue:
714 * @value: the value to free
715 *
716 * Cleanup the default XML Schemas type library
717 */
718void
719xmlSchemaFreeValue(xmlSchemaValPtr value) {
720 if (value == NULL)
721 return;
Daniel Veillardc4c21552003-03-29 10:53:38 +0000722 switch (value->type) {
723 case XML_SCHEMAS_STRING:
724 case XML_SCHEMAS_NORMSTRING:
725 case XML_SCHEMAS_TOKEN:
726 case XML_SCHEMAS_LANGUAGE:
727 case XML_SCHEMAS_NMTOKEN:
728 case XML_SCHEMAS_NMTOKENS:
729 case XML_SCHEMAS_NAME:
Daniel Veillardc4c21552003-03-29 10:53:38 +0000730 case XML_SCHEMAS_NCNAME:
731 case XML_SCHEMAS_ID:
732 case XML_SCHEMAS_IDREF:
733 case XML_SCHEMAS_IDREFS:
734 case XML_SCHEMAS_ENTITY:
735 case XML_SCHEMAS_ENTITIES:
736 case XML_SCHEMAS_NOTATION:
737 case XML_SCHEMAS_ANYURI:
738 if (value->value.str != NULL)
739 xmlFree(value->value.str);
740 break;
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000741 case XML_SCHEMAS_QNAME:
742 if (value->value.qname.uri != NULL)
743 xmlFree(value->value.qname.uri);
744 if (value->value.qname.name != NULL)
745 xmlFree(value->value.qname.name);
746 break;
Daniel Veillard70bcb0e2003-08-08 14:00:28 +0000747 case XML_SCHEMAS_HEXBINARY:
748 if (value->value.hex.str != NULL)
749 xmlFree(value->value.hex.str);
750 break;
Daniel Veillard1ac24d32003-08-27 14:15:15 +0000751 case XML_SCHEMAS_BASE64BINARY:
752 if (value->value.base64.str != NULL)
753 xmlFree(value->value.base64.str);
754 break;
Daniel Veillardc4c21552003-03-29 10:53:38 +0000755 default:
756 break;
757 }
Daniel Veillard4255d502002-04-16 15:50:10 +0000758 xmlFree(value);
759}
760
761/**
762 * xmlSchemaGetPredefinedType:
763 * @name: the type name
764 * @ns: the URI of the namespace usually "http://www.w3.org/2001/XMLSchema"
765 *
766 * Lookup a type in the default XML Schemas type library
767 *
768 * Returns the type if found, NULL otherwise
769 */
770xmlSchemaTypePtr
771xmlSchemaGetPredefinedType(const xmlChar *name, const xmlChar *ns) {
772 if (xmlSchemaTypesInitialized == 0)
773 xmlSchemaInitTypes();
774 if (name == NULL)
775 return(NULL);
776 return((xmlSchemaTypePtr) xmlHashLookup2(xmlSchemaTypesBank, name, ns));
777}
Daniel Veillard070803b2002-05-03 07:29:38 +0000778
Daniel Veillard01fa6152004-06-29 17:04:39 +0000779/**
780 * xmlSchemaGetBuiltInListSimpleTypeItemType:
781 * @type: the built-in simple type.
782 *
Daniel Veillard6927b102004-10-27 17:29:04 +0000783 * Lookup function
784 *
Daniel Veillardc0826a72004-08-10 14:17:33 +0000785 * Returns the item type of @type as defined by the built-in datatype
786 * hierarchy of XML Schema Part 2: Datatypes, or NULL in case of an error.
Daniel Veillard01fa6152004-06-29 17:04:39 +0000787 */
788xmlSchemaTypePtr
789xmlSchemaGetBuiltInListSimpleTypeItemType(xmlSchemaTypePtr type)
790{
Daniel Veillard42595322004-11-08 10:52:06 +0000791 if ((type == NULL) || (type->type != XML_SCHEMA_TYPE_BASIC))
Daniel Veillard01fa6152004-06-29 17:04:39 +0000792 return (NULL);
793 switch (type->builtInType) {
794 case XML_SCHEMAS_NMTOKENS:
795 return (xmlSchemaTypeNmtokenDef );
796 case XML_SCHEMAS_IDREFS:
797 return (xmlSchemaTypeIdrefDef);
798 case XML_SCHEMAS_ENTITIES:
799 return (xmlSchemaTypeEntityDef);
800 default:
801 return (NULL);
802 }
803}
804
Daniel Veillard070803b2002-05-03 07:29:38 +0000805/****************************************************************
806 * *
807 * Convenience macros and functions *
808 * *
809 ****************************************************************/
810
811#define IS_TZO_CHAR(c) \
812 ((c == 0) || (c == 'Z') || (c == '+') || (c == '-'))
813
814#define VALID_YEAR(yr) (yr != 0)
815#define VALID_MONTH(mon) ((mon >= 1) && (mon <= 12))
816/* VALID_DAY should only be used when month is unknown */
817#define VALID_DAY(day) ((day >= 1) && (day <= 31))
818#define VALID_HOUR(hr) ((hr >= 0) && (hr <= 23))
819#define VALID_MIN(min) ((min >= 0) && (min <= 59))
820#define VALID_SEC(sec) ((sec >= 0) && (sec < 60))
821#define VALID_TZO(tzo) ((tzo > -1440) && (tzo < 1440))
822#define IS_LEAP(y) \
823 (((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0))
824
Daniel Veillardebe25d42004-03-25 09:35:49 +0000825static const unsigned int daysInMonth[12] =
Daniel Veillard070803b2002-05-03 07:29:38 +0000826 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
Daniel Veillardebe25d42004-03-25 09:35:49 +0000827static const unsigned int daysInMonthLeap[12] =
Daniel Veillard070803b2002-05-03 07:29:38 +0000828 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
829
Daniel Veillard5a872412002-05-22 06:40:27 +0000830#define MAX_DAYINMONTH(yr,mon) \
831 (IS_LEAP(yr) ? daysInMonthLeap[mon - 1] : daysInMonth[mon - 1])
832
Daniel Veillard070803b2002-05-03 07:29:38 +0000833#define VALID_MDAY(dt) \
834 (IS_LEAP(dt->year) ? \
835 (dt->day <= daysInMonthLeap[dt->mon - 1]) : \
836 (dt->day <= daysInMonth[dt->mon - 1]))
837
838#define VALID_DATE(dt) \
839 (VALID_YEAR(dt->year) && VALID_MONTH(dt->mon) && VALID_MDAY(dt))
840
841#define VALID_TIME(dt) \
842 (VALID_HOUR(dt->hour) && VALID_MIN(dt->min) && \
843 VALID_SEC(dt->sec) && VALID_TZO(dt->tzo))
844
845#define VALID_DATETIME(dt) \
846 (VALID_DATE(dt) && VALID_TIME(dt))
847
848#define SECS_PER_MIN (60)
849#define SECS_PER_HOUR (60 * SECS_PER_MIN)
850#define SECS_PER_DAY (24 * SECS_PER_HOUR)
851
Daniel Veillard5a872412002-05-22 06:40:27 +0000852static const long dayInYearByMonth[12] =
853 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
854static const long dayInLeapYearByMonth[12] =
855 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 };
856
857#define DAY_IN_YEAR(day, month, year) \
858 ((IS_LEAP(year) ? \
859 dayInLeapYearByMonth[month - 1] : \
860 dayInYearByMonth[month - 1]) + day)
861
862#ifdef DEBUG
863#define DEBUG_DATE(dt) \
864 xmlGenericError(xmlGenericErrorContext, \
865 "type=%o %04ld-%02u-%02uT%02u:%02u:%03f", \
866 dt->type,dt->value.date.year,dt->value.date.mon, \
867 dt->value.date.day,dt->value.date.hour,dt->value.date.min, \
868 dt->value.date.sec); \
869 if (dt->value.date.tz_flag) \
870 if (dt->value.date.tzo != 0) \
871 xmlGenericError(xmlGenericErrorContext, \
872 "%+05d\n",dt->value.date.tzo); \
873 else \
874 xmlGenericError(xmlGenericErrorContext, "Z\n"); \
875 else \
876 xmlGenericError(xmlGenericErrorContext,"\n")
877#else
878#define DEBUG_DATE(dt)
879#endif
880
Daniel Veillard070803b2002-05-03 07:29:38 +0000881/**
882 * _xmlSchemaParseGYear:
883 * @dt: pointer to a date structure
884 * @str: pointer to the string to analyze
885 *
886 * Parses a xs:gYear without time zone and fills in the appropriate
887 * field of the @dt structure. @str is updated to point just after the
888 * xs:gYear. It is supposed that @dt->year is big enough to contain
889 * the year.
890 *
891 * Returns 0 or the error code
892 */
893static int
894_xmlSchemaParseGYear (xmlSchemaValDatePtr dt, const xmlChar **str) {
895 const xmlChar *cur = *str, *firstChar;
896 int isneg = 0, digcnt = 0;
897
898 if (((*cur < '0') || (*cur > '9')) &&
899 (*cur != '-') && (*cur != '+'))
900 return -1;
901
902 if (*cur == '-') {
903 isneg = 1;
904 cur++;
905 }
906
907 firstChar = cur;
908
909 while ((*cur >= '0') && (*cur <= '9')) {
910 dt->year = dt->year * 10 + (*cur - '0');
911 cur++;
912 digcnt++;
913 }
914
915 /* year must be at least 4 digits (CCYY); over 4
916 * digits cannot have a leading zero. */
917 if ((digcnt < 4) || ((digcnt > 4) && (*firstChar == '0')))
918 return 1;
919
920 if (isneg)
921 dt->year = - dt->year;
922
923 if (!VALID_YEAR(dt->year))
924 return 2;
925
926 *str = cur;
927 return 0;
928}
929
930/**
931 * PARSE_2_DIGITS:
932 * @num: the integer to fill in
933 * @cur: an #xmlChar *
934 * @invalid: an integer
935 *
936 * Parses a 2-digits integer and updates @num with the value. @cur is
937 * updated to point just after the integer.
938 * In case of error, @invalid is set to %TRUE, values of @num and
939 * @cur are undefined.
940 */
941#define PARSE_2_DIGITS(num, cur, invalid) \
942 if ((cur[0] < '0') || (cur[0] > '9') || \
943 (cur[1] < '0') || (cur[1] > '9')) \
944 invalid = 1; \
945 else \
946 num = (cur[0] - '0') * 10 + (cur[1] - '0'); \
947 cur += 2;
948
949/**
950 * PARSE_FLOAT:
951 * @num: the double to fill in
952 * @cur: an #xmlChar *
953 * @invalid: an integer
954 *
955 * Parses a float and updates @num with the value. @cur is
956 * updated to point just after the float. The float must have a
957 * 2-digits integer part and may or may not have a decimal part.
958 * In case of error, @invalid is set to %TRUE, values of @num and
959 * @cur are undefined.
960 */
961#define PARSE_FLOAT(num, cur, invalid) \
962 PARSE_2_DIGITS(num, cur, invalid); \
963 if (!invalid && (*cur == '.')) { \
964 double mult = 1; \
965 cur++; \
966 if ((*cur < '0') || (*cur > '9')) \
967 invalid = 1; \
968 while ((*cur >= '0') && (*cur <= '9')) { \
969 mult /= 10; \
970 num += (*cur - '0') * mult; \
971 cur++; \
972 } \
973 }
974
975/**
976 * _xmlSchemaParseGMonth:
977 * @dt: pointer to a date structure
978 * @str: pointer to the string to analyze
979 *
980 * Parses a xs:gMonth without time zone and fills in the appropriate
981 * field of the @dt structure. @str is updated to point just after the
982 * xs:gMonth.
983 *
984 * Returns 0 or the error code
985 */
986static int
987_xmlSchemaParseGMonth (xmlSchemaValDatePtr dt, const xmlChar **str) {
988 const xmlChar *cur = *str;
989 int ret = 0;
990
991 PARSE_2_DIGITS(dt->mon, cur, ret);
992 if (ret != 0)
993 return ret;
994
995 if (!VALID_MONTH(dt->mon))
996 return 2;
997
998 *str = cur;
999 return 0;
1000}
1001
1002/**
1003 * _xmlSchemaParseGDay:
1004 * @dt: pointer to a date structure
1005 * @str: pointer to the string to analyze
1006 *
1007 * Parses a xs:gDay without time zone and fills in the appropriate
1008 * field of the @dt structure. @str is updated to point just after the
1009 * xs:gDay.
1010 *
1011 * Returns 0 or the error code
1012 */
1013static int
1014_xmlSchemaParseGDay (xmlSchemaValDatePtr dt, const xmlChar **str) {
1015 const xmlChar *cur = *str;
1016 int ret = 0;
1017
1018 PARSE_2_DIGITS(dt->day, cur, ret);
1019 if (ret != 0)
1020 return ret;
1021
1022 if (!VALID_DAY(dt->day))
1023 return 2;
1024
1025 *str = cur;
1026 return 0;
1027}
1028
1029/**
1030 * _xmlSchemaParseTime:
1031 * @dt: pointer to a date structure
1032 * @str: pointer to the string to analyze
1033 *
1034 * Parses a xs:time without time zone and fills in the appropriate
1035 * fields of the @dt structure. @str is updated to point just after the
1036 * xs:time.
1037 * In case of error, values of @dt fields are undefined.
1038 *
1039 * Returns 0 or the error code
1040 */
1041static int
1042_xmlSchemaParseTime (xmlSchemaValDatePtr dt, const xmlChar **str) {
1043 const xmlChar *cur = *str;
1044 unsigned int hour = 0; /* use temp var in case str is not xs:time */
1045 int ret = 0;
1046
1047 PARSE_2_DIGITS(hour, cur, ret);
1048 if (ret != 0)
1049 return ret;
1050
1051 if (*cur != ':')
1052 return 1;
1053 cur++;
1054
1055 /* the ':' insures this string is xs:time */
1056 dt->hour = hour;
1057
1058 PARSE_2_DIGITS(dt->min, cur, ret);
1059 if (ret != 0)
1060 return ret;
1061
1062 if (*cur != ':')
1063 return 1;
1064 cur++;
1065
1066 PARSE_FLOAT(dt->sec, cur, ret);
1067 if (ret != 0)
1068 return ret;
1069
1070 if (!VALID_TIME(dt))
1071 return 2;
1072
1073 *str = cur;
1074 return 0;
1075}
1076
1077/**
1078 * _xmlSchemaParseTimeZone:
1079 * @dt: pointer to a date structure
1080 * @str: pointer to the string to analyze
1081 *
1082 * Parses a time zone without time zone and fills in the appropriate
1083 * field of the @dt structure. @str is updated to point just after the
1084 * time zone.
1085 *
1086 * Returns 0 or the error code
1087 */
1088static int
1089_xmlSchemaParseTimeZone (xmlSchemaValDatePtr dt, const xmlChar **str) {
1090 const xmlChar *cur = *str;
1091 int ret = 0;
1092
1093 if (str == NULL)
1094 return -1;
1095
1096 switch (*cur) {
1097 case 0:
1098 dt->tz_flag = 0;
1099 dt->tzo = 0;
1100 break;
1101
1102 case 'Z':
1103 dt->tz_flag = 1;
1104 dt->tzo = 0;
1105 cur++;
1106 break;
1107
1108 case '+':
1109 case '-': {
1110 int isneg = 0, tmp = 0;
1111 isneg = (*cur == '-');
1112
1113 cur++;
1114
1115 PARSE_2_DIGITS(tmp, cur, ret);
1116 if (ret != 0)
1117 return ret;
1118 if (!VALID_HOUR(tmp))
1119 return 2;
1120
1121 if (*cur != ':')
1122 return 1;
1123 cur++;
1124
1125 dt->tzo = tmp * 60;
1126
1127 PARSE_2_DIGITS(tmp, cur, ret);
1128 if (ret != 0)
1129 return ret;
1130 if (!VALID_MIN(tmp))
1131 return 2;
1132
1133 dt->tzo += tmp;
1134 if (isneg)
1135 dt->tzo = - dt->tzo;
1136
1137 if (!VALID_TZO(dt->tzo))
1138 return 2;
1139
Daniel Veillard5a872412002-05-22 06:40:27 +00001140 dt->tz_flag = 1;
Daniel Veillard070803b2002-05-03 07:29:38 +00001141 break;
1142 }
1143 default:
1144 return 1;
1145 }
1146
1147 *str = cur;
1148 return 0;
1149}
1150
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001151/**
1152 * _xmlSchemaBase64Decode:
1153 * @ch: a character
1154 *
1155 * Converts a base64 encoded character to its base 64 value.
1156 *
1157 * Returns 0-63 (value), 64 (pad), or -1 (not recognized)
1158 */
1159static int
1160_xmlSchemaBase64Decode (const xmlChar ch) {
1161 if (('A' <= ch) && (ch <= 'Z')) return ch - 'A';
1162 if (('a' <= ch) && (ch <= 'z')) return ch - 'a' + 26;
1163 if (('0' <= ch) && (ch <= '9')) return ch - '0' + 52;
1164 if ('+' == ch) return 62;
1165 if ('/' == ch) return 63;
1166 if ('=' == ch) return 64;
1167 return -1;
1168}
1169
Daniel Veillard070803b2002-05-03 07:29:38 +00001170/****************************************************************
1171 * *
1172 * XML Schema Dates/Times Datatypes Handling *
1173 * *
1174 ****************************************************************/
1175
1176/**
1177 * PARSE_DIGITS:
1178 * @num: the integer to fill in
1179 * @cur: an #xmlChar *
1180 * @num_type: an integer flag
1181 *
1182 * Parses a digits integer and updates @num with the value. @cur is
1183 * updated to point just after the integer.
1184 * In case of error, @num_type is set to -1, values of @num and
1185 * @cur are undefined.
1186 */
1187#define PARSE_DIGITS(num, cur, num_type) \
1188 if ((*cur < '0') || (*cur > '9')) \
1189 num_type = -1; \
1190 else \
1191 while ((*cur >= '0') && (*cur <= '9')) { \
1192 num = num * 10 + (*cur - '0'); \
1193 cur++; \
1194 }
1195
1196/**
1197 * PARSE_NUM:
1198 * @num: the double to fill in
1199 * @cur: an #xmlChar *
1200 * @num_type: an integer flag
1201 *
1202 * Parses a float or integer and updates @num with the value. @cur is
1203 * updated to point just after the number. If the number is a float,
1204 * then it must have an integer part and a decimal part; @num_type will
1205 * be set to 1. If there is no decimal part, @num_type is set to zero.
1206 * In case of error, @num_type is set to -1, values of @num and
1207 * @cur are undefined.
1208 */
1209#define PARSE_NUM(num, cur, num_type) \
1210 num = 0; \
1211 PARSE_DIGITS(num, cur, num_type); \
1212 if (!num_type && (*cur == '.')) { \
1213 double mult = 1; \
1214 cur++; \
1215 if ((*cur < '0') || (*cur > '9')) \
1216 num_type = -1; \
1217 else \
1218 num_type = 1; \
1219 while ((*cur >= '0') && (*cur <= '9')) { \
1220 mult /= 10; \
1221 num += (*cur - '0') * mult; \
1222 cur++; \
1223 } \
1224 }
1225
1226/**
Daniel Veillard5a872412002-05-22 06:40:27 +00001227 * xmlSchemaValidateDates:
Daniel Veillard455cc072003-03-31 10:13:23 +00001228 * @type: the expected type or XML_SCHEMAS_UNKNOWN
Daniel Veillard070803b2002-05-03 07:29:38 +00001229 * @dateTime: string to analyze
1230 * @val: the return computed value
1231 *
1232 * Check that @dateTime conforms to the lexical space of one of the date types.
1233 * if true a value is computed and returned in @val.
1234 *
1235 * Returns 0 if this validates, a positive error code number otherwise
1236 * and -1 in case of internal or API error.
1237 */
1238static int
Daniel Veillard455cc072003-03-31 10:13:23 +00001239xmlSchemaValidateDates (xmlSchemaValType type,
Daniel Veillard118aed72002-09-24 14:13:13 +00001240 const xmlChar *dateTime, xmlSchemaValPtr *val) {
Daniel Veillard070803b2002-05-03 07:29:38 +00001241 xmlSchemaValPtr dt;
1242 int ret;
1243 const xmlChar *cur = dateTime;
1244
1245#define RETURN_TYPE_IF_VALID(t) \
1246 if (IS_TZO_CHAR(*cur)) { \
1247 ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur); \
1248 if (ret == 0) { \
1249 if (*cur != 0) \
1250 goto error; \
1251 dt->type = t; \
Daniel Veillard455cc072003-03-31 10:13:23 +00001252 goto done; \
Daniel Veillard070803b2002-05-03 07:29:38 +00001253 } \
1254 }
1255
1256 if (dateTime == NULL)
1257 return -1;
1258
1259 if ((*cur != '-') && (*cur < '0') && (*cur > '9'))
1260 return 1;
1261
1262 dt = xmlSchemaNewValue(XML_SCHEMAS_UNKNOWN);
1263 if (dt == NULL)
1264 return -1;
1265
1266 if ((cur[0] == '-') && (cur[1] == '-')) {
1267 /*
1268 * It's an incomplete date (xs:gMonthDay, xs:gMonth or
1269 * xs:gDay)
1270 */
1271 cur += 2;
1272
1273 /* is it an xs:gDay? */
1274 if (*cur == '-') {
Daniel Veillard455cc072003-03-31 10:13:23 +00001275 if (type == XML_SCHEMAS_GMONTH)
1276 goto error;
Daniel Veillard070803b2002-05-03 07:29:38 +00001277 ++cur;
1278 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
1279 if (ret != 0)
1280 goto error;
1281
1282 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GDAY);
1283
1284 goto error;
1285 }
1286
1287 /*
1288 * it should be an xs:gMonthDay or xs:gMonth
1289 */
1290 ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
1291 if (ret != 0)
1292 goto error;
1293
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001294 /*
1295 * a '-' char could indicate this type is xs:gMonthDay or
1296 * a negative time zone offset. Check for xs:gMonthDay first.
1297 * Also the first three char's of a negative tzo (-MM:SS) can
1298 * appear to be a valid day; so even if the day portion
1299 * of the xs:gMonthDay verifies, we must insure it was not
1300 * a tzo.
1301 */
1302 if (*cur == '-') {
1303 const xmlChar *rewnd = cur;
1304 cur++;
Daniel Veillard070803b2002-05-03 07:29:38 +00001305
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001306 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
1307 if ((ret == 0) && ((*cur == 0) || (*cur != ':'))) {
1308
1309 /*
1310 * we can use the VALID_MDAY macro to validate the month
1311 * and day because the leap year test will flag year zero
1312 * as a leap year (even though zero is an invalid year).
1313 */
1314 if (VALID_MDAY((&(dt->value.date)))) {
1315
1316 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTHDAY);
1317
1318 goto error;
1319 }
1320 }
1321
1322 /*
1323 * not xs:gMonthDay so rewind and check if just xs:gMonth
1324 * with an optional time zone.
1325 */
1326 cur = rewnd;
1327 }
1328
1329 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTH);
Daniel Veillard070803b2002-05-03 07:29:38 +00001330
1331 goto error;
1332 }
1333
1334 /*
1335 * It's a right-truncated date or an xs:time.
1336 * Try to parse an xs:time then fallback on right-truncated dates.
1337 */
1338 if ((*cur >= '0') && (*cur <= '9')) {
1339 ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
1340 if (ret == 0) {
1341 /* it's an xs:time */
1342 RETURN_TYPE_IF_VALID(XML_SCHEMAS_TIME);
1343 }
1344 }
1345
1346 /* fallback on date parsing */
1347 cur = dateTime;
1348
1349 ret = _xmlSchemaParseGYear(&(dt->value.date), &cur);
1350 if (ret != 0)
1351 goto error;
1352
1353 /* is it an xs:gYear? */
1354 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEAR);
1355
1356 if (*cur != '-')
1357 goto error;
1358 cur++;
1359
1360 ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
1361 if (ret != 0)
1362 goto error;
1363
1364 /* is it an xs:gYearMonth? */
1365 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEARMONTH);
1366
1367 if (*cur != '-')
1368 goto error;
1369 cur++;
1370
1371 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
1372 if ((ret != 0) || !VALID_DATE((&(dt->value.date))))
1373 goto error;
1374
1375 /* is it an xs:date? */
1376 RETURN_TYPE_IF_VALID(XML_SCHEMAS_DATE);
1377
1378 if (*cur != 'T')
1379 goto error;
1380 cur++;
1381
1382 /* it should be an xs:dateTime */
1383 ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
1384 if (ret != 0)
1385 goto error;
1386
1387 ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur);
1388 if ((ret != 0) || (*cur != 0) || !VALID_DATETIME((&(dt->value.date))))
1389 goto error;
1390
Daniel Veillard455cc072003-03-31 10:13:23 +00001391
Daniel Veillard070803b2002-05-03 07:29:38 +00001392 dt->type = XML_SCHEMAS_DATETIME;
1393
Daniel Veillard455cc072003-03-31 10:13:23 +00001394done:
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001395#if 1
1396 if ((type != XML_SCHEMAS_UNKNOWN) && (type != dt->type))
1397 goto error;
1398#else
1399 /*
1400 * insure the parsed type is equal to or less significant (right
1401 * truncated) than the desired type.
1402 */
1403 if ((type != XML_SCHEMAS_UNKNOWN) && (type != dt->type)) {
1404
1405 /* time only matches time */
1406 if ((type == XML_SCHEMAS_TIME) && (dt->type == XML_SCHEMAS_TIME))
1407 goto error;
1408
1409 if ((type == XML_SCHEMAS_DATETIME) &&
1410 ((dt->type != XML_SCHEMAS_DATE) ||
1411 (dt->type != XML_SCHEMAS_GYEARMONTH) ||
1412 (dt->type != XML_SCHEMAS_GYEAR)))
1413 goto error;
1414
1415 if ((type == XML_SCHEMAS_DATE) &&
1416 ((dt->type != XML_SCHEMAS_GYEAR) ||
1417 (dt->type != XML_SCHEMAS_GYEARMONTH)))
1418 goto error;
1419
1420 if ((type == XML_SCHEMAS_GYEARMONTH) && (dt->type != XML_SCHEMAS_GYEAR))
1421 goto error;
1422
1423 if ((type == XML_SCHEMAS_GMONTHDAY) && (dt->type != XML_SCHEMAS_GMONTH))
1424 goto error;
1425 }
Daniel Veillard455cc072003-03-31 10:13:23 +00001426#endif
1427
Daniel Veillard070803b2002-05-03 07:29:38 +00001428 if (val != NULL)
1429 *val = dt;
Daniel Veillard80b19092003-03-28 13:29:53 +00001430 else
1431 xmlSchemaFreeValue(dt);
Daniel Veillard070803b2002-05-03 07:29:38 +00001432
1433 return 0;
1434
1435error:
1436 if (dt != NULL)
1437 xmlSchemaFreeValue(dt);
1438 return 1;
1439}
1440
1441/**
Daniel Veillard5a872412002-05-22 06:40:27 +00001442 * xmlSchemaValidateDuration:
Daniel Veillard070803b2002-05-03 07:29:38 +00001443 * @type: the predefined type
1444 * @duration: string to analyze
1445 * @val: the return computed value
1446 *
1447 * Check that @duration conforms to the lexical space of the duration type.
1448 * if true a value is computed and returned in @val.
1449 *
1450 * Returns 0 if this validates, a positive error code number otherwise
1451 * and -1 in case of internal or API error.
1452 */
1453static int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00001454xmlSchemaValidateDuration (xmlSchemaTypePtr type ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +00001455 const xmlChar *duration, xmlSchemaValPtr *val) {
Daniel Veillard070803b2002-05-03 07:29:38 +00001456 const xmlChar *cur = duration;
1457 xmlSchemaValPtr dur;
1458 int isneg = 0;
1459 unsigned int seq = 0;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001460 double num;
1461 int num_type = 0; /* -1 = invalid, 0 = int, 1 = floating */
1462 const xmlChar desig[] = {'Y', 'M', 'D', 'H', 'M', 'S'};
1463 const double multi[] = { 0.0, 0.0, 86400.0, 3600.0, 60.0, 1.0, 0.0};
Daniel Veillard070803b2002-05-03 07:29:38 +00001464
1465 if (duration == NULL)
1466 return -1;
1467
1468 if (*cur == '-') {
1469 isneg = 1;
1470 cur++;
1471 }
1472
1473 /* duration must start with 'P' (after sign) */
1474 if (*cur++ != 'P')
1475 return 1;
1476
Daniel Veillard80b19092003-03-28 13:29:53 +00001477 if (*cur == 0)
1478 return 1;
1479
Daniel Veillard070803b2002-05-03 07:29:38 +00001480 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
1481 if (dur == NULL)
1482 return -1;
1483
1484 while (*cur != 0) {
Daniel Veillard070803b2002-05-03 07:29:38 +00001485
1486 /* input string should be empty or invalid date/time item */
1487 if (seq >= sizeof(desig))
1488 goto error;
1489
1490 /* T designator must be present for time items */
1491 if (*cur == 'T') {
1492 if (seq <= 3) {
1493 seq = 3;
1494 cur++;
1495 } else
1496 return 1;
1497 } else if (seq == 3)
1498 goto error;
1499
1500 /* parse the number portion of the item */
1501 PARSE_NUM(num, cur, num_type);
1502
1503 if ((num_type == -1) || (*cur == 0))
1504 goto error;
1505
1506 /* update duration based on item type */
1507 while (seq < sizeof(desig)) {
1508 if (*cur == desig[seq]) {
1509
1510 /* verify numeric type; only seconds can be float */
1511 if ((num_type != 0) && (seq < (sizeof(desig)-1)))
1512 goto error;
1513
1514 switch (seq) {
1515 case 0:
1516 dur->value.dur.mon = (long)num * 12;
1517 break;
1518 case 1:
1519 dur->value.dur.mon += (long)num;
1520 break;
1521 default:
1522 /* convert to seconds using multiplier */
1523 dur->value.dur.sec += num * multi[seq];
1524 seq++;
1525 break;
1526 }
1527
1528 break; /* exit loop */
1529 }
1530 /* no date designators found? */
1531 if (++seq == 3)
1532 goto error;
1533 }
1534 cur++;
1535 }
1536
1537 if (isneg) {
1538 dur->value.dur.mon = -dur->value.dur.mon;
1539 dur->value.dur.day = -dur->value.dur.day;
1540 dur->value.dur.sec = -dur->value.dur.sec;
1541 }
1542
1543 if (val != NULL)
1544 *val = dur;
Daniel Veillard80b19092003-03-28 13:29:53 +00001545 else
1546 xmlSchemaFreeValue(dur);
Daniel Veillard070803b2002-05-03 07:29:38 +00001547
1548 return 0;
1549
1550error:
1551 if (dur != NULL)
1552 xmlSchemaFreeValue(dur);
1553 return 1;
1554}
1555
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001556/**
1557 * xmlSchemaStrip:
1558 * @value: a value
1559 *
1560 * Removes the leading and ending spaces of a string
1561 *
1562 * Returns the new string or NULL if no change was required.
1563 */
1564static xmlChar *
1565xmlSchemaStrip(const xmlChar *value) {
1566 const xmlChar *start = value, *end, *f;
1567
1568 if (value == NULL) return(NULL);
William M. Brack76e95df2003-10-18 16:20:14 +00001569 while ((*start != 0) && (IS_BLANK_CH(*start))) start++;
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001570 end = start;
1571 while (*end != 0) end++;
1572 f = end;
1573 end--;
William M. Brack76e95df2003-10-18 16:20:14 +00001574 while ((end > start) && (IS_BLANK_CH(*end))) end--;
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001575 end++;
1576 if ((start == value) && (f == end)) return(NULL);
1577 return(xmlStrndup(start, end - start));
1578}
Daniel Veillard96a4b252003-02-06 08:22:32 +00001579
1580/**
Kasimier T. Buchcik91feaf82004-11-12 14:04:58 +00001581 * xmlSchemaWhiteSpaceReplace:
1582 * @value: a value
1583 *
1584 * Replaces 0xd, 0x9 and 0xa with a space.
1585 *
1586 * Returns the new string or NULL if no change was required.
1587 */
1588xmlChar *
1589xmlSchemaWhiteSpaceReplace(const xmlChar *value) {
1590 const xmlChar *cur = value;
1591 xmlChar *ret = NULL, *mcur;
1592
1593 if (value == NULL)
1594 return(NULL);
1595
1596 while ((*cur != 0) &&
1597 (((*cur) != 0xd) && ((*cur) != 0x9) && ((*cur) != 0xa))) {
1598 cur++;
1599 }
1600 if (*cur == 0)
1601 return (NULL);
1602 ret = xmlStrdup(value);
1603 /* TODO FIXME: I guess gcc will bark at this. */
1604 mcur = (xmlChar *) (ret + (cur - value));
1605 do {
1606 if ( ((*mcur) == 0xd) || ((*mcur) == 0x9) || ((*mcur) == 0xa) )
1607 *mcur = ' ';
1608 mcur++;
1609 } while (*mcur != 0);
1610 return(ret);
1611}
1612
1613/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001614 * xmlSchemaCollapseString:
1615 * @value: a value
1616 *
1617 * Removes and normalize white spaces in the string
1618 *
1619 * Returns the new string or NULL if no change was required.
1620 */
Daniel Veillard01fa6152004-06-29 17:04:39 +00001621xmlChar *
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001622xmlSchemaCollapseString(const xmlChar *value) {
1623 const xmlChar *start = value, *end, *f;
1624 xmlChar *g;
1625 int col = 0;
1626
1627 if (value == NULL) return(NULL);
William M. Brack76e95df2003-10-18 16:20:14 +00001628 while ((*start != 0) && (IS_BLANK_CH(*start))) start++;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001629 end = start;
1630 while (*end != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00001631 if ((*end == ' ') && (IS_BLANK_CH(end[1]))) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001632 col = end - start;
1633 break;
1634 } else if ((*end == 0xa) || (*end == 0x9) || (*end == 0xd)) {
1635 col = end - start;
1636 break;
1637 }
1638 end++;
1639 }
1640 if (col == 0) {
1641 f = end;
1642 end--;
William M. Brack76e95df2003-10-18 16:20:14 +00001643 while ((end > start) && (IS_BLANK_CH(*end))) end--;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001644 end++;
1645 if ((start == value) && (f == end)) return(NULL);
1646 return(xmlStrndup(start, end - start));
1647 }
1648 start = xmlStrdup(start);
1649 if (start == NULL) return(NULL);
1650 g = (xmlChar *) (start + col);
1651 end = g;
1652 while (*end != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00001653 if (IS_BLANK_CH(*end)) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001654 end++;
William M. Brack76e95df2003-10-18 16:20:14 +00001655 while (IS_BLANK_CH(*end)) end++;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001656 if (*end != 0)
1657 *g++ = ' ';
1658 } else
1659 *g++ = *end++;
1660 }
1661 *g = 0;
1662 return((xmlChar *) start);
1663}
1664
1665/**
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001666 * xmlSchemaValAtomicListNode:
1667 * @type: the predefined atomic type for a token in the list
1668 * @value: the list value to check
1669 * @ret: the return computed value
1670 * @node: the node containing the value
1671 *
1672 * Check that a value conforms to the lexical space of the predefined
1673 * list type. if true a value is computed and returned in @ret.
1674 *
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001675 * Returns the number of items if this validates, a negative error code
1676 * number otherwise
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001677 */
1678static int
1679xmlSchemaValAtomicListNode(xmlSchemaTypePtr type, const xmlChar *value,
1680 xmlSchemaValPtr *ret, xmlNodePtr node) {
1681 xmlChar *val, *cur, *endval;
1682 int nb_values = 0;
Daniel Veillard580ced82003-03-21 21:22:48 +00001683 int tmp = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001684
1685 if (value == NULL) {
1686 return(-1);
1687 }
1688 val = xmlStrdup(value);
1689 if (val == NULL) {
1690 return(-1);
1691 }
Daniel Veillard6fc5db02005-01-16 00:05:58 +00001692 if (ret != NULL) {
1693 *ret = NULL;
1694 }
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001695 cur = val;
1696 /*
1697 * Split the list
1698 */
William M. Brack76e95df2003-10-18 16:20:14 +00001699 while (IS_BLANK_CH(*cur)) *cur++ = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001700 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00001701 if (IS_BLANK_CH(*cur)) {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001702 *cur = 0;
1703 cur++;
William M. Brack76e95df2003-10-18 16:20:14 +00001704 while (IS_BLANK_CH(*cur)) *cur++ = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001705 } else {
1706 nb_values++;
1707 cur++;
William M. Brack76e95df2003-10-18 16:20:14 +00001708 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001709 }
1710 }
1711 if (nb_values == 0) {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001712 xmlFree(val);
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001713 return(nb_values);
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001714 }
1715 endval = cur;
1716 cur = val;
1717 while ((*cur == 0) && (cur != endval)) cur++;
1718 while (cur != endval) {
1719 tmp = xmlSchemaValPredefTypeNode(type, cur, NULL, node);
1720 if (tmp != 0)
1721 break;
1722 while (*cur != 0) cur++;
1723 while ((*cur == 0) && (cur != endval)) cur++;
1724 }
Daniel Veillard6fc5db02005-01-16 00:05:58 +00001725 /* TODO what return value ? c.f. bug #158628
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001726 if (ret != NULL) {
1727 TODO
Daniel Veillard6fc5db02005-01-16 00:05:58 +00001728 } */
1729 xmlFree(val);
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001730 if (tmp == 0)
1731 return(nb_values);
1732 return(-1);
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001733}
1734
1735/**
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001736 * xmlSchemaParseUInt:
1737 * @str: pointer to the string R/W
1738 * @llo: pointer to the low result
1739 * @lmi: pointer to the mid result
1740 * @lhi: pointer to the high result
1741 *
1742 * Parse an unsigned long into 3 fields.
1743 *
1744 * Returns the number of chars parsed or -1 if overflow of the capacity
1745 */
1746static int
1747xmlSchemaParseUInt(const xmlChar **str, unsigned long *llo,
1748 unsigned long *lmi, unsigned long *lhi) {
1749 unsigned long lo = 0, mi = 0, hi = 0;
1750 const xmlChar *tmp, *cur = *str;
1751 int ret = 0, i = 0;
1752
1753 while (*cur == '0') {
1754 ret++;
1755 cur++;
1756 }
1757 tmp = cur;
1758 while ((*tmp != 0) && (*tmp >= '0') && (*tmp <= '9')) {
1759 i++;tmp++;ret++;
1760 }
1761 if (i > 24) {
1762 *str = tmp;
1763 return(-1);
1764 }
1765 while (i > 16) {
1766 hi = hi * 10 + (*cur++ - '0');
1767 i--;
1768 }
1769 while (i > 8) {
1770 mi = mi * 10 + (*cur++ - '0');
1771 i--;
1772 }
1773 while (i > 0) {
1774 lo = lo * 10 + (*cur++ - '0');
1775 i--;
1776 }
1777
1778 *str = cur;
1779 *llo = lo;
1780 *lmi = mi;
1781 *lhi = hi;
1782 return(ret);
1783}
1784
1785/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001786 * xmlSchemaValAtomicType:
1787 * @type: the predefined type
1788 * @value: the value to check
1789 * @val: the return computed value
1790 * @node: the node containing the value
1791 * flags: flags to control the vlidation
1792 *
1793 * Check that a value conforms to the lexical space of the atomic type.
1794 * if true a value is computed and returned in @val.
Daniel Veillard01fa6152004-06-29 17:04:39 +00001795 * This checks the value space for list types as well (IDREFS, NMTOKENS).
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001796 *
1797 * Returns 0 if this validates, a positive error code number otherwise
1798 * and -1 in case of internal or API error.
1799 */
1800static int
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001801xmlSchemaValAtomicType(xmlSchemaTypePtr type, const xmlChar * value,
1802 xmlSchemaValPtr * val, xmlNodePtr node, int flags)
1803{
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001804 xmlSchemaValPtr v;
1805 xmlChar *norm = NULL;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001806 int ret = 0;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001807
1808 if (xmlSchemaTypesInitialized == 0)
Daniel Veillard01fa6152004-06-29 17:04:39 +00001809 xmlSchemaInitTypes();
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001810 if (type == NULL)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001811 return (-1);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001812
Daniel Veillardeebd6332004-08-26 10:30:44 +00001813 /*
1814 * validating a non existant text node is similar to validating
1815 * an empty one.
1816 */
1817 if (value == NULL)
1818 value = BAD_CAST "";
1819
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001820 if (val != NULL)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001821 *val = NULL;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001822 if ((flags == 0) && (value != NULL)) {
Kasimier T. Buchcik91feaf82004-11-12 14:04:58 +00001823
Daniel Veillard01fa6152004-06-29 17:04:39 +00001824 if ((type->builtInType != XML_SCHEMAS_STRING) &&
Kasimier T. Buchcik91feaf82004-11-12 14:04:58 +00001825 (type->builtInType != XML_SCHEMAS_ANYTYPE) &&
1826 (type->builtInType != XML_SCHEMAS_ANYSIMPLETYPE)) {
1827 if (type->builtInType == XML_SCHEMAS_NORMSTRING)
1828 norm = xmlSchemaWhiteSpaceReplace(value);
1829 else
1830 norm = xmlSchemaCollapseString(value);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001831 if (norm != NULL)
1832 value = norm;
1833 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001834 }
1835
Daniel Veillard01fa6152004-06-29 17:04:39 +00001836 switch (type->builtInType) {
William M. Brack2f2a6632004-08-20 23:09:47 +00001837 case XML_SCHEMAS_UNKNOWN:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001838 goto error;
William M. Brack2f2a6632004-08-20 23:09:47 +00001839 case XML_SCHEMAS_ANYTYPE:
1840 case XML_SCHEMAS_ANYSIMPLETYPE:
1841 goto return0;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001842 case XML_SCHEMAS_STRING:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001843 goto return0;
Daniel Veillard1516d5b2004-01-22 07:27:45 +00001844 case XML_SCHEMAS_NORMSTRING:{
1845 const xmlChar *cur = value;
1846
1847 while (*cur != 0) {
1848 if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) {
1849 goto return1;
1850 } else {
1851 cur++;
1852 }
1853 }
1854 if (val != NULL) {
1855 v = xmlSchemaNewValue(XML_SCHEMAS_NORMSTRING);
1856 if (v != NULL) {
1857 v->value.str = xmlStrdup(value);
1858 *val = v;
1859 } else {
1860 goto error;
1861 }
1862 }
1863 goto return0;
1864 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001865 case XML_SCHEMAS_DECIMAL:{
1866 const xmlChar *cur = value, *tmp;
1867 unsigned int frac = 0, len, neg = 0;
1868 unsigned long base = 0;
1869
1870 if (cur == NULL)
1871 goto return1;
1872 if (*cur == '+')
1873 cur++;
1874 else if (*cur == '-') {
1875 neg = 1;
1876 cur++;
1877 }
1878 tmp = cur;
1879 while ((*cur >= '0') && (*cur <= '9')) {
1880 base = base * 10 + (*cur - '0');
1881 cur++;
1882 }
1883 len = cur - tmp;
1884 if (*cur == '.') {
1885 cur++;
1886 tmp = cur;
1887 while ((*cur >= '0') && (*cur <= '9')) {
1888 base = base * 10 + (*cur - '0');
1889 cur++;
1890 }
1891 frac = cur - tmp;
1892 }
1893 if (*cur != 0)
1894 goto return1;
1895 if (val != NULL) {
1896 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
1897 if (v != NULL) {
1898 v->value.decimal.lo = base;
1899 v->value.decimal.sign = neg;
1900 v->value.decimal.frac = frac;
1901 v->value.decimal.total = frac + len;
1902 *val = v;
1903 }
1904 }
1905 goto return0;
1906 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001907 case XML_SCHEMAS_TIME:
1908 case XML_SCHEMAS_GDAY:
1909 case XML_SCHEMAS_GMONTH:
1910 case XML_SCHEMAS_GMONTHDAY:
1911 case XML_SCHEMAS_GYEAR:
1912 case XML_SCHEMAS_GYEARMONTH:
1913 case XML_SCHEMAS_DATE:
1914 case XML_SCHEMAS_DATETIME:
Daniel Veillard01fa6152004-06-29 17:04:39 +00001915 ret = xmlSchemaValidateDates(type->builtInType, value, val);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001916 break;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001917 case XML_SCHEMAS_DURATION:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001918 ret = xmlSchemaValidateDuration(type, value, val);
1919 break;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001920 case XML_SCHEMAS_FLOAT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001921 case XML_SCHEMAS_DOUBLE:{
1922 const xmlChar *cur = value;
1923 int neg = 0;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001924
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001925 if (cur == NULL)
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00001926 goto return1;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001927 if ((cur[0] == 'N') && (cur[1] == 'a') && (cur[2] == 'N')) {
1928 cur += 3;
1929 if (*cur != 0)
1930 goto return1;
1931 if (val != NULL) {
1932 if (type == xmlSchemaTypeFloatDef) {
1933 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1934 if (v != NULL) {
1935 v->value.f = (float) xmlXPathNAN;
1936 } else {
1937 xmlSchemaFreeValue(v);
1938 goto error;
1939 }
1940 } else {
1941 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1942 if (v != NULL) {
1943 v->value.d = xmlXPathNAN;
1944 } else {
1945 xmlSchemaFreeValue(v);
1946 goto error;
1947 }
1948 }
1949 *val = v;
1950 }
1951 goto return0;
1952 }
1953 if (*cur == '-') {
1954 neg = 1;
1955 cur++;
1956 }
1957 if ((cur[0] == 'I') && (cur[1] == 'N') && (cur[2] == 'F')) {
1958 cur += 3;
1959 if (*cur != 0)
1960 goto return1;
1961 if (val != NULL) {
1962 if (type == xmlSchemaTypeFloatDef) {
1963 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1964 if (v != NULL) {
1965 if (neg)
1966 v->value.f = (float) xmlXPathNINF;
1967 else
1968 v->value.f = (float) xmlXPathPINF;
1969 } else {
1970 xmlSchemaFreeValue(v);
1971 goto error;
1972 }
1973 } else {
1974 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1975 if (v != NULL) {
1976 if (neg)
1977 v->value.d = xmlXPathNINF;
1978 else
1979 v->value.d = xmlXPathPINF;
1980 } else {
1981 xmlSchemaFreeValue(v);
1982 goto error;
1983 }
1984 }
1985 *val = v;
1986 }
1987 goto return0;
1988 }
1989 if ((neg == 0) && (*cur == '+'))
1990 cur++;
1991 if ((cur[0] == 0) || (cur[0] == '+') || (cur[0] == '-'))
1992 goto return1;
1993 while ((*cur >= '0') && (*cur <= '9')) {
1994 cur++;
1995 }
1996 if (*cur == '.') {
1997 cur++;
1998 while ((*cur >= '0') && (*cur <= '9'))
1999 cur++;
2000 }
2001 if ((*cur == 'e') || (*cur == 'E')) {
2002 cur++;
2003 if ((*cur == '-') || (*cur == '+'))
2004 cur++;
2005 while ((*cur >= '0') && (*cur <= '9'))
2006 cur++;
2007 }
2008 if (*cur != 0)
2009 goto return1;
2010 if (val != NULL) {
2011 if (type == xmlSchemaTypeFloatDef) {
2012 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
2013 if (v != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002014 if (sscanf((const char *) value, "%f",
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002015 &(v->value.f)) == 1) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00002016 *val = v;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002017 } else {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002018 xmlSchemaFreeValue(v);
2019 goto return1;
2020 }
2021 } else {
2022 goto error;
2023 }
2024 } else {
2025 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
2026 if (v != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002027 if (sscanf((const char *) value, "%lf",
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002028 &(v->value.d)) == 1) {
2029 *val = v;
2030 } else {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002031 xmlSchemaFreeValue(v);
2032 goto return1;
2033 }
2034 } else {
2035 goto error;
2036 }
2037 }
2038 }
2039 goto return0;
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00002040 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002041 case XML_SCHEMAS_BOOLEAN:{
2042 const xmlChar *cur = value;
2043
2044 if ((cur[0] == '0') && (cur[1] == 0))
2045 ret = 0;
2046 else if ((cur[0] == '1') && (cur[1] == 0))
2047 ret = 1;
2048 else if ((cur[0] == 't') && (cur[1] == 'r')
2049 && (cur[2] == 'u') && (cur[3] == 'e')
2050 && (cur[4] == 0))
2051 ret = 1;
2052 else if ((cur[0] == 'f') && (cur[1] == 'a')
2053 && (cur[2] == 'l') && (cur[3] == 's')
2054 && (cur[4] == 'e') && (cur[5] == 0))
2055 ret = 0;
2056 else
2057 goto return1;
2058 if (val != NULL) {
2059 v = xmlSchemaNewValue(XML_SCHEMAS_BOOLEAN);
2060 if (v != NULL) {
2061 v->value.b = ret;
2062 *val = v;
2063 } else {
2064 goto error;
2065 }
2066 }
2067 goto return0;
2068 }
2069 case XML_SCHEMAS_TOKEN:{
2070 const xmlChar *cur = value;
2071
William M. Brack76e95df2003-10-18 16:20:14 +00002072 if (IS_BLANK_CH(*cur))
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002073 goto return1;
2074
2075 while (*cur != 0) {
2076 if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) {
2077 goto return1;
2078 } else if (*cur == ' ') {
2079 cur++;
2080 if (*cur == 0)
2081 goto return1;
2082 if (*cur == ' ')
2083 goto return1;
2084 } else {
2085 cur++;
2086 }
2087 }
2088 if (val != NULL) {
2089 v = xmlSchemaNewValue(XML_SCHEMAS_TOKEN);
2090 if (v != NULL) {
2091 v->value.str = xmlStrdup(value);
2092 *val = v;
2093 } else {
2094 goto error;
2095 }
2096 }
2097 goto return0;
2098 }
2099 case XML_SCHEMAS_LANGUAGE:
2100 if (xmlCheckLanguageID(value) == 1) {
2101 if (val != NULL) {
2102 v = xmlSchemaNewValue(XML_SCHEMAS_LANGUAGE);
2103 if (v != NULL) {
2104 v->value.str = xmlStrdup(value);
2105 *val = v;
2106 } else {
2107 goto error;
2108 }
2109 }
2110 goto return0;
2111 }
2112 goto return1;
2113 case XML_SCHEMAS_NMTOKEN:
2114 if (xmlValidateNMToken(value, 1) == 0) {
2115 if (val != NULL) {
2116 v = xmlSchemaNewValue(XML_SCHEMAS_NMTOKEN);
2117 if (v != NULL) {
2118 v->value.str = xmlStrdup(value);
2119 *val = v;
2120 } else {
2121 goto error;
2122 }
2123 }
2124 goto return0;
2125 }
2126 goto return1;
2127 case XML_SCHEMAS_NMTOKENS:
2128 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeNmtokenDef,
2129 value, val, node);
2130 if (ret > 0)
2131 ret = 0;
2132 else
2133 ret = 1;
2134 goto done;
2135 case XML_SCHEMAS_NAME:
2136 ret = xmlValidateName(value, 1);
Daniel Veillarddf292f72005-01-16 19:00:15 +00002137 if ((ret == 0) && (val != NULL) && (value != NULL)) {
2138 v = xmlSchemaNewValue(XML_SCHEMAS_NAME);
2139 if (v != NULL) {
2140 const xmlChar *start = value, *end;
2141 while (IS_BLANK_CH(*start)) start++;
2142 end = start;
2143 while ((*end != 0) && (!IS_BLANK_CH(*end))) end++;
2144 v->value.str = xmlStrndup(start, end - start);
2145 *val = v;
2146 } else {
2147 goto error;
2148 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002149 }
2150 goto done;
2151 case XML_SCHEMAS_QNAME:{
2152 xmlChar *uri = NULL;
2153 xmlChar *local = NULL;
2154
2155 ret = xmlValidateQName(value, 1);
2156 if ((ret == 0) && (node != NULL)) {
2157 xmlChar *prefix;
2158
2159 local = xmlSplitQName2(value, &prefix);
2160 if (prefix != NULL) {
2161 xmlNsPtr ns;
2162
2163 ns = xmlSearchNs(node->doc, node, prefix);
2164 if (ns == NULL)
2165 ret = 1;
2166 else if (val != NULL)
2167 uri = xmlStrdup(ns->href);
2168 }
2169 if ((local != NULL) && ((val == NULL) || (ret != 0)))
2170 xmlFree(local);
2171 if (prefix != NULL)
2172 xmlFree(prefix);
2173 }
2174 if ((ret == 0) && (val != NULL)) {
2175 v = xmlSchemaNewValue(XML_SCHEMAS_QNAME);
2176 if (v != NULL) {
2177 if (local != NULL)
2178 v->value.qname.name = local;
2179 else
2180 v->value.qname.name = xmlStrdup(value);
2181 if (uri != NULL)
2182 v->value.qname.uri = uri;
2183
2184 *val = v;
2185 } else {
2186 if (local != NULL)
2187 xmlFree(local);
2188 if (uri != NULL)
2189 xmlFree(uri);
2190 goto error;
2191 }
2192 }
2193 goto done;
2194 }
2195 case XML_SCHEMAS_NCNAME:
2196 ret = xmlValidateNCName(value, 1);
2197 if ((ret == 0) && (val != NULL)) {
2198 v = xmlSchemaNewValue(XML_SCHEMAS_NCNAME);
2199 if (v != NULL) {
2200 v->value.str = xmlStrdup(value);
2201 *val = v;
2202 } else {
2203 goto error;
2204 }
2205 }
2206 goto done;
2207 case XML_SCHEMAS_ID:
2208 ret = xmlValidateNCName(value, 1);
2209 if ((ret == 0) && (val != NULL)) {
2210 v = xmlSchemaNewValue(XML_SCHEMAS_ID);
2211 if (v != NULL) {
2212 v->value.str = xmlStrdup(value);
2213 *val = v;
2214 } else {
2215 goto error;
2216 }
2217 }
2218 if ((ret == 0) && (node != NULL) &&
2219 (node->type == XML_ATTRIBUTE_NODE)) {
2220 xmlAttrPtr attr = (xmlAttrPtr) node;
2221
2222 /*
2223 * NOTE: the IDness might have already be declared in the DTD
2224 */
2225 if (attr->atype != XML_ATTRIBUTE_ID) {
2226 xmlIDPtr res;
2227 xmlChar *strip;
2228
2229 strip = xmlSchemaStrip(value);
2230 if (strip != NULL) {
2231 res = xmlAddID(NULL, node->doc, strip, attr);
2232 xmlFree(strip);
2233 } else
2234 res = xmlAddID(NULL, node->doc, value, attr);
2235 if (res == NULL) {
2236 ret = 2;
2237 } else {
2238 attr->atype = XML_ATTRIBUTE_ID;
2239 }
2240 }
2241 }
2242 goto done;
2243 case XML_SCHEMAS_IDREF:
2244 ret = xmlValidateNCName(value, 1);
2245 if ((ret == 0) && (val != NULL)) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00002246 v = xmlSchemaNewValue(XML_SCHEMAS_IDREF);
2247 if (v == NULL)
2248 goto error;
2249 v->value.str = xmlStrdup(value);
2250 *val = v;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002251 }
2252 if ((ret == 0) && (node != NULL) &&
2253 (node->type == XML_ATTRIBUTE_NODE)) {
2254 xmlAttrPtr attr = (xmlAttrPtr) node;
2255 xmlChar *strip;
2256
2257 strip = xmlSchemaStrip(value);
2258 if (strip != NULL) {
2259 xmlAddRef(NULL, node->doc, strip, attr);
2260 xmlFree(strip);
2261 } else
2262 xmlAddRef(NULL, node->doc, value, attr);
2263 attr->atype = XML_ATTRIBUTE_IDREF;
2264 }
2265 goto done;
2266 case XML_SCHEMAS_IDREFS:
2267 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeIdrefDef,
2268 value, val, node);
2269 if (ret < 0)
2270 ret = 2;
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_IDREFS;
2278 }
2279 goto done;
2280 case XML_SCHEMAS_ENTITY:{
2281 xmlChar *strip;
2282
2283 ret = xmlValidateNCName(value, 1);
2284 if ((node == NULL) || (node->doc == NULL))
2285 ret = 3;
2286 if (ret == 0) {
2287 xmlEntityPtr ent;
2288
2289 strip = xmlSchemaStrip(value);
2290 if (strip != NULL) {
2291 ent = xmlGetDocEntity(node->doc, strip);
2292 xmlFree(strip);
2293 } else {
2294 ent = xmlGetDocEntity(node->doc, value);
2295 }
2296 if ((ent == NULL) ||
2297 (ent->etype !=
2298 XML_EXTERNAL_GENERAL_UNPARSED_ENTITY))
2299 ret = 4;
2300 }
2301 if ((ret == 0) && (val != NULL)) {
2302 TODO;
2303 }
2304 if ((ret == 0) && (node != NULL) &&
2305 (node->type == XML_ATTRIBUTE_NODE)) {
2306 xmlAttrPtr attr = (xmlAttrPtr) node;
2307
2308 attr->atype = XML_ATTRIBUTE_ENTITY;
2309 }
2310 goto done;
2311 }
2312 case XML_SCHEMAS_ENTITIES:
2313 if ((node == NULL) || (node->doc == NULL))
2314 goto return3;
2315 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeEntityDef,
2316 value, val, node);
2317 if (ret <= 0)
2318 ret = 1;
2319 else
2320 ret = 0;
2321 if ((ret == 0) && (node != NULL) &&
2322 (node->type == XML_ATTRIBUTE_NODE)) {
2323 xmlAttrPtr attr = (xmlAttrPtr) node;
2324
2325 attr->atype = XML_ATTRIBUTE_ENTITIES;
2326 }
2327 goto done;
2328 case XML_SCHEMAS_NOTATION:{
2329 xmlChar *uri = NULL;
2330 xmlChar *local = NULL;
2331
2332 ret = xmlValidateQName(value, 1);
2333 if ((ret == 0) && (node != NULL)) {
2334 xmlChar *prefix;
2335
2336 local = xmlSplitQName2(value, &prefix);
2337 if (prefix != NULL) {
2338 xmlNsPtr ns;
2339
2340 ns = xmlSearchNs(node->doc, node, prefix);
2341 if (ns == NULL)
2342 ret = 1;
2343 else if (val != NULL)
2344 uri = xmlStrdup(ns->href);
2345 }
2346 if ((local != NULL) && ((val == NULL) || (ret != 0)))
2347 xmlFree(local);
2348 if (prefix != NULL)
2349 xmlFree(prefix);
2350 }
2351 if ((node == NULL) || (node->doc == NULL))
2352 ret = 3;
2353 if (ret == 0) {
2354 ret = xmlValidateNotationUse(NULL, node->doc, value);
2355 if (ret == 1)
2356 ret = 0;
2357 else
2358 ret = 1;
2359 }
2360 if ((ret == 0) && (val != NULL)) {
2361 v = xmlSchemaNewValue(XML_SCHEMAS_NOTATION);
2362 if (v != NULL) {
2363 if (local != NULL)
2364 v->value.qname.name = local;
2365 else
2366 v->value.qname.name = xmlStrdup(value);
2367 if (uri != NULL)
2368 v->value.qname.uri = uri;
2369
2370 *val = v;
2371 } else {
2372 if (local != NULL)
2373 xmlFree(local);
2374 if (uri != NULL)
2375 xmlFree(uri);
2376 goto error;
2377 }
2378 }
2379 goto done;
2380 }
2381 case XML_SCHEMAS_ANYURI:{
Daniel Veillard11c466a2004-03-14 12:20:15 +00002382 if (*value != 0) {
2383 xmlURIPtr uri = xmlParseURI((const char *) value);
2384 if (uri == NULL)
2385 goto return1;
2386 xmlFreeURI(uri);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002387 }
Daniel Veillard11c466a2004-03-14 12:20:15 +00002388
2389 if (val != NULL) {
2390 v = xmlSchemaNewValue(XML_SCHEMAS_ANYURI);
2391 if (v == NULL)
2392 goto error;
2393 v->value.str = xmlStrdup(value);
2394 *val = v;
2395 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002396 goto return0;
2397 }
2398 case XML_SCHEMAS_HEXBINARY:{
2399 const xmlChar *cur = value;
2400 xmlChar *base;
2401 int total, i = 0;
2402
Daniel Veillardf34a20e2004-08-31 08:42:17 +00002403 if (cur == NULL)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002404 goto return1;
2405
2406 while (((*cur >= '0') && (*cur <= '9')) ||
2407 ((*cur >= 'A') && (*cur <= 'F')) ||
2408 ((*cur >= 'a') && (*cur <= 'f'))) {
2409 i++;
2410 cur++;
2411 }
2412
2413 if (*cur != 0)
2414 goto return1;
2415 if ((i % 2) != 0)
2416 goto return1;
2417
2418 if (val != NULL) {
2419
2420 v = xmlSchemaNewValue(XML_SCHEMAS_HEXBINARY);
2421 if (v == NULL)
2422 goto error;
2423
2424 cur = xmlStrdup(value);
2425 if (cur == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002426 xmlSchemaTypeErrMemory(node, "allocating hexbin data");
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002427 xmlFree(v);
2428 goto return1;
2429 }
2430
2431 total = i / 2; /* number of octets */
2432
2433 base = (xmlChar *) cur;
2434 while (i-- > 0) {
2435 if (*base >= 'a')
2436 *base = *base - ('a' - 'A');
2437 base++;
2438 }
2439
2440 v->value.hex.str = (xmlChar *) cur;
2441 v->value.hex.total = total;
2442 *val = v;
2443 }
2444 goto return0;
2445 }
2446 case XML_SCHEMAS_BASE64BINARY:{
2447 /* ISSUE:
2448 *
2449 * Ignore all stray characters? (yes, currently)
2450 * Worry about long lines? (no, currently)
2451 *
2452 * rfc2045.txt:
2453 *
2454 * "The encoded output stream must be represented in lines of
2455 * no more than 76 characters each. All line breaks or other
2456 * characters not found in Table 1 must be ignored by decoding
2457 * software. In base64 data, characters other than those in
2458 * Table 1, line breaks, and other white space probably
2459 * indicate a transmission error, about which a warning
2460 * message or even a message rejection might be appropriate
2461 * under some circumstances." */
2462 const xmlChar *cur = value;
2463 xmlChar *base;
2464 int total, i = 0, pad = 0;
2465
2466 if (cur == NULL)
2467 goto return1;
2468
2469 for (; *cur; ++cur) {
2470 int decc;
2471
2472 decc = _xmlSchemaBase64Decode(*cur);
2473 if (decc < 0) ;
2474 else if (decc < 64)
2475 i++;
2476 else
2477 break;
2478 }
2479 for (; *cur; ++cur) {
2480 int decc;
2481
2482 decc = _xmlSchemaBase64Decode(*cur);
2483 if (decc < 0) ;
2484 else if (decc < 64)
2485 goto return1;
2486 if (decc == 64)
2487 pad++;
2488 }
2489
2490 /* rfc2045.txt: "Special processing is performed if fewer than
2491 * 24 bits are available at the end of the data being encoded.
2492 * A full encoding quantum is always completed at the end of a
2493 * body. When fewer than 24 input bits are available in an
2494 * input group, zero bits are added (on the right) to form an
2495 * integral number of 6-bit groups. Padding at the end of the
2496 * data is performed using the "=" character. Since all
2497 * base64 input is an integral number of octets, only the
2498 * following cases can arise: (1) the final quantum of
2499 * encoding input is an integral multiple of 24 bits; here,
2500 * the final unit of encoded output will be an integral
2501 * multiple ofindent: Standard input:701: Warning:old style
2502 * assignment ambiguity in "=*". Assuming "= *" 4 characters
2503 * with no "=" padding, (2) the final
2504 * quantum of encoding input is exactly 8 bits; here, the
2505 * final unit of encoded output will be two characters
2506 * followed by two "=" padding characters, or (3) the final
2507 * quantum of encoding input is exactly 16 bits; here, the
2508 * final unit of encoded output will be three characters
2509 * followed by one "=" padding character." */
2510
2511 total = 3 * (i / 4);
2512 if (pad == 0) {
2513 if (i % 4 != 0)
2514 goto return1;
2515 } else if (pad == 1) {
2516 int decc;
2517
2518 if (i % 4 != 3)
2519 goto return1;
2520 for (decc = _xmlSchemaBase64Decode(*cur);
2521 (decc < 0) || (decc > 63);
2522 decc = _xmlSchemaBase64Decode(*cur))
2523 --cur;
2524 /* 16bits in 24bits means 2 pad bits: nnnnnn nnmmmm mmmm00*/
2525 /* 00111100 -> 0x3c */
2526 if (decc & ~0x3c)
2527 goto return1;
2528 total += 2;
2529 } else if (pad == 2) {
2530 int decc;
2531
2532 if (i % 4 != 2)
2533 goto return1;
2534 for (decc = _xmlSchemaBase64Decode(*cur);
2535 (decc < 0) || (decc > 63);
2536 decc = _xmlSchemaBase64Decode(*cur))
2537 --cur;
2538 /* 8bits in 12bits means 4 pad bits: nnnnnn nn0000 */
2539 /* 00110000 -> 0x30 */
2540 if (decc & ~0x30)
2541 goto return1;
2542 total += 1;
2543 } else
2544 goto return1;
2545
2546 if (val != NULL) {
2547 v = xmlSchemaNewValue(XML_SCHEMAS_BASE64BINARY);
2548 if (v == NULL)
2549 goto error;
2550 base =
2551 (xmlChar *) xmlMallocAtomic((i + pad + 1) *
2552 sizeof(xmlChar));
2553 if (base == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002554 xmlSchemaTypeErrMemory(node, "allocating base64 data");
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002555 xmlFree(v);
2556 goto return1;
2557 }
2558 v->value.base64.str = base;
2559 for (cur = value; *cur; ++cur)
2560 if (_xmlSchemaBase64Decode(*cur) >= 0) {
2561 *base = *cur;
2562 ++base;
2563 }
2564 *base = 0;
2565 v->value.base64.total = total;
2566 *val = v;
2567 }
2568 goto return0;
2569 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002570 case XML_SCHEMAS_INTEGER:
2571 case XML_SCHEMAS_PINTEGER:
2572 case XML_SCHEMAS_NPINTEGER:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002573 case XML_SCHEMAS_NINTEGER:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002574 case XML_SCHEMAS_NNINTEGER:{
2575 const xmlChar *cur = value;
2576 unsigned long lo, mi, hi;
2577 int sign = 0;
2578
2579 if (cur == NULL)
2580 goto return1;
2581 if (*cur == '-') {
2582 sign = 1;
2583 cur++;
2584 } else if (*cur == '+')
2585 cur++;
2586 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2587 if (ret == 0)
2588 goto return1;
2589 if (*cur != 0)
2590 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002591 if (type->builtInType == XML_SCHEMAS_NPINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002592 if ((sign == 0) &&
2593 ((hi != 0) || (mi != 0) || (lo != 0)))
2594 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002595 } else if (type->builtInType == XML_SCHEMAS_PINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002596 if (sign == 1)
2597 goto return1;
2598 if ((hi == 0) && (mi == 0) && (lo == 0))
2599 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002600 } else if (type->builtInType == XML_SCHEMAS_NINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002601 if (sign == 0)
2602 goto return1;
2603 if ((hi == 0) && (mi == 0) && (lo == 0))
2604 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002605 } else if (type->builtInType == XML_SCHEMAS_NNINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002606 if ((sign == 1) &&
2607 ((hi != 0) || (mi != 0) || (lo != 0)))
2608 goto return1;
2609 }
2610 /*
2611 * We can store a value only if no overflow occured
2612 */
2613 if ((ret > 0) && (val != NULL)) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00002614 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002615 if (v != NULL) {
2616 v->value.decimal.lo = lo;
2617 v->value.decimal.mi = lo;
2618 v->value.decimal.hi = lo;
2619 v->value.decimal.sign = sign;
2620 v->value.decimal.frac = 0;
2621 v->value.decimal.total = cur - value;
2622 *val = v;
2623 }
2624 }
2625 goto return0;
2626 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002627 case XML_SCHEMAS_LONG:
2628 case XML_SCHEMAS_BYTE:
2629 case XML_SCHEMAS_SHORT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002630 case XML_SCHEMAS_INT:{
2631 const xmlChar *cur = value;
2632 unsigned long lo, mi, hi;
2633 int total = 0;
2634 int sign = 0;
2635
2636 if (cur == NULL)
2637 goto return1;
2638 if (*cur == '-') {
2639 sign = 1;
2640 cur++;
2641 } else if (*cur == '+')
2642 cur++;
2643 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2644 if (ret <= 0)
2645 goto return1;
2646 if (*cur != 0)
2647 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002648 if (type->builtInType == XML_SCHEMAS_LONG) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002649 if (hi >= 922) {
2650 if (hi > 922)
2651 goto return1;
2652 if (mi >= 33720368) {
2653 if (mi > 33720368)
2654 goto return1;
2655 if ((sign == 0) && (lo > 54775807))
2656 goto return1;
2657 if ((sign == 1) && (lo > 54775808))
2658 goto return1;
2659 }
2660 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002661 } else if (type->builtInType == XML_SCHEMAS_INT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002662 if (hi != 0)
2663 goto return1;
2664 if (mi >= 21) {
2665 if (mi > 21)
2666 goto return1;
2667 if ((sign == 0) && (lo > 47483647))
2668 goto return1;
2669 if ((sign == 1) && (lo > 47483648))
2670 goto return1;
2671 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002672 } else if (type->builtInType == XML_SCHEMAS_SHORT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002673 if ((mi != 0) || (hi != 0))
2674 goto return1;
2675 if ((sign == 1) && (lo > 32768))
2676 goto return1;
2677 if ((sign == 0) && (lo > 32767))
2678 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002679 } else if (type->builtInType == XML_SCHEMAS_BYTE) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002680 if ((mi != 0) || (hi != 0))
2681 goto return1;
2682 if ((sign == 1) && (lo > 128))
2683 goto return1;
2684 if ((sign == 0) && (lo > 127))
2685 goto return1;
2686 }
2687 if (val != NULL) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00002688 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002689 if (v != NULL) {
2690 v->value.decimal.lo = lo;
2691 v->value.decimal.mi = lo;
2692 v->value.decimal.hi = lo;
2693 v->value.decimal.sign = sign;
2694 v->value.decimal.frac = 0;
2695 v->value.decimal.total = total;
2696 *val = v;
2697 }
2698 }
2699 goto return0;
2700 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002701 case XML_SCHEMAS_UINT:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002702 case XML_SCHEMAS_ULONG:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002703 case XML_SCHEMAS_USHORT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002704 case XML_SCHEMAS_UBYTE:{
2705 const xmlChar *cur = value;
2706 unsigned long lo, mi, hi;
2707 int total = 0;
2708
2709 if (cur == NULL)
2710 goto return1;
2711 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2712 if (ret <= 0)
2713 goto return1;
2714 if (*cur != 0)
2715 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002716 if (type->builtInType == XML_SCHEMAS_ULONG) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002717 if (hi >= 1844) {
2718 if (hi > 1844)
2719 goto return1;
2720 if (mi >= 67440737) {
2721 if (mi > 67440737)
2722 goto return1;
2723 if (lo > 9551615)
2724 goto return1;
2725 }
2726 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002727 } else if (type->builtInType == XML_SCHEMAS_UINT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002728 if (hi != 0)
2729 goto return1;
2730 if (mi >= 42) {
2731 if (mi > 42)
2732 goto return1;
2733 if (lo > 94967295)
2734 goto return1;
2735 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002736 } else if (type->builtInType == XML_SCHEMAS_USHORT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002737 if ((mi != 0) || (hi != 0))
2738 goto return1;
2739 if (lo > 65535)
2740 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002741 } else if (type->builtInType == XML_SCHEMAS_UBYTE) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002742 if ((mi != 0) || (hi != 0))
2743 goto return1;
2744 if (lo > 255)
2745 goto return1;
2746 }
2747 if (val != NULL) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00002748 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002749 if (v != NULL) {
2750 v->value.decimal.lo = lo;
2751 v->value.decimal.mi = mi;
2752 v->value.decimal.hi = hi;
2753 v->value.decimal.sign = 0;
2754 v->value.decimal.frac = 0;
2755 v->value.decimal.total = total;
2756 *val = v;
2757 }
2758 }
2759 goto return0;
2760 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002761 }
2762
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002763 done:
2764 if (norm != NULL)
2765 xmlFree(norm);
2766 return (ret);
2767 return3:
2768 if (norm != NULL)
2769 xmlFree(norm);
2770 return (3);
2771 return1:
2772 if (norm != NULL)
2773 xmlFree(norm);
2774 return (1);
2775 return0:
2776 if (norm != NULL)
2777 xmlFree(norm);
2778 return (0);
2779 error:
2780 if (norm != NULL)
2781 xmlFree(norm);
2782 return (-1);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002783}
2784
2785/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002786 * xmlSchemaValPredefTypeNode:
Daniel Veillard4255d502002-04-16 15:50:10 +00002787 * @type: the predefined type
2788 * @value: the value to check
2789 * @val: the return computed value
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002790 * @node: the node containing the value
Daniel Veillard4255d502002-04-16 15:50:10 +00002791 *
2792 * Check that a value conforms to the lexical space of the predefined type.
2793 * if true a value is computed and returned in @val.
2794 *
2795 * Returns 0 if this validates, a positive error code number otherwise
2796 * and -1 in case of internal or API error.
2797 */
2798int
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002799xmlSchemaValPredefTypeNode(xmlSchemaTypePtr type, const xmlChar *value,
2800 xmlSchemaValPtr *val, xmlNodePtr node) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002801 return(xmlSchemaValAtomicType(type, value, val, node, 0));
Daniel Veillard4255d502002-04-16 15:50:10 +00002802}
2803
2804/**
Daniel Veillardc0826a72004-08-10 14:17:33 +00002805 * xmlSchemaValPredefTypeNodeNoNorm:
2806 * @type: the predefined type
2807 * @value: the value to check
2808 * @val: the return computed value
2809 * @node: the node containing the value
2810 *
2811 * Check that a value conforms to the lexical space of the predefined type.
2812 * if true a value is computed and returned in @val.
2813 * This one does apply any normalization to the value.
2814 *
2815 * Returns 0 if this validates, a positive error code number otherwise
2816 * and -1 in case of internal or API error.
2817 */
2818int
2819xmlSchemaValPredefTypeNodeNoNorm(xmlSchemaTypePtr type, const xmlChar *value,
2820 xmlSchemaValPtr *val, xmlNodePtr node) {
2821 return(xmlSchemaValAtomicType(type, value, val, node, 1));
2822}
2823
2824/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002825 * xmlSchemaValidatePredefinedType:
2826 * @type: the predefined type
2827 * @value: the value to check
2828 * @val: the return computed value
2829 *
2830 * Check that a value conforms to the lexical space of the predefined type.
2831 * if true a value is computed and returned in @val.
2832 *
2833 * Returns 0 if this validates, a positive error code number otherwise
2834 * and -1 in case of internal or API error.
2835 */
2836int
2837xmlSchemaValidatePredefinedType(xmlSchemaTypePtr type, const xmlChar *value,
2838 xmlSchemaValPtr *val) {
2839 return(xmlSchemaValPredefTypeNode(type, value, val, NULL));
2840}
2841
2842/**
Daniel Veillard4255d502002-04-16 15:50:10 +00002843 * xmlSchemaCompareDecimals:
2844 * @x: a first decimal value
2845 * @y: a second decimal value
2846 *
2847 * Compare 2 decimals
2848 *
2849 * Returns -1 if x < y, 0 if x == y, 1 if x > y and -2 in case of error
2850 */
2851static int
2852xmlSchemaCompareDecimals(xmlSchemaValPtr x, xmlSchemaValPtr y)
2853{
2854 xmlSchemaValPtr swp;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002855 int order = 1, p;
Daniel Veillard4255d502002-04-16 15:50:10 +00002856 unsigned long tmp;
2857
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002858 if ((x->value.decimal.sign) &&
2859 ((x->value.decimal.lo != 0) ||
2860 (x->value.decimal.mi != 0) ||
2861 (x->value.decimal.hi != 0))) {
2862 if ((y->value.decimal.sign) &&
2863 ((y->value.decimal.lo != 0) ||
2864 (y->value.decimal.mi != 0) ||
2865 (y->value.decimal.hi != 0)))
Daniel Veillard80b19092003-03-28 13:29:53 +00002866 order = -1;
2867 else
2868 return (-1);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002869 } else if ((y->value.decimal.sign) &&
2870 ((y->value.decimal.lo != 0) ||
2871 (y->value.decimal.mi != 0) ||
2872 (y->value.decimal.hi != 0))) {
Daniel Veillard4255d502002-04-16 15:50:10 +00002873 return (1);
Daniel Veillard80b19092003-03-28 13:29:53 +00002874 }
Daniel Veillard4255d502002-04-16 15:50:10 +00002875 if (x->value.decimal.frac == y->value.decimal.frac) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002876 if (x->value.decimal.hi < y->value.decimal.hi)
2877 return (-order);
Daniel Veillard01fa6152004-06-29 17:04:39 +00002878 if (x->value.decimal.hi > y->value.decimal.hi)
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002879 return (order);
2880 if (x->value.decimal.mi < y->value.decimal.mi)
2881 return (-order);
Daniel Veillard01fa6152004-06-29 17:04:39 +00002882 if (x->value.decimal.mi > y->value.decimal.mi)
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002883 return (order);
2884 if (x->value.decimal.lo < y->value.decimal.lo)
Daniel Veillard80b19092003-03-28 13:29:53 +00002885 return (-order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002886 if (x->value.decimal.lo > y->value.decimal.lo)
Daniel Veillard80b19092003-03-28 13:29:53 +00002887 return(order);
2888 return(0);
Daniel Veillard4255d502002-04-16 15:50:10 +00002889 }
2890 if (y->value.decimal.frac > x->value.decimal.frac) {
2891 swp = y;
2892 y = x;
2893 x = swp;
2894 order = -order;
2895 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002896 p = powten[x->value.decimal.frac - y->value.decimal.frac];
2897 tmp = x->value.decimal.lo / p;
2898 if (tmp > y->value.decimal.lo)
Daniel Veillard4255d502002-04-16 15:50:10 +00002899 return (order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002900 if (tmp < y->value.decimal.lo)
Daniel Veillard4255d502002-04-16 15:50:10 +00002901 return (-order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002902 tmp = y->value.decimal.lo * p;
2903 if (x->value.decimal.lo < tmp)
Daniel Veillard4255d502002-04-16 15:50:10 +00002904 return (-order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002905 if (x->value.decimal.lo == tmp)
Daniel Veillard4255d502002-04-16 15:50:10 +00002906 return (0);
2907 return (order);
2908}
2909
2910/**
Daniel Veillard070803b2002-05-03 07:29:38 +00002911 * xmlSchemaCompareDurations:
2912 * @x: a first duration value
2913 * @y: a second duration value
2914 *
2915 * Compare 2 durations
2916 *
2917 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
2918 * case of error
2919 */
2920static int
2921xmlSchemaCompareDurations(xmlSchemaValPtr x, xmlSchemaValPtr y)
2922{
2923 long carry, mon, day;
2924 double sec;
Daniel Veillard80b19092003-03-28 13:29:53 +00002925 int invert = 1;
2926 long xmon, xday, myear, minday, maxday;
Daniel Veillard070803b2002-05-03 07:29:38 +00002927 static const long dayRange [2][12] = {
2928 { 0, 28, 59, 89, 120, 150, 181, 212, 242, 273, 303, 334, },
2929 { 0, 31, 62, 92, 123, 153, 184, 215, 245, 276, 306, 337} };
2930
2931 if ((x == NULL) || (y == NULL))
Daniel Veillard5a872412002-05-22 06:40:27 +00002932 return -2;
Daniel Veillard070803b2002-05-03 07:29:38 +00002933
2934 /* months */
2935 mon = x->value.dur.mon - y->value.dur.mon;
2936
2937 /* seconds */
2938 sec = x->value.dur.sec - y->value.dur.sec;
2939 carry = (long)sec / SECS_PER_DAY;
2940 sec -= (double)(carry * SECS_PER_DAY);
2941
2942 /* days */
2943 day = x->value.dur.day - y->value.dur.day + carry;
2944
2945 /* easy test */
2946 if (mon == 0) {
2947 if (day == 0)
2948 if (sec == 0.0)
2949 return 0;
2950 else if (sec < 0.0)
2951 return -1;
2952 else
2953 return 1;
2954 else if (day < 0)
2955 return -1;
2956 else
2957 return 1;
2958 }
2959
2960 if (mon > 0) {
2961 if ((day >= 0) && (sec >= 0.0))
2962 return 1;
2963 else {
2964 xmon = mon;
2965 xday = -day;
2966 }
2967 } else if ((day <= 0) && (sec <= 0.0)) {
2968 return -1;
2969 } else {
Daniel Veillard80b19092003-03-28 13:29:53 +00002970 invert = -1;
Daniel Veillard070803b2002-05-03 07:29:38 +00002971 xmon = -mon;
2972 xday = day;
2973 }
2974
2975 myear = xmon / 12;
Daniel Veillard80b19092003-03-28 13:29:53 +00002976 if (myear == 0) {
2977 minday = 0;
2978 maxday = 0;
2979 } else {
2980 maxday = 366 * ((myear + 3) / 4) +
2981 365 * ((myear - 1) % 4);
2982 minday = maxday - 1;
2983 }
2984
Daniel Veillard070803b2002-05-03 07:29:38 +00002985 xmon = xmon % 12;
2986 minday += dayRange[0][xmon];
2987 maxday += dayRange[1][xmon];
2988
Daniel Veillard80b19092003-03-28 13:29:53 +00002989 if ((maxday == minday) && (maxday == xday))
2990 return(0); /* can this really happen ? */
Daniel Veillard070803b2002-05-03 07:29:38 +00002991 if (maxday < xday)
Daniel Veillard80b19092003-03-28 13:29:53 +00002992 return(-invert);
2993 if (minday > xday)
2994 return(invert);
Daniel Veillard070803b2002-05-03 07:29:38 +00002995
2996 /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00002997 return 2;
2998}
2999
3000/*
3001 * macros for adding date/times and durations
3002 */
3003#define FQUOTIENT(a,b) (floor(((double)a/(double)b)))
3004#define MODULO(a,b) (a - FQUOTIENT(a,b) * b)
3005#define FQUOTIENT_RANGE(a,low,high) (FQUOTIENT((a-low),(high-low)))
3006#define MODULO_RANGE(a,low,high) ((MODULO((a-low),(high-low)))+low)
3007
3008/**
Daniel Veillard669adfc2004-05-29 20:12:46 +00003009 * xmlSchemaDupVal:
3010 * @v: the #xmlSchemaValPtr value to duplicate
3011 *
3012 * Makes a copy of @v. The calling program is responsible for freeing
3013 * the returned value.
3014 *
3015 * returns a pointer to a duplicated #xmlSchemaValPtr or NULL if error.
3016 */
3017static xmlSchemaValPtr
3018xmlSchemaDupVal (xmlSchemaValPtr v)
3019{
3020 xmlSchemaValPtr ret = xmlSchemaNewValue(v->type);
3021 if (ret == NULL)
3022 return NULL;
3023
3024 memcpy(ret, v, sizeof(xmlSchemaVal));
3025 return ret;
3026}
3027
3028/**
Daniel Veillard5a872412002-05-22 06:40:27 +00003029 * _xmlSchemaDateAdd:
3030 * @dt: an #xmlSchemaValPtr
3031 * @dur: an #xmlSchemaValPtr of type #XS_DURATION
3032 *
3033 * Compute a new date/time from @dt and @dur. This function assumes @dt
3034 * is either #XML_SCHEMAS_DATETIME, #XML_SCHEMAS_DATE, #XML_SCHEMAS_GYEARMONTH,
Daniel Veillard669adfc2004-05-29 20:12:46 +00003035 * or #XML_SCHEMAS_GYEAR. The returned #xmlSchemaVal is the same type as
3036 * @dt. The calling program is responsible for freeing the returned value.
Daniel Veillard5a872412002-05-22 06:40:27 +00003037 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00003038 * Returns a pointer to a new #xmlSchemaVal or NULL if error.
Daniel Veillard5a872412002-05-22 06:40:27 +00003039 */
3040static xmlSchemaValPtr
3041_xmlSchemaDateAdd (xmlSchemaValPtr dt, xmlSchemaValPtr dur)
3042{
Daniel Veillard669adfc2004-05-29 20:12:46 +00003043 xmlSchemaValPtr ret, tmp;
Daniel Veillard5a872412002-05-22 06:40:27 +00003044 long carry, tempdays, temp;
3045 xmlSchemaValDatePtr r, d;
3046 xmlSchemaValDurationPtr u;
3047
3048 if ((dt == NULL) || (dur == NULL))
3049 return NULL;
3050
3051 ret = xmlSchemaNewValue(dt->type);
3052 if (ret == NULL)
3053 return NULL;
3054
Daniel Veillard669adfc2004-05-29 20:12:46 +00003055 /* make a copy so we don't alter the original value */
3056 tmp = xmlSchemaDupVal(dt);
3057 if (tmp == NULL) {
3058 xmlSchemaFreeValue(ret);
3059 return NULL;
3060 }
3061
Daniel Veillard5a872412002-05-22 06:40:27 +00003062 r = &(ret->value.date);
Daniel Veillard669adfc2004-05-29 20:12:46 +00003063 d = &(tmp->value.date);
Daniel Veillard5a872412002-05-22 06:40:27 +00003064 u = &(dur->value.dur);
3065
3066 /* normalization */
3067 if (d->mon == 0)
3068 d->mon = 1;
3069
3070 /* normalize for time zone offset */
3071 u->sec -= (d->tzo * 60);
3072 d->tzo = 0;
3073
3074 /* normalization */
3075 if (d->day == 0)
3076 d->day = 1;
3077
3078 /* month */
3079 carry = d->mon + u->mon;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003080 r->mon = (unsigned int) MODULO_RANGE(carry, 1, 13);
3081 carry = (long) FQUOTIENT_RANGE(carry, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00003082
3083 /* year (may be modified later) */
3084 r->year = d->year + carry;
3085 if (r->year == 0) {
3086 if (d->year > 0)
3087 r->year--;
3088 else
3089 r->year++;
3090 }
3091
3092 /* time zone */
3093 r->tzo = d->tzo;
3094 r->tz_flag = d->tz_flag;
3095
3096 /* seconds */
3097 r->sec = d->sec + u->sec;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003098 carry = (long) FQUOTIENT((long)r->sec, 60);
Daniel Veillard5a872412002-05-22 06:40:27 +00003099 if (r->sec != 0.0) {
3100 r->sec = MODULO(r->sec, 60.0);
3101 }
3102
3103 /* minute */
3104 carry += d->min;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003105 r->min = (unsigned int) MODULO(carry, 60);
3106 carry = (long) FQUOTIENT(carry, 60);
Daniel Veillard5a872412002-05-22 06:40:27 +00003107
3108 /* hours */
3109 carry += d->hour;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003110 r->hour = (unsigned int) MODULO(carry, 24);
3111 carry = (long)FQUOTIENT(carry, 24);
Daniel Veillard5a872412002-05-22 06:40:27 +00003112
3113 /*
3114 * days
3115 * Note we use tempdays because the temporary values may need more
3116 * than 5 bits
3117 */
3118 if ((VALID_YEAR(r->year)) && (VALID_MONTH(r->mon)) &&
3119 (d->day > MAX_DAYINMONTH(r->year, r->mon)))
3120 tempdays = MAX_DAYINMONTH(r->year, r->mon);
3121 else if (d->day < 1)
3122 tempdays = 1;
3123 else
3124 tempdays = d->day;
3125
3126 tempdays += u->day + carry;
3127
3128 while (1) {
3129 if (tempdays < 1) {
Daniel Veillardebe25d42004-03-25 09:35:49 +00003130 long tmon = (long) MODULO_RANGE(r->mon-1, 1, 13);
3131 long tyr = r->year + (long)FQUOTIENT_RANGE(r->mon-1, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00003132 if (tyr == 0)
3133 tyr--;
3134 tempdays += MAX_DAYINMONTH(tyr, tmon);
3135 carry = -1;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003136 } else if (tempdays > (long) MAX_DAYINMONTH(r->year, r->mon)) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003137 tempdays = tempdays - MAX_DAYINMONTH(r->year, r->mon);
3138 carry = 1;
3139 } else
3140 break;
3141
3142 temp = r->mon + carry;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003143 r->mon = (unsigned int) MODULO_RANGE(temp, 1, 13);
3144 r->year = r->year + (unsigned int) FQUOTIENT_RANGE(temp, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00003145 if (r->year == 0) {
3146 if (temp < 1)
3147 r->year--;
3148 else
3149 r->year++;
3150 }
3151 }
3152
3153 r->day = tempdays;
3154
3155 /*
3156 * adjust the date/time type to the date values
3157 */
3158 if (ret->type != XML_SCHEMAS_DATETIME) {
3159 if ((r->hour) || (r->min) || (r->sec))
3160 ret->type = XML_SCHEMAS_DATETIME;
3161 else if (ret->type != XML_SCHEMAS_DATE) {
3162 if ((r->mon != 1) && (r->day != 1))
3163 ret->type = XML_SCHEMAS_DATE;
3164 else if ((ret->type != XML_SCHEMAS_GYEARMONTH) && (r->mon != 1))
3165 ret->type = XML_SCHEMAS_GYEARMONTH;
3166 }
3167 }
3168
Daniel Veillard669adfc2004-05-29 20:12:46 +00003169 xmlSchemaFreeValue(tmp);
Daniel Veillard5a872412002-05-22 06:40:27 +00003170
Daniel Veillard5a872412002-05-22 06:40:27 +00003171 return ret;
3172}
3173
3174/**
3175 * xmlSchemaDateNormalize:
Daniel Veillard669adfc2004-05-29 20:12:46 +00003176 * @dt: an #xmlSchemaValPtr of a date/time type value.
3177 * @offset: number of seconds to adjust @dt by.
Daniel Veillard5a872412002-05-22 06:40:27 +00003178 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00003179 * Normalize @dt to GMT time. The @offset parameter is subtracted from
3180 * the return value is a time-zone offset is present on @dt.
Daniel Veillard5a872412002-05-22 06:40:27 +00003181 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00003182 * Returns a normalized copy of @dt or NULL if error.
Daniel Veillard5a872412002-05-22 06:40:27 +00003183 */
3184static xmlSchemaValPtr
3185xmlSchemaDateNormalize (xmlSchemaValPtr dt, double offset)
3186{
3187 xmlSchemaValPtr dur, ret;
3188
3189 if (dt == NULL)
3190 return NULL;
3191
3192 if (((dt->type != XML_SCHEMAS_TIME) &&
3193 (dt->type != XML_SCHEMAS_DATETIME)) || (dt->value.date.tzo == 0))
3194 return xmlSchemaDupVal(dt);
3195
3196 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
3197 if (dur == NULL)
3198 return NULL;
3199
3200 dur->value.date.sec -= offset;
3201
3202 ret = _xmlSchemaDateAdd(dt, dur);
3203 if (ret == NULL)
3204 return NULL;
3205
3206 xmlSchemaFreeValue(dur);
3207
3208 /* ret->value.date.tzo = 0; */
3209 return ret;
3210}
3211
3212/**
3213 * _xmlSchemaDateCastYMToDays:
3214 * @dt: an #xmlSchemaValPtr
3215 *
3216 * Convert mon and year of @dt to total number of days. Take the
3217 * number of years since (or before) 1 AD and add the number of leap
3218 * years. This is a function because negative
3219 * years must be handled a little differently and there is no zero year.
3220 *
3221 * Returns number of days.
3222 */
3223static long
3224_xmlSchemaDateCastYMToDays (const xmlSchemaValPtr dt)
3225{
3226 long ret;
Daniel Veillard49e89632004-09-23 16:24:36 +00003227 int mon;
Daniel Veillard5a872412002-05-22 06:40:27 +00003228
Daniel Veillard49e89632004-09-23 16:24:36 +00003229 mon = dt->value.date.mon;
3230 if (mon <= 0) mon = 1; /* normalization */
3231
3232 if (dt->value.date.year <= 0)
Daniel Veillard5a872412002-05-22 06:40:27 +00003233 ret = (dt->value.date.year * 365) +
3234 (((dt->value.date.year+1)/4)-((dt->value.date.year+1)/100)+
3235 ((dt->value.date.year+1)/400)) +
Daniel Veillard49e89632004-09-23 16:24:36 +00003236 DAY_IN_YEAR(0, mon, dt->value.date.year);
Daniel Veillard5a872412002-05-22 06:40:27 +00003237 else
3238 ret = ((dt->value.date.year-1) * 365) +
3239 (((dt->value.date.year-1)/4)-((dt->value.date.year-1)/100)+
3240 ((dt->value.date.year-1)/400)) +
Daniel Veillard49e89632004-09-23 16:24:36 +00003241 DAY_IN_YEAR(0, mon, dt->value.date.year);
Daniel Veillard5a872412002-05-22 06:40:27 +00003242
3243 return ret;
3244}
3245
3246/**
3247 * TIME_TO_NUMBER:
3248 * @dt: an #xmlSchemaValPtr
3249 *
3250 * Calculates the number of seconds in the time portion of @dt.
3251 *
3252 * Returns seconds.
3253 */
3254#define TIME_TO_NUMBER(dt) \
3255 ((double)((dt->value.date.hour * SECS_PER_HOUR) + \
Daniel Veillardb3721c22003-03-31 11:22:25 +00003256 (dt->value.date.min * SECS_PER_MIN) + \
3257 (dt->value.date.tzo * SECS_PER_MIN)) + \
3258 dt->value.date.sec)
Daniel Veillard5a872412002-05-22 06:40:27 +00003259
3260/**
3261 * xmlSchemaCompareDates:
3262 * @x: a first date/time value
3263 * @y: a second date/time value
3264 *
3265 * Compare 2 date/times
3266 *
3267 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3268 * case of error
3269 */
3270static int
3271xmlSchemaCompareDates (xmlSchemaValPtr x, xmlSchemaValPtr y)
3272{
3273 unsigned char xmask, ymask, xor_mask, and_mask;
3274 xmlSchemaValPtr p1, p2, q1, q2;
3275 long p1d, p2d, q1d, q2d;
3276
3277 if ((x == NULL) || (y == NULL))
3278 return -2;
3279
3280 if (x->value.date.tz_flag) {
3281
3282 if (!y->value.date.tz_flag) {
3283 p1 = xmlSchemaDateNormalize(x, 0);
3284 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3285 /* normalize y + 14:00 */
3286 q1 = xmlSchemaDateNormalize(y, (14 * SECS_PER_HOUR));
3287
3288 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003289 if (p1d < q1d) {
3290 xmlSchemaFreeValue(p1);
3291 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003292 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003293 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003294 double sec;
3295
3296 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00003297 if (sec < 0.0) {
3298 xmlSchemaFreeValue(p1);
3299 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003300 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003301 } else {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003302 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003303 /* normalize y - 14:00 */
3304 q2 = xmlSchemaDateNormalize(y, -(14 * SECS_PER_HOUR));
3305 q2d = _xmlSchemaDateCastYMToDays(q2) + q2->value.date.day;
3306 if (p1d > q2d)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003307 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003308 else if (p1d == q2d) {
3309 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q2);
3310 if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003311 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003312 else
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003313 ret = 2; /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00003314 }
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003315 xmlSchemaFreeValue(p1);
3316 xmlSchemaFreeValue(q1);
3317 xmlSchemaFreeValue(q2);
3318 if (ret != 0)
3319 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003320 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00003321 } else {
3322 xmlSchemaFreeValue(p1);
3323 xmlSchemaFreeValue(q1);
3324 }
Daniel Veillard5a872412002-05-22 06:40:27 +00003325 }
3326 } else if (y->value.date.tz_flag) {
3327 q1 = xmlSchemaDateNormalize(y, 0);
3328 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
3329
3330 /* normalize x - 14:00 */
3331 p1 = xmlSchemaDateNormalize(x, -(14 * SECS_PER_HOUR));
3332 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3333
Daniel Veillardfdc91562002-07-01 21:52:03 +00003334 if (p1d < q1d) {
3335 xmlSchemaFreeValue(p1);
3336 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003337 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003338 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003339 double sec;
3340
3341 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00003342 if (sec < 0.0) {
3343 xmlSchemaFreeValue(p1);
3344 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003345 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003346 } else {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003347 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003348 /* normalize x + 14:00 */
3349 p2 = xmlSchemaDateNormalize(x, (14 * SECS_PER_HOUR));
3350 p2d = _xmlSchemaDateCastYMToDays(p2) + p2->value.date.day;
3351
Daniel Veillard6560a422003-03-27 21:25:38 +00003352 if (p2d > q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003353 ret = 1;
Daniel Veillard6560a422003-03-27 21:25:38 +00003354 } else if (p2d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003355 sec = TIME_TO_NUMBER(p2) - TIME_TO_NUMBER(q1);
3356 if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003357 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003358 else
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003359 ret = 2; /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00003360 }
Daniel Veillard6560a422003-03-27 21:25:38 +00003361 xmlSchemaFreeValue(p1);
3362 xmlSchemaFreeValue(q1);
3363 xmlSchemaFreeValue(p2);
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003364 if (ret != 0)
3365 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003366 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00003367 } else {
3368 xmlSchemaFreeValue(p1);
3369 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003370 }
3371 }
3372
3373 /*
3374 * if the same type then calculate the difference
3375 */
3376 if (x->type == y->type) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003377 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003378 q1 = xmlSchemaDateNormalize(y, 0);
3379 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
3380
3381 p1 = xmlSchemaDateNormalize(x, 0);
3382 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3383
Daniel Veillardfdc91562002-07-01 21:52:03 +00003384 if (p1d < q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003385 ret = -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003386 } else if (p1d > q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003387 ret = 1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003388 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00003389 double sec;
3390
3391 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
3392 if (sec < 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003393 ret = -1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003394 else if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003395 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003396
3397 }
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003398 xmlSchemaFreeValue(p1);
3399 xmlSchemaFreeValue(q1);
3400 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003401 }
3402
3403 switch (x->type) {
3404 case XML_SCHEMAS_DATETIME:
3405 xmask = 0xf;
3406 break;
3407 case XML_SCHEMAS_DATE:
3408 xmask = 0x7;
3409 break;
3410 case XML_SCHEMAS_GYEAR:
3411 xmask = 0x1;
3412 break;
3413 case XML_SCHEMAS_GMONTH:
3414 xmask = 0x2;
3415 break;
3416 case XML_SCHEMAS_GDAY:
3417 xmask = 0x3;
3418 break;
3419 case XML_SCHEMAS_GYEARMONTH:
3420 xmask = 0x3;
3421 break;
3422 case XML_SCHEMAS_GMONTHDAY:
3423 xmask = 0x6;
3424 break;
3425 case XML_SCHEMAS_TIME:
3426 xmask = 0x8;
3427 break;
3428 default:
3429 xmask = 0;
3430 break;
3431 }
3432
3433 switch (y->type) {
3434 case XML_SCHEMAS_DATETIME:
3435 ymask = 0xf;
3436 break;
3437 case XML_SCHEMAS_DATE:
3438 ymask = 0x7;
3439 break;
3440 case XML_SCHEMAS_GYEAR:
3441 ymask = 0x1;
3442 break;
3443 case XML_SCHEMAS_GMONTH:
3444 ymask = 0x2;
3445 break;
3446 case XML_SCHEMAS_GDAY:
3447 ymask = 0x3;
3448 break;
3449 case XML_SCHEMAS_GYEARMONTH:
3450 ymask = 0x3;
3451 break;
3452 case XML_SCHEMAS_GMONTHDAY:
3453 ymask = 0x6;
3454 break;
3455 case XML_SCHEMAS_TIME:
3456 ymask = 0x8;
3457 break;
3458 default:
3459 ymask = 0;
3460 break;
3461 }
3462
3463 xor_mask = xmask ^ ymask; /* mark type differences */
3464 and_mask = xmask & ymask; /* mark field specification */
3465
3466 /* year */
3467 if (xor_mask & 1)
3468 return 2; /* indeterminate */
3469 else if (and_mask & 1) {
3470 if (x->value.date.year < y->value.date.year)
3471 return -1;
3472 else if (x->value.date.year > y->value.date.year)
3473 return 1;
3474 }
3475
3476 /* month */
3477 if (xor_mask & 2)
3478 return 2; /* indeterminate */
3479 else if (and_mask & 2) {
3480 if (x->value.date.mon < y->value.date.mon)
3481 return -1;
3482 else if (x->value.date.mon > y->value.date.mon)
3483 return 1;
3484 }
3485
3486 /* day */
3487 if (xor_mask & 4)
3488 return 2; /* indeterminate */
3489 else if (and_mask & 4) {
3490 if (x->value.date.day < y->value.date.day)
3491 return -1;
3492 else if (x->value.date.day > y->value.date.day)
3493 return 1;
3494 }
3495
3496 /* time */
3497 if (xor_mask & 8)
3498 return 2; /* indeterminate */
3499 else if (and_mask & 8) {
3500 if (x->value.date.hour < y->value.date.hour)
3501 return -1;
3502 else if (x->value.date.hour > y->value.date.hour)
3503 return 1;
3504 else if (x->value.date.min < y->value.date.min)
3505 return -1;
3506 else if (x->value.date.min > y->value.date.min)
3507 return 1;
3508 else if (x->value.date.sec < y->value.date.sec)
3509 return -1;
3510 else if (x->value.date.sec > y->value.date.sec)
3511 return 1;
3512 }
3513
Daniel Veillard070803b2002-05-03 07:29:38 +00003514 return 0;
3515}
3516
3517/**
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003518 * xmlSchemaComparePreserveReplaceStrings:
3519 * @x: a first string value
3520 * @y: a second string value
3521 * @invert: inverts the result if x < y or x > y.
3522 *
3523 * Compare 2 string for their normalized values.
3524 * @x is a string with whitespace of "preserve", @y is
3525 * a string with a whitespace of "replace". I.e. @x could
3526 * be an "xsd:string" and @y an "xsd:normalizedString".
3527 *
3528 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
3529 * case of error
3530 */
3531static int
3532xmlSchemaComparePreserveReplaceStrings(xmlSchemaValPtr x, xmlSchemaValPtr y,
3533 int invert)
3534{
3535 const xmlChar *utf1;
3536 const xmlChar *utf2;
3537 int tmp;
3538
3539 if ((x == NULL) || (y == NULL))
3540 return(-2);
3541 utf1 = x->value.str;
3542 utf2 = y->value.str;
3543
3544 while ((*utf1 != 0) && (*utf2 != 0)) {
3545 if (IS_WSP_REPLACE_CH(*utf2)) {
3546 if (! IS_WSP_SPACE_CH(*utf1)) {
3547 if ((*utf1 - 0x20) < 0) {
3548 if (invert)
3549 return(1);
3550 else
3551 return(-1);
3552 } else {
3553 if (invert)
3554 return(-1);
3555 else
3556 return(1);
3557 }
3558 }
3559 } else {
3560 tmp = *utf1 - *utf2;
3561 if (tmp < 0) {
3562 if (invert)
3563 return(1);
3564 else
3565 return(-1);
3566 }
3567 if (tmp > 0) {
3568 if (invert)
3569 return(-1);
3570 else
3571 return(1);
3572 }
3573 }
3574 utf1++;
3575 utf2++;
3576 }
3577 if (*utf1 != 0) {
3578 if (invert)
3579 return(-1);
3580 else
3581 return(1);
3582 }
3583 if (*utf2 != 0) {
3584 if (invert)
3585 return(1);
3586 else
3587 return(-1);
3588 }
3589 return(0);
3590}
3591
3592/**
3593 * xmlSchemaComparePreserveCollapseStrings:
3594 * @x: a first string value
3595 * @y: a second string value
3596 *
3597 * Compare 2 string for their normalized values.
3598 * @x is a string with whitespace of "preserve", @y is
3599 * a string with a whitespace of "collapse". I.e. @x could
3600 * be an "xsd:string" and @y an "xsd:normalizedString".
3601 *
3602 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
3603 * case of error
3604 */
3605static int
3606xmlSchemaComparePreserveCollapseStrings(xmlSchemaValPtr x, xmlSchemaValPtr y,
3607 int invert)
3608{
3609 const xmlChar *utf1;
3610 const xmlChar *utf2;
3611 int tmp;
3612
3613 if ((x == NULL) || (y == NULL))
3614 return(-2);
3615 utf1 = x->value.str;
3616 utf2 = y->value.str;
3617
3618 /*
3619 * Skip leading blank chars of the collapsed string.
3620 */
3621 while (IS_WSP_SPACE_CH(*utf2) || IS_WSP_REPLACE_CH(*utf2))
3622 utf2++;
3623
3624 while ((*utf1 != 0) && (*utf2 != 0)) {
3625 if (IS_WSP_SPACE_CH(*utf2) || IS_WSP_REPLACE_CH(*utf2)) {
3626 if (! IS_WSP_SPACE_CH(*utf1)) {
3627 /*
3628 * The utf2 character would have been replaced to 0x20.
3629 */
3630 if ((*utf1 - 0x20) < 0) {
3631 if (invert)
3632 return(1);
3633 else
3634 return(-1);
3635 } else {
3636 if (invert)
3637 return(-1);
3638 else
3639 return(1);
3640 }
3641 }
3642 utf1++;
3643 utf2++;
3644 /*
3645 * Skip contiguous blank chars of the collapsed string.
3646 */
3647 while (IS_WSP_SPACE_CH(*utf2) || IS_WSP_REPLACE_CH(*utf2))
3648 utf2++;
3649 } else {
3650 tmp = *utf1++ - *utf2++;
3651 if (tmp < 0) {
3652 if (invert)
3653 return(1);
3654 else
3655 return(-1);
3656 }
3657 if (tmp > 0) {
3658 if (invert)
3659 return(-1);
3660 else
3661 return(1);
3662 }
3663 }
3664 }
3665 if (*utf1 != 0) {
3666 if (invert)
3667 return(-1);
3668 else
3669 return(1);
3670 }
3671 if (*utf2 != 0) {
3672 /*
3673 * Skip trailing blank chars of the collapsed string.
3674 */
3675 while (IS_WSP_SPACE_CH(*utf2) || IS_WSP_REPLACE_CH(*utf2))
3676 utf2++;
3677 if (*utf2 != 0) {
3678 if (invert)
3679 return(1);
3680 else
3681 return(-1);
3682 }
3683 }
3684 return(0);
3685}
3686
3687/**
3688 * xmlSchemaComparePreserveCollapseStrings:
3689 * @x: a first string value
3690 * @y: a second string value
3691 *
3692 * Compare 2 string for their normalized values.
3693 * @x is a string with whitespace of "preserve", @y is
3694 * a string with a whitespace of "collapse". I.e. @x could
3695 * be an "xsd:string" and @y an "xsd:normalizedString".
3696 *
3697 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
3698 * case of error
3699 */
3700static int
3701xmlSchemaCompareReplaceCollapseStrings(xmlSchemaValPtr x, xmlSchemaValPtr y,
3702 int invert)
3703{
3704 const xmlChar *utf1;
3705 const xmlChar *utf2;
3706 int tmp;
3707
3708 if ((x == NULL) || (y == NULL))
3709 return(-2);
3710 utf1 = x->value.str;
3711 utf2 = y->value.str;
3712
3713 /*
3714 * Skip leading blank chars of the collapsed string.
3715 */
3716 while (IS_WSP_SPACE_CH(*utf2) || IS_WSP_REPLACE_CH(*utf2))
3717 utf2++;
3718
3719 while ((*utf1 != 0) && (*utf2 != 0)) {
3720 if (IS_WSP_SPACE_CH(*utf2) || IS_WSP_REPLACE_CH(*utf2)) {
3721 if (! (IS_WSP_SPACE_CH(*utf1) || IS_WSP_REPLACE_CH(*utf1))) {
3722 /*
3723 * The utf2 character would have been replaced to 0x20.
3724 */
3725 if ((*utf1 - 0x20) < 0) {
3726 if (invert)
3727 return(1);
3728 else
3729 return(-1);
3730 } else {
3731 if (invert)
3732 return(-1);
3733 else
3734 return(1);
3735 }
3736 }
3737 utf1++;
3738 utf2++;
3739 /*
3740 * Skip contiguous blank chars of the collapsed string.
3741 */
3742 while (IS_WSP_SPACE_CH(*utf2) || IS_WSP_REPLACE_CH(*utf2))
3743 utf2++;
3744 } else {
3745 if (IS_WSP_SPACE_CH(*utf1) || IS_WSP_REPLACE_CH(*utf1)) {
3746 /*
3747 * The utf1 character would have been replaced to 0x20.
3748 */
3749 if ((0x20 - *utf2) < 0) {
3750 if (invert)
3751 return(1);
3752 else
3753 return(-1);
3754 } else {
3755 if (invert)
3756 return(-1);
3757 else
3758 return(1);
3759 }
3760 }
3761 tmp = *utf1++ - *utf2++;
3762 if (tmp < 0)
3763 return(-1);
3764 if (tmp > 0)
3765 return(1);
3766 }
3767 }
3768 if (*utf1 != 0) {
3769 if (invert)
3770 return(-1);
3771 else
3772 return(1);
3773 }
3774 if (*utf2 != 0) {
3775 /*
3776 * Skip trailing blank chars of the collapsed string.
3777 */
3778 while (IS_WSP_SPACE_CH(*utf2) || IS_WSP_REPLACE_CH(*utf2))
3779 utf2++;
3780 if (*utf2 != 0) {
3781 if (invert)
3782 return(1);
3783 else
3784 return(-1);
3785 }
3786 }
3787 return(0);
3788}
3789
3790
3791/**
3792 * xmlSchemaCompareReplacedStrings:
3793 * @x: a first string value
3794 * @y: a second string value
3795 *
3796 * Compare 2 string for their normalized values.
3797 *
3798 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
3799 * case of error
3800 */
3801static int
3802xmlSchemaCompareReplacedStrings(xmlSchemaValPtr x, xmlSchemaValPtr y)
3803{
3804 const xmlChar *utf1;
3805 const xmlChar *utf2;
3806 int tmp;
3807
3808 if ((x == NULL) || (y == NULL))
3809 return(-2);
3810 utf1 = x->value.str;
3811 utf2 = y->value.str;
3812
3813 while ((*utf1 != 0) && (*utf2 != 0)) {
3814 if (IS_WSP_SPACE_CH(*utf2) || IS_WSP_REPLACE_CH(*utf2)) {
3815 if (! (IS_WSP_SPACE_CH(*utf1) || IS_WSP_REPLACE_CH(*utf1))) {
3816 if ((*utf1 - 0x20) < 0)
3817 return(-1);
3818 else
3819 return(1);
3820 }
3821 } else {
3822 if (IS_WSP_SPACE_CH(*utf1) || IS_WSP_REPLACE_CH(*utf1)) {
3823 if ((0x20 - *utf2) < 0)
3824 return(-1);
3825 else
3826 return(1);
3827 }
3828 tmp = *utf1 - *utf2;
3829 if (tmp < 0)
3830 return(-1);
3831 if (tmp > 0)
3832 return(1);
3833 }
3834 utf1++;
3835 utf2++;
3836 }
3837 if (*utf1 != 0)
3838 return(1);
3839 if (*utf2 != 0)
3840 return(-1);
3841 return(0);
3842}
3843
3844/**
Daniel Veillardc4c21552003-03-29 10:53:38 +00003845 * xmlSchemaCompareNormStrings:
3846 * @x: a first string value
3847 * @y: a second string value
3848 *
3849 * Compare 2 string for their normalized values.
3850 *
3851 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
3852 * case of error
3853 */
3854static int
3855xmlSchemaCompareNormStrings(xmlSchemaValPtr x, xmlSchemaValPtr y) {
3856 const xmlChar *utf1;
3857 const xmlChar *utf2;
3858 int tmp;
3859
3860 if ((x == NULL) || (y == NULL))
3861 return(-2);
3862 utf1 = x->value.str;
3863 utf2 = y->value.str;
3864
William M. Brack76e95df2003-10-18 16:20:14 +00003865 while (IS_BLANK_CH(*utf1)) utf1++;
3866 while (IS_BLANK_CH(*utf2)) utf2++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003867 while ((*utf1 != 0) && (*utf2 != 0)) {
William M. Brack76e95df2003-10-18 16:20:14 +00003868 if (IS_BLANK_CH(*utf1)) {
3869 if (!IS_BLANK_CH(*utf2)) {
Daniel Veillardc4c21552003-03-29 10:53:38 +00003870 tmp = *utf1 - *utf2;
3871 return(tmp);
3872 }
William M. Brack76e95df2003-10-18 16:20:14 +00003873 while (IS_BLANK_CH(*utf1)) utf1++;
3874 while (IS_BLANK_CH(*utf2)) utf2++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003875 } else {
3876 tmp = *utf1++ - *utf2++;
3877 if (tmp < 0)
3878 return(-1);
3879 if (tmp > 0)
3880 return(1);
3881 }
3882 }
3883 if (*utf1 != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00003884 while (IS_BLANK_CH(*utf1)) utf1++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003885 if (*utf1 != 0)
3886 return(1);
3887 }
3888 if (*utf2 != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00003889 while (IS_BLANK_CH(*utf2)) utf2++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003890 if (*utf2 != 0)
3891 return(-1);
3892 }
3893 return(0);
3894}
3895
3896/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003897 * xmlSchemaCompareFloats:
3898 * @x: a first float or double value
3899 * @y: a second float or double value
3900 *
3901 * Compare 2 values
3902 *
3903 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3904 * case of error
3905 */
3906static int
3907xmlSchemaCompareFloats(xmlSchemaValPtr x, xmlSchemaValPtr y) {
3908 double d1, d2;
3909
3910 if ((x == NULL) || (y == NULL))
3911 return(-2);
3912
3913 /*
3914 * Cast everything to doubles.
3915 */
3916 if (x->type == XML_SCHEMAS_DOUBLE)
3917 d1 = x->value.d;
3918 else if (x->type == XML_SCHEMAS_FLOAT)
3919 d1 = x->value.f;
3920 else
3921 return(-2);
3922
3923 if (y->type == XML_SCHEMAS_DOUBLE)
3924 d2 = y->value.d;
3925 else if (y->type == XML_SCHEMAS_FLOAT)
3926 d2 = y->value.f;
3927 else
3928 return(-2);
3929
3930 /*
3931 * Check for special cases.
3932 */
3933 if (xmlXPathIsNaN(d1)) {
3934 if (xmlXPathIsNaN(d2))
3935 return(0);
3936 return(1);
3937 }
3938 if (xmlXPathIsNaN(d2))
3939 return(-1);
3940 if (d1 == xmlXPathPINF) {
3941 if (d2 == xmlXPathPINF)
3942 return(0);
3943 return(1);
3944 }
3945 if (d2 == xmlXPathPINF)
3946 return(-1);
3947 if (d1 == xmlXPathNINF) {
3948 if (d2 == xmlXPathNINF)
3949 return(0);
3950 return(-1);
3951 }
3952 if (d2 == xmlXPathNINF)
3953 return(1);
3954
3955 /*
3956 * basic tests, the last one we should have equality, but
3957 * portability is more important than speed and handling
3958 * NaN or Inf in a portable way is always a challenge, so ...
3959 */
3960 if (d1 < d2)
3961 return(-1);
3962 if (d1 > d2)
3963 return(1);
3964 if (d1 == d2)
3965 return(0);
3966 return(2);
3967}
3968
3969/**
Daniel Veillard4255d502002-04-16 15:50:10 +00003970 * xmlSchemaCompareValues:
3971 * @x: a first value
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003972 * @xwtsp: the whitespace type
Daniel Veillard4255d502002-04-16 15:50:10 +00003973 * @y: a second value
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003974 * @ywtsp: the whitespace type
Daniel Veillard4255d502002-04-16 15:50:10 +00003975 *
3976 * Compare 2 values
3977 *
Daniel Veillard5a872412002-05-22 06:40:27 +00003978 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3979 * case of error
Daniel Veillard4255d502002-04-16 15:50:10 +00003980 */
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003981static int
3982xmlSchemaCompareValuesInternal(xmlSchemaValPtr x,
3983 xmlSchemaWhitespaceValueType xws,
3984 xmlSchemaValPtr y,
3985 xmlSchemaWhitespaceValueType yws) {
Daniel Veillard4255d502002-04-16 15:50:10 +00003986 if ((x == NULL) || (y == NULL))
3987 return(-2);
3988
3989 switch (x->type) {
Daniel Veillard80b19092003-03-28 13:29:53 +00003990 case XML_SCHEMAS_UNKNOWN:
William M. Brack2f2a6632004-08-20 23:09:47 +00003991 case XML_SCHEMAS_ANYTYPE:
3992 case XML_SCHEMAS_ANYSIMPLETYPE:
Daniel Veillard80b19092003-03-28 13:29:53 +00003993 return(-2);
3994 case XML_SCHEMAS_INTEGER:
3995 case XML_SCHEMAS_NPINTEGER:
3996 case XML_SCHEMAS_NINTEGER:
3997 case XML_SCHEMAS_NNINTEGER:
3998 case XML_SCHEMAS_PINTEGER:
3999 case XML_SCHEMAS_INT:
4000 case XML_SCHEMAS_UINT:
4001 case XML_SCHEMAS_LONG:
4002 case XML_SCHEMAS_ULONG:
4003 case XML_SCHEMAS_SHORT:
4004 case XML_SCHEMAS_USHORT:
4005 case XML_SCHEMAS_BYTE:
4006 case XML_SCHEMAS_UBYTE:
Daniel Veillard4255d502002-04-16 15:50:10 +00004007 case XML_SCHEMAS_DECIMAL:
Daniel Veillard80b19092003-03-28 13:29:53 +00004008 if (y->type == x->type)
4009 return(xmlSchemaCompareDecimals(x, y));
4010 if ((y->type == XML_SCHEMAS_DECIMAL) ||
4011 (y->type == XML_SCHEMAS_INTEGER) ||
4012 (y->type == XML_SCHEMAS_NPINTEGER) ||
4013 (y->type == XML_SCHEMAS_NINTEGER) ||
4014 (y->type == XML_SCHEMAS_NNINTEGER) ||
4015 (y->type == XML_SCHEMAS_PINTEGER) ||
4016 (y->type == XML_SCHEMAS_INT) ||
4017 (y->type == XML_SCHEMAS_UINT) ||
4018 (y->type == XML_SCHEMAS_LONG) ||
4019 (y->type == XML_SCHEMAS_ULONG) ||
4020 (y->type == XML_SCHEMAS_SHORT) ||
4021 (y->type == XML_SCHEMAS_USHORT) ||
4022 (y->type == XML_SCHEMAS_BYTE) ||
4023 (y->type == XML_SCHEMAS_UBYTE))
Daniel Veillard4255d502002-04-16 15:50:10 +00004024 return(xmlSchemaCompareDecimals(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00004025 return(-2);
Daniel Veillard070803b2002-05-03 07:29:38 +00004026 case XML_SCHEMAS_DURATION:
4027 if (y->type == XML_SCHEMAS_DURATION)
4028 return(xmlSchemaCompareDurations(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00004029 return(-2);
4030 case XML_SCHEMAS_TIME:
4031 case XML_SCHEMAS_GDAY:
4032 case XML_SCHEMAS_GMONTH:
4033 case XML_SCHEMAS_GMONTHDAY:
4034 case XML_SCHEMAS_GYEAR:
4035 case XML_SCHEMAS_GYEARMONTH:
4036 case XML_SCHEMAS_DATE:
4037 case XML_SCHEMAS_DATETIME:
4038 if ((y->type == XML_SCHEMAS_DATETIME) ||
4039 (y->type == XML_SCHEMAS_TIME) ||
4040 (y->type == XML_SCHEMAS_GDAY) ||
4041 (y->type == XML_SCHEMAS_GMONTH) ||
4042 (y->type == XML_SCHEMAS_GMONTHDAY) ||
4043 (y->type == XML_SCHEMAS_GYEAR) ||
4044 (y->type == XML_SCHEMAS_DATE) ||
4045 (y->type == XML_SCHEMAS_GYEARMONTH))
4046 return (xmlSchemaCompareDates(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00004047 return (-2);
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004048 case XML_SCHEMAS_STRING:
4049 case XML_SCHEMAS_NORMSTRING:
Daniel Veillard80b19092003-03-28 13:29:53 +00004050 case XML_SCHEMAS_TOKEN:
4051 case XML_SCHEMAS_LANGUAGE:
4052 case XML_SCHEMAS_NMTOKEN:
Daniel Veillard80b19092003-03-28 13:29:53 +00004053 case XML_SCHEMAS_NAME:
Daniel Veillard80b19092003-03-28 13:29:53 +00004054 case XML_SCHEMAS_NCNAME:
4055 case XML_SCHEMAS_ID:
4056 case XML_SCHEMAS_IDREF:
Daniel Veillard80b19092003-03-28 13:29:53 +00004057 case XML_SCHEMAS_ENTITY:
Daniel Veillard80b19092003-03-28 13:29:53 +00004058 case XML_SCHEMAS_NOTATION:
4059 case XML_SCHEMAS_ANYURI:
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004060 /*
4061 * TODO: Compare those against QName.
4062 */
4063 if (y->type == XML_SCHEMAS_QNAME) {
4064 TODO
4065 return (-2);
4066 }
4067 if ((y->type == XML_SCHEMAS_STRING) ||
4068 (y->type == XML_SCHEMAS_NORMSTRING) ||
Daniel Veillardc4c21552003-03-29 10:53:38 +00004069 (y->type == XML_SCHEMAS_TOKEN) ||
4070 (y->type == XML_SCHEMAS_LANGUAGE) ||
4071 (y->type == XML_SCHEMAS_NMTOKEN) ||
4072 (y->type == XML_SCHEMAS_NAME) ||
Daniel Veillardc4c21552003-03-29 10:53:38 +00004073 (y->type == XML_SCHEMAS_NCNAME) ||
4074 (y->type == XML_SCHEMAS_ID) ||
4075 (y->type == XML_SCHEMAS_IDREF) ||
4076 (y->type == XML_SCHEMAS_ENTITY) ||
4077 (y->type == XML_SCHEMAS_NOTATION) ||
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004078 (y->type == XML_SCHEMAS_ANYURI)) {
4079
4080 if (xws == XML_SCHEMA_WHITESPACE_PRESERVE) {
4081
4082 if (yws == XML_SCHEMA_WHITESPACE_PRESERVE) {
4083 /* TODO: What about x < y or x > y. */
4084 if (xmlStrEqual(x->value.str, y->value.str))
4085 return (0);
4086 else
4087 return (2);
4088 } else if (yws == XML_SCHEMA_WHITESPACE_REPLACE)
4089 return (xmlSchemaComparePreserveReplaceStrings(x, y, 0));
4090 else if (yws == XML_SCHEMA_WHITESPACE_COLLAPSE)
4091 return (xmlSchemaComparePreserveCollapseStrings(x, y, 0));
4092
4093 } else if (xws == XML_SCHEMA_WHITESPACE_REPLACE) {
4094
4095 if (yws == XML_SCHEMA_WHITESPACE_PRESERVE)
4096 return (xmlSchemaComparePreserveReplaceStrings(y, x, 1));
4097 if (yws == XML_SCHEMA_WHITESPACE_REPLACE)
4098 return (xmlSchemaCompareReplacedStrings(x, y));
4099 if (yws == XML_SCHEMA_WHITESPACE_COLLAPSE)
4100 return (xmlSchemaCompareReplaceCollapseStrings(x, y, 0));
4101
4102 } else if (xws == XML_SCHEMA_WHITESPACE_COLLAPSE) {
4103
4104 if (yws == XML_SCHEMA_WHITESPACE_PRESERVE)
4105 return (xmlSchemaComparePreserveCollapseStrings(y, x, 1));
4106 if (yws == XML_SCHEMA_WHITESPACE_REPLACE)
4107 return (xmlSchemaCompareReplaceCollapseStrings(y, x, 1));
4108 if (yws == XML_SCHEMA_WHITESPACE_COLLAPSE)
4109 return (xmlSchemaCompareNormStrings(x, y));
4110 } else
4111 return (-2);
4112
4113 }
Daniel Veillardc4c21552003-03-29 10:53:38 +00004114 return (-2);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004115 case XML_SCHEMAS_QNAME:
4116 if (y->type == XML_SCHEMAS_QNAME) {
4117 if ((xmlStrEqual(x->value.qname.name, y->value.qname.name)) &&
4118 (xmlStrEqual(x->value.qname.uri, y->value.qname.uri)))
4119 return(0);
4120 return(2);
4121 }
4122 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00004123 case XML_SCHEMAS_FLOAT:
4124 case XML_SCHEMAS_DOUBLE:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00004125 if ((y->type == XML_SCHEMAS_FLOAT) ||
4126 (y->type == XML_SCHEMAS_DOUBLE))
4127 return (xmlSchemaCompareFloats(x, y));
4128 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00004129 case XML_SCHEMAS_BOOLEAN:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00004130 if (y->type == XML_SCHEMAS_BOOLEAN) {
4131 if (x->value.b == y->value.b)
4132 return(0);
4133 if (x->value.b == 0)
4134 return(-1);
4135 return(1);
4136 }
4137 return (-2);
Daniel Veillard560c2a42003-07-06 21:13:49 +00004138 case XML_SCHEMAS_HEXBINARY:
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004139 if (y->type == XML_SCHEMAS_HEXBINARY) {
4140 if (x->value.hex.total == y->value.hex.total) {
4141 int ret = xmlStrcmp(x->value.hex.str, y->value.hex.str);
4142 if (ret > 0)
4143 return(1);
4144 else if (ret == 0)
4145 return(0);
4146 }
4147 else if (x->value.hex.total > y->value.hex.total)
4148 return(1);
4149
4150 return(-1);
4151 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00004152 return (-2);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00004153 case XML_SCHEMAS_BASE64BINARY:
4154 if (y->type == XML_SCHEMAS_BASE64BINARY) {
4155 if (x->value.base64.total == y->value.base64.total) {
4156 int ret = xmlStrcmp(x->value.base64.str,
4157 y->value.base64.str);
4158 if (ret > 0)
4159 return(1);
4160 else if (ret == 0)
4161 return(0);
4162 }
4163 else if (x->value.base64.total > y->value.base64.total)
4164 return(1);
4165 else
4166 return(-1);
4167 }
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004168 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00004169 case XML_SCHEMAS_IDREFS:
4170 case XML_SCHEMAS_ENTITIES:
4171 case XML_SCHEMAS_NMTOKENS:
4172 TODO
4173 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00004174 }
Daniel Veillard5a872412002-05-22 06:40:27 +00004175 return -2;
Daniel Veillard4255d502002-04-16 15:50:10 +00004176}
4177
4178/**
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004179 * xmlSchemaCompareValues:
4180 * @x: a first value
4181 * @y: a second value
4182 *
4183 * Compare 2 values
4184 *
4185 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
4186 * case of error
4187 */
4188int
4189xmlSchemaCompareValues(xmlSchemaValPtr x, xmlSchemaValPtr y) {
4190 xmlSchemaWhitespaceValueType xws, yws;
4191
4192 if (x->type == XML_SCHEMAS_STRING)
4193 xws = XML_SCHEMA_WHITESPACE_PRESERVE;
4194 else if (x->type == XML_SCHEMAS_NORMSTRING)
4195 xws = XML_SCHEMA_WHITESPACE_REPLACE;
4196 else
4197 xws = XML_SCHEMA_WHITESPACE_COLLAPSE;
4198
4199 if (y->type == XML_SCHEMAS_STRING)
4200 yws = XML_SCHEMA_WHITESPACE_PRESERVE;
4201 else if (x->type == XML_SCHEMAS_NORMSTRING)
4202 yws = XML_SCHEMA_WHITESPACE_REPLACE;
4203 else
4204 yws = XML_SCHEMA_WHITESPACE_COLLAPSE;
4205
4206 return(xmlSchemaCompareValuesInternal(x, xws, y, yws));
4207}
4208
4209/**
4210 * xmlSchemaCompareValuesWhtsp:
4211 * @x: a first value
4212 * @xws: the whitespace value of x
4213 * @y: a second value
4214 * @yws: the whitespace value of y
4215 *
4216 * Compare 2 values
4217 *
4218 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
4219 * case of error
4220 */
4221int
4222xmlSchemaCompareValuesWhtsp(xmlSchemaValPtr x,
4223 xmlSchemaWhitespaceValueType xws,
4224 xmlSchemaValPtr y,
4225 xmlSchemaWhitespaceValueType yws) {
4226 return(xmlSchemaCompareValuesInternal(x, xws, y, yws));
4227}
4228
4229/**
Daniel Veillardc4c21552003-03-29 10:53:38 +00004230 * xmlSchemaNormLen:
4231 * @value: a string
4232 *
4233 * Computes the UTF8 length of the normalized value of the string
4234 *
4235 * Returns the length or -1 in case of error.
4236 */
4237static int
4238xmlSchemaNormLen(const xmlChar *value) {
4239 const xmlChar *utf;
4240 int ret = 0;
4241
4242 if (value == NULL)
4243 return(-1);
4244 utf = value;
William M. Brack76e95df2003-10-18 16:20:14 +00004245 while (IS_BLANK_CH(*utf)) utf++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00004246 while (*utf != 0) {
4247 if (utf[0] & 0x80) {
4248 if ((utf[1] & 0xc0) != 0x80)
4249 return(-1);
4250 if ((utf[0] & 0xe0) == 0xe0) {
4251 if ((utf[2] & 0xc0) != 0x80)
4252 return(-1);
4253 if ((utf[0] & 0xf0) == 0xf0) {
4254 if ((utf[0] & 0xf8) != 0xf0 || (utf[3] & 0xc0) != 0x80)
4255 return(-1);
4256 utf += 4;
4257 } else {
4258 utf += 3;
4259 }
4260 } else {
4261 utf += 2;
4262 }
William M. Brack76e95df2003-10-18 16:20:14 +00004263 } else if (IS_BLANK_CH(*utf)) {
4264 while (IS_BLANK_CH(*utf)) utf++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00004265 if (*utf == 0)
4266 break;
4267 } else {
4268 utf++;
4269 }
4270 ret++;
4271 }
4272 return(ret);
4273}
4274
Daniel Veillard6927b102004-10-27 17:29:04 +00004275/**
4276 * xmlSchemaGetFacetValueAsULong:
4277 * @facet: an schemas type facet
4278 *
4279 * Extract the value of a facet
4280 *
4281 * Returns the value as a long
4282 */
Daniel Veillardc0826a72004-08-10 14:17:33 +00004283unsigned long
4284xmlSchemaGetFacetValueAsULong(xmlSchemaFacetPtr facet)
4285{
4286 /*
4287 * TODO: Check if this is a decimal.
4288 */
William M. Brack094dd862004-11-14 14:28:34 +00004289 if (facet == NULL)
4290 return 0;
Daniel Veillardc0826a72004-08-10 14:17:33 +00004291 return ((unsigned long) facet->val->value.decimal.lo);
4292}
4293
Daniel Veillardc4c21552003-03-29 10:53:38 +00004294/**
Daniel Veillard01fa6152004-06-29 17:04:39 +00004295 * xmlSchemaValidateListSimpleTypeFacet:
4296 * @facet: the facet to check
4297 * @value: the lexical repr of the value to validate
4298 * @actualLen: the number of list items
4299 * @expectedLen: the resulting expected number of list items
4300 *
4301 * Checks the value of a list simple type against a facet.
4302 *
4303 * Returns 0 if the value is valid, a positive error code
4304 * number otherwise and -1 in case of an internal error.
4305 */
4306int
4307xmlSchemaValidateListSimpleTypeFacet(xmlSchemaFacetPtr facet,
4308 const xmlChar *value,
4309 unsigned long actualLen,
4310 unsigned long *expectedLen)
4311{
Daniel Veillardce682bc2004-11-05 17:22:25 +00004312 if (facet == NULL)
4313 return(-1);
Daniel Veillard01fa6152004-06-29 17:04:39 +00004314 /*
4315 * TODO: Check if this will work with large numbers.
4316 * (compare value.decimal.mi and value.decimal.hi as well?).
4317 */
4318 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
4319 if (actualLen != facet->val->value.decimal.lo) {
Daniel Veillardc0826a72004-08-10 14:17:33 +00004320 if (expectedLen != 0)
4321 *expectedLen = facet->val->value.decimal.lo;
Daniel Veillard01fa6152004-06-29 17:04:39 +00004322 return (XML_SCHEMAV_CVC_LENGTH_VALID);
4323 }
4324 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
4325 if (actualLen < facet->val->value.decimal.lo) {
Daniel Veillardc0826a72004-08-10 14:17:33 +00004326 if (expectedLen != 0)
4327 *expectedLen = facet->val->value.decimal.lo;
Daniel Veillard01fa6152004-06-29 17:04:39 +00004328 return (XML_SCHEMAV_CVC_MINLENGTH_VALID);
4329 }
4330 } else if (facet->type == XML_SCHEMA_FACET_MAXLENGTH) {
4331 if (actualLen > facet->val->value.decimal.lo) {
Daniel Veillardc0826a72004-08-10 14:17:33 +00004332 if (expectedLen != 0)
4333 *expectedLen = facet->val->value.decimal.lo;
Daniel Veillard01fa6152004-06-29 17:04:39 +00004334 return (XML_SCHEMAV_CVC_MAXLENGTH_VALID);
4335 }
4336 } else
4337 /*
4338 * NOTE: That we can pass NULL as xmlSchemaValPtr to
4339 * xmlSchemaValidateFacet, since the remaining facet types
4340 * are: XML_SCHEMA_FACET_PATTERN, XML_SCHEMA_FACET_ENUMERATION.
4341 */
4342 return(xmlSchemaValidateFacet(NULL, facet, value, NULL));
4343 return (0);
4344}
4345
4346/**
Daniel Veillard6927b102004-10-27 17:29:04 +00004347 * xmlSchemaValidateLengthFacet:
Daniel Veillardc0826a72004-08-10 14:17:33 +00004348 * @type: the built-in type
4349 * @facet: the facet to check
4350 * @value: the lexical repr. of the value to be validated
4351 * @val: the precomputed value
4352 * @length: the actual length of the value
4353 *
4354 * Checka a value against a "length", "minLength" and "maxLength"
4355 * facet; sets @length to the computed length of @value.
4356 *
4357 * Returns 0 if the value is valid, a positive error code
4358 * otherwise and -1 in case of an internal or API error.
4359 */
4360int
4361xmlSchemaValidateLengthFacet(xmlSchemaTypePtr type,
4362 xmlSchemaFacetPtr facet,
4363 const xmlChar *value,
4364 xmlSchemaValPtr val,
4365 unsigned long *length)
4366{
4367 unsigned int len = 0;
4368
Daniel Veillardce682bc2004-11-05 17:22:25 +00004369 if ((length == NULL) || (facet == NULL) || (type == NULL))
4370 return (-1);
Daniel Veillardc0826a72004-08-10 14:17:33 +00004371 *length = 0;
4372 if ((facet->type != XML_SCHEMA_FACET_LENGTH) &&
4373 (facet->type != XML_SCHEMA_FACET_MAXLENGTH) &&
4374 (facet->type != XML_SCHEMA_FACET_MINLENGTH))
4375 return (-1);
4376
4377 if ((facet->val == NULL) ||
4378 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
4379 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
4380 (facet->val->value.decimal.frac != 0)) {
4381 return(-1);
4382 }
4383 if ((val != NULL) && (val->type == XML_SCHEMAS_HEXBINARY))
4384 len = val->value.hex.total;
4385 else if ((val != NULL) && (val->type == XML_SCHEMAS_BASE64BINARY))
4386 len = val->value.base64.total;
4387 else {
4388 switch (type->builtInType) {
4389 case XML_SCHEMAS_IDREF:
4390 case XML_SCHEMAS_NORMSTRING:
4391 case XML_SCHEMAS_TOKEN:
4392 case XML_SCHEMAS_LANGUAGE:
4393 case XML_SCHEMAS_NMTOKEN:
4394 case XML_SCHEMAS_NAME:
4395 case XML_SCHEMAS_NCNAME:
4396 case XML_SCHEMAS_ID:
4397 len = xmlSchemaNormLen(value);
4398 break;
4399 case XML_SCHEMAS_STRING:
4400 /*
4401 * FIXME: What exactly to do with anyURI?
4402 */
4403 case XML_SCHEMAS_ANYURI:
4404 if (value != NULL)
4405 len = xmlUTF8Strlen(value);
4406 break;
4407 default:
4408 TODO
4409 }
4410 }
4411 *length = (unsigned long) len;
4412 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
4413 if (len != facet->val->value.decimal.lo)
4414 return(XML_SCHEMAV_CVC_LENGTH_VALID);
4415 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
4416 if (len < facet->val->value.decimal.lo)
4417 return(XML_SCHEMAV_CVC_MINLENGTH_VALID);
4418 } else {
4419 if (len > facet->val->value.decimal.lo)
4420 return(XML_SCHEMAV_CVC_MAXLENGTH_VALID);
4421 }
4422
4423 return (0);
4424}
4425
4426/**
4427 * xmlSchemaValidateFacet:
Daniel Veillard01c13b52002-12-10 15:19:08 +00004428 * @base: the base type
Daniel Veillard4255d502002-04-16 15:50:10 +00004429 * @facet: the facet to check
4430 * @value: the lexical repr of the value to validate
4431 * @val: the precomputed value
4432 *
4433 * Check a value against a facet condition
4434 *
4435 * Returns 0 if the element is schemas valid, a positive error code
4436 * number otherwise and -1 in case of internal or API error.
4437 */
4438int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00004439xmlSchemaValidateFacet(xmlSchemaTypePtr base ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +00004440 xmlSchemaFacetPtr facet,
Daniel Veillard4255d502002-04-16 15:50:10 +00004441 const xmlChar *value, xmlSchemaValPtr val)
4442{
4443 int ret;
4444
Daniel Veillardce682bc2004-11-05 17:22:25 +00004445 if ((facet == NULL) || (value == NULL))
4446 return(-1);
Daniel Veillard4255d502002-04-16 15:50:10 +00004447 switch (facet->type) {
4448 case XML_SCHEMA_FACET_PATTERN:
4449 ret = xmlRegexpExec(facet->regexp, value);
4450 if (ret == 1)
4451 return(0);
4452 if (ret == 0) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00004453 return(XML_SCHEMAV_CVC_PATTERN_VALID);
Daniel Veillard4255d502002-04-16 15:50:10 +00004454 }
4455 return(ret);
4456 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
4457 ret = xmlSchemaCompareValues(val, facet->val);
4458 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004459 /* TODO error code */
Daniel Veillard4255d502002-04-16 15:50:10 +00004460 return(-1);
4461 }
4462 if (ret == -1)
4463 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00004464 /* error code */
Daniel Veillard01fa6152004-06-29 17:04:39 +00004465 return(XML_SCHEMAV_CVC_MAXEXCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00004466 case XML_SCHEMA_FACET_MAXINCLUSIVE:
4467 ret = xmlSchemaCompareValues(val, facet->val);
4468 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004469 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00004470 return(-1);
4471 }
4472 if ((ret == -1) || (ret == 0))
4473 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00004474 /* error code */
Daniel Veillard01fa6152004-06-29 17:04:39 +00004475 return(XML_SCHEMAV_CVC_MAXINCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00004476 case XML_SCHEMA_FACET_MINEXCLUSIVE:
4477 ret = xmlSchemaCompareValues(val, facet->val);
4478 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004479 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00004480 return(-1);
4481 }
4482 if (ret == 1)
4483 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00004484 /* error code */
Daniel Veillard01fa6152004-06-29 17:04:39 +00004485 return(XML_SCHEMAV_CVC_MINEXCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00004486 case XML_SCHEMA_FACET_MININCLUSIVE:
4487 ret = xmlSchemaCompareValues(val, facet->val);
4488 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004489 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00004490 return(-1);
4491 }
4492 if ((ret == 1) || (ret == 0))
4493 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00004494 /* error code */
Daniel Veillard01fa6152004-06-29 17:04:39 +00004495 return(XML_SCHEMAV_CVC_MININCLUSIVE_VALID);
Daniel Veillard8651f532002-04-17 09:06:27 +00004496 case XML_SCHEMA_FACET_WHITESPACE:
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004497 /* TODO whitespaces */
Daniel Veillard01fa6152004-06-29 17:04:39 +00004498 /*
4499 * NOTE: Whitespace should be handled to normalize
4500 * the value to be validated against a the facets;
4501 * not to normalize the value in-between.
4502 */
Daniel Veillard8651f532002-04-17 09:06:27 +00004503 return(0);
Daniel Veillard88c58912002-04-23 07:12:20 +00004504 case XML_SCHEMA_FACET_ENUMERATION:
4505 if ((facet->value != NULL) &&
4506 (xmlStrEqual(facet->value, value)))
4507 return(0);
Daniel Veillard01fa6152004-06-29 17:04:39 +00004508 return(XML_SCHEMAV_CVC_ENUMERATION_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004509 case XML_SCHEMA_FACET_LENGTH:
4510 case XML_SCHEMA_FACET_MAXLENGTH:
4511 case XML_SCHEMA_FACET_MINLENGTH: {
4512 unsigned int len = 0;
4513
4514 if ((facet->val == NULL) ||
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004515 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
4516 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004517 (facet->val->value.decimal.frac != 0)) {
4518 return(-1);
4519 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00004520 if ((val != NULL) && (val->type == XML_SCHEMAS_HEXBINARY))
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004521 len = val->value.hex.total;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00004522 else if ((val != NULL) && (val->type == XML_SCHEMAS_BASE64BINARY))
4523 len = val->value.base64.total;
4524 else {
Daniel Veillard01fa6152004-06-29 17:04:39 +00004525 switch (base->builtInType) {
Daniel Veillard560c2a42003-07-06 21:13:49 +00004526 case XML_SCHEMAS_IDREF:
4527 case XML_SCHEMAS_NORMSTRING:
4528 case XML_SCHEMAS_TOKEN:
4529 case XML_SCHEMAS_LANGUAGE:
4530 case XML_SCHEMAS_NMTOKEN:
4531 case XML_SCHEMAS_NAME:
4532 case XML_SCHEMAS_NCNAME:
4533 case XML_SCHEMAS_ID:
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004534 len = xmlSchemaNormLen(value);
4535 break;
Daniel Veillard560c2a42003-07-06 21:13:49 +00004536 case XML_SCHEMAS_STRING:
Daniel Veillard01fa6152004-06-29 17:04:39 +00004537 /*
4538 * FIXME: What exactly to do with anyURI?
4539 */
4540 case XML_SCHEMAS_ANYURI:
William M. Brackfbf2c5e2004-02-03 17:55:56 +00004541 if (value != NULL)
4542 len = xmlUTF8Strlen(value);
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004543 break;
Daniel Veillard560c2a42003-07-06 21:13:49 +00004544 default:
4545 TODO
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004546 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004547 }
4548 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004549 if (len != facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004550 return(XML_SCHEMAV_CVC_LENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004551 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004552 if (len < facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004553 return(XML_SCHEMAV_CVC_MINLENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004554 } else {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004555 if (len > facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004556 return(XML_SCHEMAV_CVC_MAXLENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004557 }
4558 break;
4559 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00004560 case XML_SCHEMA_FACET_TOTALDIGITS:
4561 case XML_SCHEMA_FACET_FRACTIONDIGITS:
4562
4563 if ((facet->val == NULL) ||
4564 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
4565 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
4566 (facet->val->value.decimal.frac != 0)) {
4567 return(-1);
4568 }
4569 if ((val == NULL) ||
4570 ((val->type != XML_SCHEMAS_DECIMAL) &&
4571 (val->type != XML_SCHEMAS_INTEGER) &&
4572 (val->type != XML_SCHEMAS_NPINTEGER) &&
4573 (val->type != XML_SCHEMAS_NINTEGER) &&
4574 (val->type != XML_SCHEMAS_NNINTEGER) &&
4575 (val->type != XML_SCHEMAS_PINTEGER) &&
4576 (val->type != XML_SCHEMAS_INT) &&
4577 (val->type != XML_SCHEMAS_UINT) &&
4578 (val->type != XML_SCHEMAS_LONG) &&
4579 (val->type != XML_SCHEMAS_ULONG) &&
4580 (val->type != XML_SCHEMAS_SHORT) &&
4581 (val->type != XML_SCHEMAS_USHORT) &&
4582 (val->type != XML_SCHEMAS_BYTE) &&
4583 (val->type != XML_SCHEMAS_UBYTE))) {
4584 return(-1);
4585 }
4586 if (facet->type == XML_SCHEMA_FACET_TOTALDIGITS) {
4587 if (val->value.decimal.total > facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004588 return(XML_SCHEMAV_CVC_TOTALDIGITS_VALID);
Daniel Veillard560c2a42003-07-06 21:13:49 +00004589
4590 } else if (facet->type == XML_SCHEMA_FACET_FRACTIONDIGITS) {
4591 if (val->value.decimal.frac > facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004592 return(XML_SCHEMAV_CVC_FRACTIONDIGITS_VALID);
Daniel Veillard560c2a42003-07-06 21:13:49 +00004593 }
4594 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00004595 default:
4596 TODO
4597 }
4598 return(0);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00004599
Daniel Veillard4255d502002-04-16 15:50:10 +00004600}
4601
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004602/**
4603 * xmlSchemaGetCanonValue:
4604 * @val: the precomputed value
4605 * @retValue: the returned value
4606 *
4607 * Returns a the cononical representation of the value.
4608 * The called has to free the returned retValue.
4609 *
4610 * Returns 0 if the value could be built and -1 in case of
4611 * API errors or if the value type is not supported yet.
4612 */
4613int
4614xmlSchemaGetCanonValue(xmlSchemaValPtr val,
4615 const xmlChar **retValue)
4616{
4617 if (retValue == NULL)
4618 return (-1);
4619 *retValue = NULL;
4620 switch (val->type) {
4621 case XML_SCHEMAS_STRING:
4622 case XML_SCHEMAS_NORMSTRING:
4623 /*
4624 case XML_SCHEMAS_TOKEN:
4625 case XML_SCHEMAS_LANGUAGE:
4626 case XML_SCHEMAS_NMTOKEN:
4627 case XML_SCHEMAS_NAME:
4628 case XML_SCHEMAS_QNAME:
4629 case XML_SCHEMAS_NCNAME:
4630 case XML_SCHEMAS_ID:
4631 case XML_SCHEMAS_IDREF:
4632 case XML_SCHEMAS_ENTITY:
4633 case XML_SCHEMAS_NOTATION:
4634 case XML_SCHEMAS_ANYURI:
4635 */
4636 if (val->value.str == NULL)
4637 *retValue = NULL;
4638 else
4639 /* TODO: This is not yet correct for non-normalized values. */
4640 *retValue =
4641 BAD_CAST xmlStrdup((const xmlChar *) val->value.str);
4642 return (0);
4643 default:
4644 return (-1);
4645 }
4646 return (-1);
4647}
4648
Daniel Veillard4255d502002-04-16 15:50:10 +00004649#endif /* LIBXML_SCHEMAS_ENABLED */