blob: b5d48c5334d447a0f2b8f11fff71c1a95850ff94 [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
Daniel Veillardb5839c32005-02-19 18:27:14 +0000687 * @value: the value
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +0000688 *
689 * Allocate a new simple type value. The type can be
Kasimier T. Buchcik2ee855d2005-03-07 11:14:14 +0000690 * of XML_SCHEMAS_STRING.
691 * WARNING: This one is intended to be expanded for other
692 * string based types. We need this for anySimpleType as well.
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +0000693 *
694 * Returns a pointer to the new value or NULL in case of error
695 */
696xmlSchemaValPtr
697xmlSchemaNewStringValue(xmlSchemaValType type,
698 const xmlChar *value)
699{
700 xmlSchemaValPtr val;
701
702 if (type != XML_SCHEMAS_STRING)
703 return(NULL);
704 val = (xmlSchemaValPtr) xmlMalloc(sizeof(xmlSchemaVal));
705 if (val == NULL) {
706 return(NULL);
707 }
708 memset(val, 0, sizeof(xmlSchemaVal));
709 val->type = type;
710 val->value.str = (xmlChar *) value;
711 return(val);
712}
713
Kasimier T. Buchcikb06b4de2005-02-17 19:00:23 +0000714/**
715 * xmlSchemaNewNOTATIONValue:
Daniel Veillardb5839c32005-02-19 18:27:14 +0000716 * @name: the notation name
717 * @ns: the notation namespace name or NULL
Kasimier T. Buchcikb06b4de2005-02-17 19:00:23 +0000718 *
719 * Allocate a new NOTATION value.
720 *
721 * Returns a pointer to the new value or NULL in case of error
722 */
723xmlSchemaValPtr
724xmlSchemaNewNOTATIONValue(const xmlChar *name,
725 const xmlChar *ns)
726{
727 xmlSchemaValPtr val;
728
729 val = xmlSchemaNewValue(XML_SCHEMAS_NOTATION);
730 if (val == NULL)
731 return (NULL);
732
William M. Brack12d37ab2005-02-21 13:54:07 +0000733 val->value.qname.name = (xmlChar *)name;
Kasimier T. Buchcikb06b4de2005-02-17 19:00:23 +0000734 if (ns != NULL)
William M. Brack12d37ab2005-02-21 13:54:07 +0000735 val->value.qname.uri = (xmlChar *)ns;
Kasimier T. Buchcikb06b4de2005-02-17 19:00:23 +0000736 return(val);
737}
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +0000738
739/**
Daniel Veillard4255d502002-04-16 15:50:10 +0000740 * xmlSchemaFreeValue:
741 * @value: the value to free
742 *
743 * Cleanup the default XML Schemas type library
744 */
745void
746xmlSchemaFreeValue(xmlSchemaValPtr value) {
747 if (value == NULL)
748 return;
Daniel Veillardc4c21552003-03-29 10:53:38 +0000749 switch (value->type) {
750 case XML_SCHEMAS_STRING:
751 case XML_SCHEMAS_NORMSTRING:
752 case XML_SCHEMAS_TOKEN:
753 case XML_SCHEMAS_LANGUAGE:
754 case XML_SCHEMAS_NMTOKEN:
755 case XML_SCHEMAS_NMTOKENS:
756 case XML_SCHEMAS_NAME:
Daniel Veillardc4c21552003-03-29 10:53:38 +0000757 case XML_SCHEMAS_NCNAME:
758 case XML_SCHEMAS_ID:
759 case XML_SCHEMAS_IDREF:
760 case XML_SCHEMAS_IDREFS:
761 case XML_SCHEMAS_ENTITY:
Kasimier T. Buchcikb06b4de2005-02-17 19:00:23 +0000762 case XML_SCHEMAS_ENTITIES:
Daniel Veillardc4c21552003-03-29 10:53:38 +0000763 case XML_SCHEMAS_ANYURI:
764 if (value->value.str != NULL)
765 xmlFree(value->value.str);
766 break;
Kasimier T. Buchcikb06b4de2005-02-17 19:00:23 +0000767 case XML_SCHEMAS_NOTATION:
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000768 case XML_SCHEMAS_QNAME:
769 if (value->value.qname.uri != NULL)
770 xmlFree(value->value.qname.uri);
771 if (value->value.qname.name != NULL)
772 xmlFree(value->value.qname.name);
773 break;
Daniel Veillard70bcb0e2003-08-08 14:00:28 +0000774 case XML_SCHEMAS_HEXBINARY:
775 if (value->value.hex.str != NULL)
776 xmlFree(value->value.hex.str);
777 break;
Daniel Veillard1ac24d32003-08-27 14:15:15 +0000778 case XML_SCHEMAS_BASE64BINARY:
779 if (value->value.base64.str != NULL)
780 xmlFree(value->value.base64.str);
781 break;
Daniel Veillardc4c21552003-03-29 10:53:38 +0000782 default:
783 break;
784 }
Daniel Veillard4255d502002-04-16 15:50:10 +0000785 xmlFree(value);
786}
787
788/**
789 * xmlSchemaGetPredefinedType:
790 * @name: the type name
791 * @ns: the URI of the namespace usually "http://www.w3.org/2001/XMLSchema"
792 *
793 * Lookup a type in the default XML Schemas type library
794 *
795 * Returns the type if found, NULL otherwise
796 */
797xmlSchemaTypePtr
798xmlSchemaGetPredefinedType(const xmlChar *name, const xmlChar *ns) {
799 if (xmlSchemaTypesInitialized == 0)
800 xmlSchemaInitTypes();
801 if (name == NULL)
802 return(NULL);
803 return((xmlSchemaTypePtr) xmlHashLookup2(xmlSchemaTypesBank, name, ns));
804}
Daniel Veillard070803b2002-05-03 07:29:38 +0000805
Daniel Veillard01fa6152004-06-29 17:04:39 +0000806/**
807 * xmlSchemaGetBuiltInListSimpleTypeItemType:
808 * @type: the built-in simple type.
809 *
Daniel Veillard6927b102004-10-27 17:29:04 +0000810 * Lookup function
811 *
Daniel Veillardc0826a72004-08-10 14:17:33 +0000812 * Returns the item type of @type as defined by the built-in datatype
813 * hierarchy of XML Schema Part 2: Datatypes, or NULL in case of an error.
Daniel Veillard01fa6152004-06-29 17:04:39 +0000814 */
815xmlSchemaTypePtr
816xmlSchemaGetBuiltInListSimpleTypeItemType(xmlSchemaTypePtr type)
817{
Daniel Veillard42595322004-11-08 10:52:06 +0000818 if ((type == NULL) || (type->type != XML_SCHEMA_TYPE_BASIC))
Daniel Veillard01fa6152004-06-29 17:04:39 +0000819 return (NULL);
820 switch (type->builtInType) {
821 case XML_SCHEMAS_NMTOKENS:
822 return (xmlSchemaTypeNmtokenDef );
823 case XML_SCHEMAS_IDREFS:
824 return (xmlSchemaTypeIdrefDef);
825 case XML_SCHEMAS_ENTITIES:
826 return (xmlSchemaTypeEntityDef);
827 default:
828 return (NULL);
829 }
830}
831
Daniel Veillard070803b2002-05-03 07:29:38 +0000832/****************************************************************
833 * *
834 * Convenience macros and functions *
835 * *
836 ****************************************************************/
837
838#define IS_TZO_CHAR(c) \
839 ((c == 0) || (c == 'Z') || (c == '+') || (c == '-'))
840
841#define VALID_YEAR(yr) (yr != 0)
842#define VALID_MONTH(mon) ((mon >= 1) && (mon <= 12))
843/* VALID_DAY should only be used when month is unknown */
844#define VALID_DAY(day) ((day >= 1) && (day <= 31))
845#define VALID_HOUR(hr) ((hr >= 0) && (hr <= 23))
846#define VALID_MIN(min) ((min >= 0) && (min <= 59))
847#define VALID_SEC(sec) ((sec >= 0) && (sec < 60))
848#define VALID_TZO(tzo) ((tzo > -1440) && (tzo < 1440))
849#define IS_LEAP(y) \
850 (((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0))
851
Daniel Veillardebe25d42004-03-25 09:35:49 +0000852static const unsigned int daysInMonth[12] =
Daniel Veillard070803b2002-05-03 07:29:38 +0000853 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
Daniel Veillardebe25d42004-03-25 09:35:49 +0000854static const unsigned int daysInMonthLeap[12] =
Daniel Veillard070803b2002-05-03 07:29:38 +0000855 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
856
Daniel Veillard5a872412002-05-22 06:40:27 +0000857#define MAX_DAYINMONTH(yr,mon) \
858 (IS_LEAP(yr) ? daysInMonthLeap[mon - 1] : daysInMonth[mon - 1])
859
Daniel Veillard070803b2002-05-03 07:29:38 +0000860#define VALID_MDAY(dt) \
861 (IS_LEAP(dt->year) ? \
862 (dt->day <= daysInMonthLeap[dt->mon - 1]) : \
863 (dt->day <= daysInMonth[dt->mon - 1]))
864
865#define VALID_DATE(dt) \
866 (VALID_YEAR(dt->year) && VALID_MONTH(dt->mon) && VALID_MDAY(dt))
867
868#define VALID_TIME(dt) \
869 (VALID_HOUR(dt->hour) && VALID_MIN(dt->min) && \
870 VALID_SEC(dt->sec) && VALID_TZO(dt->tzo))
871
872#define VALID_DATETIME(dt) \
873 (VALID_DATE(dt) && VALID_TIME(dt))
874
875#define SECS_PER_MIN (60)
876#define SECS_PER_HOUR (60 * SECS_PER_MIN)
877#define SECS_PER_DAY (24 * SECS_PER_HOUR)
878
Daniel Veillard5a872412002-05-22 06:40:27 +0000879static const long dayInYearByMonth[12] =
880 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
881static const long dayInLeapYearByMonth[12] =
882 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 };
883
884#define DAY_IN_YEAR(day, month, year) \
885 ((IS_LEAP(year) ? \
886 dayInLeapYearByMonth[month - 1] : \
887 dayInYearByMonth[month - 1]) + day)
888
889#ifdef DEBUG
890#define DEBUG_DATE(dt) \
891 xmlGenericError(xmlGenericErrorContext, \
892 "type=%o %04ld-%02u-%02uT%02u:%02u:%03f", \
893 dt->type,dt->value.date.year,dt->value.date.mon, \
894 dt->value.date.day,dt->value.date.hour,dt->value.date.min, \
895 dt->value.date.sec); \
896 if (dt->value.date.tz_flag) \
897 if (dt->value.date.tzo != 0) \
898 xmlGenericError(xmlGenericErrorContext, \
899 "%+05d\n",dt->value.date.tzo); \
900 else \
901 xmlGenericError(xmlGenericErrorContext, "Z\n"); \
902 else \
903 xmlGenericError(xmlGenericErrorContext,"\n")
904#else
905#define DEBUG_DATE(dt)
906#endif
907
Daniel Veillard070803b2002-05-03 07:29:38 +0000908/**
909 * _xmlSchemaParseGYear:
910 * @dt: pointer to a date structure
911 * @str: pointer to the string to analyze
912 *
913 * Parses a xs:gYear without time zone and fills in the appropriate
914 * field of the @dt structure. @str is updated to point just after the
915 * xs:gYear. It is supposed that @dt->year is big enough to contain
916 * the year.
917 *
918 * Returns 0 or the error code
919 */
920static int
921_xmlSchemaParseGYear (xmlSchemaValDatePtr dt, const xmlChar **str) {
922 const xmlChar *cur = *str, *firstChar;
923 int isneg = 0, digcnt = 0;
924
925 if (((*cur < '0') || (*cur > '9')) &&
926 (*cur != '-') && (*cur != '+'))
927 return -1;
928
929 if (*cur == '-') {
930 isneg = 1;
931 cur++;
932 }
933
934 firstChar = cur;
935
936 while ((*cur >= '0') && (*cur <= '9')) {
937 dt->year = dt->year * 10 + (*cur - '0');
938 cur++;
939 digcnt++;
940 }
941
942 /* year must be at least 4 digits (CCYY); over 4
943 * digits cannot have a leading zero. */
944 if ((digcnt < 4) || ((digcnt > 4) && (*firstChar == '0')))
945 return 1;
946
947 if (isneg)
948 dt->year = - dt->year;
949
950 if (!VALID_YEAR(dt->year))
951 return 2;
952
953 *str = cur;
954 return 0;
955}
956
957/**
958 * PARSE_2_DIGITS:
959 * @num: the integer to fill in
960 * @cur: an #xmlChar *
961 * @invalid: an integer
962 *
963 * Parses a 2-digits integer and updates @num with the value. @cur is
964 * updated to point just after the integer.
965 * In case of error, @invalid is set to %TRUE, values of @num and
966 * @cur are undefined.
967 */
968#define PARSE_2_DIGITS(num, cur, invalid) \
969 if ((cur[0] < '0') || (cur[0] > '9') || \
970 (cur[1] < '0') || (cur[1] > '9')) \
971 invalid = 1; \
972 else \
973 num = (cur[0] - '0') * 10 + (cur[1] - '0'); \
974 cur += 2;
975
976/**
977 * PARSE_FLOAT:
978 * @num: the double to fill in
979 * @cur: an #xmlChar *
980 * @invalid: an integer
981 *
982 * Parses a float and updates @num with the value. @cur is
983 * updated to point just after the float. The float must have a
984 * 2-digits integer part and may or may not have a decimal part.
985 * In case of error, @invalid is set to %TRUE, values of @num and
986 * @cur are undefined.
987 */
988#define PARSE_FLOAT(num, cur, invalid) \
989 PARSE_2_DIGITS(num, cur, invalid); \
990 if (!invalid && (*cur == '.')) { \
991 double mult = 1; \
992 cur++; \
993 if ((*cur < '0') || (*cur > '9')) \
994 invalid = 1; \
995 while ((*cur >= '0') && (*cur <= '9')) { \
996 mult /= 10; \
997 num += (*cur - '0') * mult; \
998 cur++; \
999 } \
1000 }
1001
1002/**
1003 * _xmlSchemaParseGMonth:
1004 * @dt: pointer to a date structure
1005 * @str: pointer to the string to analyze
1006 *
1007 * Parses a xs:gMonth without time zone and fills in the appropriate
1008 * field of the @dt structure. @str is updated to point just after the
1009 * xs:gMonth.
1010 *
1011 * Returns 0 or the error code
1012 */
1013static int
1014_xmlSchemaParseGMonth (xmlSchemaValDatePtr dt, const xmlChar **str) {
1015 const xmlChar *cur = *str;
1016 int ret = 0;
1017
1018 PARSE_2_DIGITS(dt->mon, cur, ret);
1019 if (ret != 0)
1020 return ret;
1021
1022 if (!VALID_MONTH(dt->mon))
1023 return 2;
1024
1025 *str = cur;
1026 return 0;
1027}
1028
1029/**
1030 * _xmlSchemaParseGDay:
1031 * @dt: pointer to a date structure
1032 * @str: pointer to the string to analyze
1033 *
1034 * Parses a xs:gDay without time zone and fills in the appropriate
1035 * field of the @dt structure. @str is updated to point just after the
1036 * xs:gDay.
1037 *
1038 * Returns 0 or the error code
1039 */
1040static int
1041_xmlSchemaParseGDay (xmlSchemaValDatePtr dt, const xmlChar **str) {
1042 const xmlChar *cur = *str;
1043 int ret = 0;
1044
1045 PARSE_2_DIGITS(dt->day, cur, ret);
1046 if (ret != 0)
1047 return ret;
1048
1049 if (!VALID_DAY(dt->day))
1050 return 2;
1051
1052 *str = cur;
1053 return 0;
1054}
1055
1056/**
1057 * _xmlSchemaParseTime:
1058 * @dt: pointer to a date structure
1059 * @str: pointer to the string to analyze
1060 *
1061 * Parses a xs:time without time zone and fills in the appropriate
1062 * fields of the @dt structure. @str is updated to point just after the
1063 * xs:time.
1064 * In case of error, values of @dt fields are undefined.
1065 *
1066 * Returns 0 or the error code
1067 */
1068static int
1069_xmlSchemaParseTime (xmlSchemaValDatePtr dt, const xmlChar **str) {
1070 const xmlChar *cur = *str;
1071 unsigned int hour = 0; /* use temp var in case str is not xs:time */
1072 int ret = 0;
1073
1074 PARSE_2_DIGITS(hour, cur, ret);
1075 if (ret != 0)
1076 return ret;
1077
1078 if (*cur != ':')
1079 return 1;
1080 cur++;
1081
1082 /* the ':' insures this string is xs:time */
1083 dt->hour = hour;
1084
1085 PARSE_2_DIGITS(dt->min, cur, ret);
1086 if (ret != 0)
1087 return ret;
1088
1089 if (*cur != ':')
1090 return 1;
1091 cur++;
1092
1093 PARSE_FLOAT(dt->sec, cur, ret);
1094 if (ret != 0)
1095 return ret;
1096
1097 if (!VALID_TIME(dt))
1098 return 2;
1099
1100 *str = cur;
1101 return 0;
1102}
1103
1104/**
1105 * _xmlSchemaParseTimeZone:
1106 * @dt: pointer to a date structure
1107 * @str: pointer to the string to analyze
1108 *
1109 * Parses a time zone without time zone and fills in the appropriate
1110 * field of the @dt structure. @str is updated to point just after the
1111 * time zone.
1112 *
1113 * Returns 0 or the error code
1114 */
1115static int
1116_xmlSchemaParseTimeZone (xmlSchemaValDatePtr dt, const xmlChar **str) {
1117 const xmlChar *cur = *str;
1118 int ret = 0;
1119
1120 if (str == NULL)
1121 return -1;
1122
1123 switch (*cur) {
1124 case 0:
1125 dt->tz_flag = 0;
1126 dt->tzo = 0;
1127 break;
1128
1129 case 'Z':
1130 dt->tz_flag = 1;
1131 dt->tzo = 0;
1132 cur++;
1133 break;
1134
1135 case '+':
1136 case '-': {
1137 int isneg = 0, tmp = 0;
1138 isneg = (*cur == '-');
1139
1140 cur++;
1141
1142 PARSE_2_DIGITS(tmp, cur, ret);
1143 if (ret != 0)
1144 return ret;
1145 if (!VALID_HOUR(tmp))
1146 return 2;
1147
1148 if (*cur != ':')
1149 return 1;
1150 cur++;
1151
1152 dt->tzo = tmp * 60;
1153
1154 PARSE_2_DIGITS(tmp, cur, ret);
1155 if (ret != 0)
1156 return ret;
1157 if (!VALID_MIN(tmp))
1158 return 2;
1159
1160 dt->tzo += tmp;
1161 if (isneg)
1162 dt->tzo = - dt->tzo;
1163
1164 if (!VALID_TZO(dt->tzo))
1165 return 2;
1166
Daniel Veillard5a872412002-05-22 06:40:27 +00001167 dt->tz_flag = 1;
Daniel Veillard070803b2002-05-03 07:29:38 +00001168 break;
1169 }
1170 default:
1171 return 1;
1172 }
1173
1174 *str = cur;
1175 return 0;
1176}
1177
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001178/**
1179 * _xmlSchemaBase64Decode:
1180 * @ch: a character
1181 *
1182 * Converts a base64 encoded character to its base 64 value.
1183 *
1184 * Returns 0-63 (value), 64 (pad), or -1 (not recognized)
1185 */
1186static int
1187_xmlSchemaBase64Decode (const xmlChar ch) {
1188 if (('A' <= ch) && (ch <= 'Z')) return ch - 'A';
1189 if (('a' <= ch) && (ch <= 'z')) return ch - 'a' + 26;
1190 if (('0' <= ch) && (ch <= '9')) return ch - '0' + 52;
1191 if ('+' == ch) return 62;
1192 if ('/' == ch) return 63;
1193 if ('=' == ch) return 64;
1194 return -1;
1195}
1196
Daniel Veillard070803b2002-05-03 07:29:38 +00001197/****************************************************************
1198 * *
1199 * XML Schema Dates/Times Datatypes Handling *
1200 * *
1201 ****************************************************************/
1202
1203/**
1204 * PARSE_DIGITS:
1205 * @num: the integer to fill in
1206 * @cur: an #xmlChar *
1207 * @num_type: an integer flag
1208 *
1209 * Parses a digits integer and updates @num with the value. @cur is
1210 * updated to point just after the integer.
1211 * In case of error, @num_type is set to -1, values of @num and
1212 * @cur are undefined.
1213 */
1214#define PARSE_DIGITS(num, cur, num_type) \
1215 if ((*cur < '0') || (*cur > '9')) \
1216 num_type = -1; \
1217 else \
1218 while ((*cur >= '0') && (*cur <= '9')) { \
1219 num = num * 10 + (*cur - '0'); \
1220 cur++; \
1221 }
1222
1223/**
1224 * PARSE_NUM:
1225 * @num: the double to fill in
1226 * @cur: an #xmlChar *
1227 * @num_type: an integer flag
1228 *
1229 * Parses a float or integer and updates @num with the value. @cur is
1230 * updated to point just after the number. If the number is a float,
1231 * then it must have an integer part and a decimal part; @num_type will
1232 * be set to 1. If there is no decimal part, @num_type is set to zero.
1233 * In case of error, @num_type is set to -1, values of @num and
1234 * @cur are undefined.
1235 */
1236#define PARSE_NUM(num, cur, num_type) \
1237 num = 0; \
1238 PARSE_DIGITS(num, cur, num_type); \
1239 if (!num_type && (*cur == '.')) { \
1240 double mult = 1; \
1241 cur++; \
1242 if ((*cur < '0') || (*cur > '9')) \
1243 num_type = -1; \
1244 else \
1245 num_type = 1; \
1246 while ((*cur >= '0') && (*cur <= '9')) { \
1247 mult /= 10; \
1248 num += (*cur - '0') * mult; \
1249 cur++; \
1250 } \
1251 }
1252
1253/**
Daniel Veillard5a872412002-05-22 06:40:27 +00001254 * xmlSchemaValidateDates:
Daniel Veillard455cc072003-03-31 10:13:23 +00001255 * @type: the expected type or XML_SCHEMAS_UNKNOWN
Daniel Veillard070803b2002-05-03 07:29:38 +00001256 * @dateTime: string to analyze
1257 * @val: the return computed value
1258 *
1259 * Check that @dateTime conforms to the lexical space of one of the date types.
1260 * if true a value is computed and returned in @val.
1261 *
1262 * Returns 0 if this validates, a positive error code number otherwise
1263 * and -1 in case of internal or API error.
1264 */
1265static int
Daniel Veillard455cc072003-03-31 10:13:23 +00001266xmlSchemaValidateDates (xmlSchemaValType type,
Daniel Veillard118aed72002-09-24 14:13:13 +00001267 const xmlChar *dateTime, xmlSchemaValPtr *val) {
Daniel Veillard070803b2002-05-03 07:29:38 +00001268 xmlSchemaValPtr dt;
1269 int ret;
1270 const xmlChar *cur = dateTime;
1271
1272#define RETURN_TYPE_IF_VALID(t) \
1273 if (IS_TZO_CHAR(*cur)) { \
1274 ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur); \
1275 if (ret == 0) { \
1276 if (*cur != 0) \
1277 goto error; \
1278 dt->type = t; \
Daniel Veillard455cc072003-03-31 10:13:23 +00001279 goto done; \
Daniel Veillard070803b2002-05-03 07:29:38 +00001280 } \
1281 }
1282
1283 if (dateTime == NULL)
1284 return -1;
1285
1286 if ((*cur != '-') && (*cur < '0') && (*cur > '9'))
1287 return 1;
1288
1289 dt = xmlSchemaNewValue(XML_SCHEMAS_UNKNOWN);
1290 if (dt == NULL)
1291 return -1;
1292
1293 if ((cur[0] == '-') && (cur[1] == '-')) {
1294 /*
1295 * It's an incomplete date (xs:gMonthDay, xs:gMonth or
1296 * xs:gDay)
1297 */
1298 cur += 2;
1299
1300 /* is it an xs:gDay? */
1301 if (*cur == '-') {
Daniel Veillard455cc072003-03-31 10:13:23 +00001302 if (type == XML_SCHEMAS_GMONTH)
1303 goto error;
Daniel Veillard070803b2002-05-03 07:29:38 +00001304 ++cur;
1305 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
1306 if (ret != 0)
1307 goto error;
1308
1309 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GDAY);
1310
1311 goto error;
1312 }
1313
1314 /*
1315 * it should be an xs:gMonthDay or xs:gMonth
1316 */
1317 ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
1318 if (ret != 0)
1319 goto error;
1320
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001321 /*
1322 * a '-' char could indicate this type is xs:gMonthDay or
1323 * a negative time zone offset. Check for xs:gMonthDay first.
1324 * Also the first three char's of a negative tzo (-MM:SS) can
1325 * appear to be a valid day; so even if the day portion
1326 * of the xs:gMonthDay verifies, we must insure it was not
1327 * a tzo.
1328 */
1329 if (*cur == '-') {
1330 const xmlChar *rewnd = cur;
1331 cur++;
Daniel Veillard070803b2002-05-03 07:29:38 +00001332
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001333 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
1334 if ((ret == 0) && ((*cur == 0) || (*cur != ':'))) {
1335
1336 /*
1337 * we can use the VALID_MDAY macro to validate the month
1338 * and day because the leap year test will flag year zero
1339 * as a leap year (even though zero is an invalid year).
1340 */
1341 if (VALID_MDAY((&(dt->value.date)))) {
1342
1343 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTHDAY);
1344
1345 goto error;
1346 }
1347 }
1348
1349 /*
1350 * not xs:gMonthDay so rewind and check if just xs:gMonth
1351 * with an optional time zone.
1352 */
1353 cur = rewnd;
1354 }
1355
1356 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTH);
Daniel Veillard070803b2002-05-03 07:29:38 +00001357
1358 goto error;
1359 }
1360
1361 /*
1362 * It's a right-truncated date or an xs:time.
1363 * Try to parse an xs:time then fallback on right-truncated dates.
1364 */
1365 if ((*cur >= '0') && (*cur <= '9')) {
1366 ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
1367 if (ret == 0) {
1368 /* it's an xs:time */
1369 RETURN_TYPE_IF_VALID(XML_SCHEMAS_TIME);
1370 }
1371 }
1372
1373 /* fallback on date parsing */
1374 cur = dateTime;
1375
1376 ret = _xmlSchemaParseGYear(&(dt->value.date), &cur);
1377 if (ret != 0)
1378 goto error;
1379
1380 /* is it an xs:gYear? */
1381 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEAR);
1382
1383 if (*cur != '-')
1384 goto error;
1385 cur++;
1386
1387 ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
1388 if (ret != 0)
1389 goto error;
1390
1391 /* is it an xs:gYearMonth? */
1392 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEARMONTH);
1393
1394 if (*cur != '-')
1395 goto error;
1396 cur++;
1397
1398 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
1399 if ((ret != 0) || !VALID_DATE((&(dt->value.date))))
1400 goto error;
1401
1402 /* is it an xs:date? */
1403 RETURN_TYPE_IF_VALID(XML_SCHEMAS_DATE);
1404
1405 if (*cur != 'T')
1406 goto error;
1407 cur++;
1408
1409 /* it should be an xs:dateTime */
1410 ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
1411 if (ret != 0)
1412 goto error;
1413
1414 ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur);
1415 if ((ret != 0) || (*cur != 0) || !VALID_DATETIME((&(dt->value.date))))
1416 goto error;
1417
Daniel Veillard455cc072003-03-31 10:13:23 +00001418
Daniel Veillard070803b2002-05-03 07:29:38 +00001419 dt->type = XML_SCHEMAS_DATETIME;
1420
Daniel Veillard455cc072003-03-31 10:13:23 +00001421done:
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001422#if 1
1423 if ((type != XML_SCHEMAS_UNKNOWN) && (type != dt->type))
1424 goto error;
1425#else
1426 /*
1427 * insure the parsed type is equal to or less significant (right
1428 * truncated) than the desired type.
1429 */
1430 if ((type != XML_SCHEMAS_UNKNOWN) && (type != dt->type)) {
1431
1432 /* time only matches time */
1433 if ((type == XML_SCHEMAS_TIME) && (dt->type == XML_SCHEMAS_TIME))
1434 goto error;
1435
1436 if ((type == XML_SCHEMAS_DATETIME) &&
1437 ((dt->type != XML_SCHEMAS_DATE) ||
1438 (dt->type != XML_SCHEMAS_GYEARMONTH) ||
1439 (dt->type != XML_SCHEMAS_GYEAR)))
1440 goto error;
1441
1442 if ((type == XML_SCHEMAS_DATE) &&
1443 ((dt->type != XML_SCHEMAS_GYEAR) ||
1444 (dt->type != XML_SCHEMAS_GYEARMONTH)))
1445 goto error;
1446
1447 if ((type == XML_SCHEMAS_GYEARMONTH) && (dt->type != XML_SCHEMAS_GYEAR))
1448 goto error;
1449
1450 if ((type == XML_SCHEMAS_GMONTHDAY) && (dt->type != XML_SCHEMAS_GMONTH))
1451 goto error;
1452 }
Daniel Veillard455cc072003-03-31 10:13:23 +00001453#endif
1454
Daniel Veillard070803b2002-05-03 07:29:38 +00001455 if (val != NULL)
1456 *val = dt;
Daniel Veillard80b19092003-03-28 13:29:53 +00001457 else
1458 xmlSchemaFreeValue(dt);
Daniel Veillard070803b2002-05-03 07:29:38 +00001459
1460 return 0;
1461
1462error:
1463 if (dt != NULL)
1464 xmlSchemaFreeValue(dt);
1465 return 1;
1466}
1467
1468/**
Daniel Veillard5a872412002-05-22 06:40:27 +00001469 * xmlSchemaValidateDuration:
Daniel Veillard070803b2002-05-03 07:29:38 +00001470 * @type: the predefined type
1471 * @duration: string to analyze
1472 * @val: the return computed value
1473 *
1474 * Check that @duration conforms to the lexical space of the duration type.
1475 * if true a value is computed and returned in @val.
1476 *
1477 * Returns 0 if this validates, a positive error code number otherwise
1478 * and -1 in case of internal or API error.
1479 */
1480static int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00001481xmlSchemaValidateDuration (xmlSchemaTypePtr type ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +00001482 const xmlChar *duration, xmlSchemaValPtr *val) {
Daniel Veillard070803b2002-05-03 07:29:38 +00001483 const xmlChar *cur = duration;
1484 xmlSchemaValPtr dur;
1485 int isneg = 0;
1486 unsigned int seq = 0;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001487 double num;
1488 int num_type = 0; /* -1 = invalid, 0 = int, 1 = floating */
1489 const xmlChar desig[] = {'Y', 'M', 'D', 'H', 'M', 'S'};
1490 const double multi[] = { 0.0, 0.0, 86400.0, 3600.0, 60.0, 1.0, 0.0};
Daniel Veillard070803b2002-05-03 07:29:38 +00001491
1492 if (duration == NULL)
1493 return -1;
1494
1495 if (*cur == '-') {
1496 isneg = 1;
1497 cur++;
1498 }
1499
1500 /* duration must start with 'P' (after sign) */
1501 if (*cur++ != 'P')
1502 return 1;
1503
Daniel Veillard80b19092003-03-28 13:29:53 +00001504 if (*cur == 0)
1505 return 1;
1506
Daniel Veillard070803b2002-05-03 07:29:38 +00001507 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
1508 if (dur == NULL)
1509 return -1;
1510
1511 while (*cur != 0) {
Daniel Veillard070803b2002-05-03 07:29:38 +00001512
1513 /* input string should be empty or invalid date/time item */
1514 if (seq >= sizeof(desig))
1515 goto error;
1516
1517 /* T designator must be present for time items */
1518 if (*cur == 'T') {
1519 if (seq <= 3) {
1520 seq = 3;
1521 cur++;
1522 } else
1523 return 1;
1524 } else if (seq == 3)
1525 goto error;
1526
1527 /* parse the number portion of the item */
1528 PARSE_NUM(num, cur, num_type);
1529
1530 if ((num_type == -1) || (*cur == 0))
1531 goto error;
1532
1533 /* update duration based on item type */
1534 while (seq < sizeof(desig)) {
1535 if (*cur == desig[seq]) {
1536
1537 /* verify numeric type; only seconds can be float */
1538 if ((num_type != 0) && (seq < (sizeof(desig)-1)))
1539 goto error;
1540
1541 switch (seq) {
1542 case 0:
1543 dur->value.dur.mon = (long)num * 12;
1544 break;
1545 case 1:
1546 dur->value.dur.mon += (long)num;
1547 break;
1548 default:
1549 /* convert to seconds using multiplier */
1550 dur->value.dur.sec += num * multi[seq];
1551 seq++;
1552 break;
1553 }
1554
1555 break; /* exit loop */
1556 }
1557 /* no date designators found? */
1558 if (++seq == 3)
1559 goto error;
1560 }
1561 cur++;
1562 }
1563
1564 if (isneg) {
1565 dur->value.dur.mon = -dur->value.dur.mon;
1566 dur->value.dur.day = -dur->value.dur.day;
1567 dur->value.dur.sec = -dur->value.dur.sec;
1568 }
1569
1570 if (val != NULL)
1571 *val = dur;
Daniel Veillard80b19092003-03-28 13:29:53 +00001572 else
1573 xmlSchemaFreeValue(dur);
Daniel Veillard070803b2002-05-03 07:29:38 +00001574
1575 return 0;
1576
1577error:
1578 if (dur != NULL)
1579 xmlSchemaFreeValue(dur);
1580 return 1;
1581}
1582
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001583/**
1584 * xmlSchemaStrip:
1585 * @value: a value
1586 *
1587 * Removes the leading and ending spaces of a string
1588 *
1589 * Returns the new string or NULL if no change was required.
1590 */
1591static xmlChar *
1592xmlSchemaStrip(const xmlChar *value) {
1593 const xmlChar *start = value, *end, *f;
1594
1595 if (value == NULL) return(NULL);
William M. Brack76e95df2003-10-18 16:20:14 +00001596 while ((*start != 0) && (IS_BLANK_CH(*start))) start++;
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001597 end = start;
1598 while (*end != 0) end++;
1599 f = end;
1600 end--;
William M. Brack76e95df2003-10-18 16:20:14 +00001601 while ((end > start) && (IS_BLANK_CH(*end))) end--;
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001602 end++;
1603 if ((start == value) && (f == end)) return(NULL);
1604 return(xmlStrndup(start, end - start));
1605}
Daniel Veillard96a4b252003-02-06 08:22:32 +00001606
1607/**
Kasimier T. Buchcik91feaf82004-11-12 14:04:58 +00001608 * xmlSchemaWhiteSpaceReplace:
1609 * @value: a value
1610 *
1611 * Replaces 0xd, 0x9 and 0xa with a space.
1612 *
1613 * Returns the new string or NULL if no change was required.
1614 */
1615xmlChar *
1616xmlSchemaWhiteSpaceReplace(const xmlChar *value) {
1617 const xmlChar *cur = value;
1618 xmlChar *ret = NULL, *mcur;
1619
1620 if (value == NULL)
1621 return(NULL);
1622
1623 while ((*cur != 0) &&
1624 (((*cur) != 0xd) && ((*cur) != 0x9) && ((*cur) != 0xa))) {
1625 cur++;
1626 }
1627 if (*cur == 0)
1628 return (NULL);
1629 ret = xmlStrdup(value);
1630 /* TODO FIXME: I guess gcc will bark at this. */
1631 mcur = (xmlChar *) (ret + (cur - value));
1632 do {
1633 if ( ((*mcur) == 0xd) || ((*mcur) == 0x9) || ((*mcur) == 0xa) )
1634 *mcur = ' ';
1635 mcur++;
1636 } while (*mcur != 0);
1637 return(ret);
1638}
1639
1640/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001641 * xmlSchemaCollapseString:
1642 * @value: a value
1643 *
1644 * Removes and normalize white spaces in the string
1645 *
1646 * Returns the new string or NULL if no change was required.
1647 */
Daniel Veillard01fa6152004-06-29 17:04:39 +00001648xmlChar *
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001649xmlSchemaCollapseString(const xmlChar *value) {
1650 const xmlChar *start = value, *end, *f;
1651 xmlChar *g;
1652 int col = 0;
1653
1654 if (value == NULL) return(NULL);
William M. Brack76e95df2003-10-18 16:20:14 +00001655 while ((*start != 0) && (IS_BLANK_CH(*start))) start++;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001656 end = start;
1657 while (*end != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00001658 if ((*end == ' ') && (IS_BLANK_CH(end[1]))) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001659 col = end - start;
1660 break;
1661 } else if ((*end == 0xa) || (*end == 0x9) || (*end == 0xd)) {
1662 col = end - start;
1663 break;
1664 }
1665 end++;
1666 }
1667 if (col == 0) {
1668 f = end;
1669 end--;
William M. Brack76e95df2003-10-18 16:20:14 +00001670 while ((end > start) && (IS_BLANK_CH(*end))) end--;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001671 end++;
1672 if ((start == value) && (f == end)) return(NULL);
1673 return(xmlStrndup(start, end - start));
1674 }
1675 start = xmlStrdup(start);
1676 if (start == NULL) return(NULL);
1677 g = (xmlChar *) (start + col);
1678 end = g;
1679 while (*end != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00001680 if (IS_BLANK_CH(*end)) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001681 end++;
William M. Brack76e95df2003-10-18 16:20:14 +00001682 while (IS_BLANK_CH(*end)) end++;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001683 if (*end != 0)
1684 *g++ = ' ';
1685 } else
1686 *g++ = *end++;
1687 }
1688 *g = 0;
1689 return((xmlChar *) start);
1690}
1691
1692/**
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001693 * xmlSchemaValAtomicListNode:
1694 * @type: the predefined atomic type for a token in the list
1695 * @value: the list value to check
1696 * @ret: the return computed value
1697 * @node: the node containing the value
1698 *
1699 * Check that a value conforms to the lexical space of the predefined
1700 * list type. if true a value is computed and returned in @ret.
1701 *
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001702 * Returns the number of items if this validates, a negative error code
1703 * number otherwise
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001704 */
1705static int
1706xmlSchemaValAtomicListNode(xmlSchemaTypePtr type, const xmlChar *value,
1707 xmlSchemaValPtr *ret, xmlNodePtr node) {
1708 xmlChar *val, *cur, *endval;
1709 int nb_values = 0;
Daniel Veillard580ced82003-03-21 21:22:48 +00001710 int tmp = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001711
1712 if (value == NULL) {
1713 return(-1);
1714 }
1715 val = xmlStrdup(value);
1716 if (val == NULL) {
1717 return(-1);
1718 }
Daniel Veillard6fc5db02005-01-16 00:05:58 +00001719 if (ret != NULL) {
1720 *ret = NULL;
1721 }
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001722 cur = val;
1723 /*
1724 * Split the list
1725 */
William M. Brack76e95df2003-10-18 16:20:14 +00001726 while (IS_BLANK_CH(*cur)) *cur++ = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001727 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00001728 if (IS_BLANK_CH(*cur)) {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001729 *cur = 0;
1730 cur++;
William M. Brack76e95df2003-10-18 16:20:14 +00001731 while (IS_BLANK_CH(*cur)) *cur++ = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001732 } else {
1733 nb_values++;
1734 cur++;
William M. Brack76e95df2003-10-18 16:20:14 +00001735 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001736 }
1737 }
1738 if (nb_values == 0) {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001739 xmlFree(val);
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001740 return(nb_values);
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001741 }
1742 endval = cur;
1743 cur = val;
1744 while ((*cur == 0) && (cur != endval)) cur++;
1745 while (cur != endval) {
1746 tmp = xmlSchemaValPredefTypeNode(type, cur, NULL, node);
1747 if (tmp != 0)
1748 break;
1749 while (*cur != 0) cur++;
1750 while ((*cur == 0) && (cur != endval)) cur++;
1751 }
Daniel Veillard6fc5db02005-01-16 00:05:58 +00001752 /* TODO what return value ? c.f. bug #158628
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001753 if (ret != NULL) {
1754 TODO
Daniel Veillard6fc5db02005-01-16 00:05:58 +00001755 } */
1756 xmlFree(val);
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001757 if (tmp == 0)
1758 return(nb_values);
1759 return(-1);
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001760}
1761
1762/**
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001763 * xmlSchemaParseUInt:
1764 * @str: pointer to the string R/W
1765 * @llo: pointer to the low result
1766 * @lmi: pointer to the mid result
1767 * @lhi: pointer to the high result
1768 *
1769 * Parse an unsigned long into 3 fields.
1770 *
1771 * Returns the number of chars parsed or -1 if overflow of the capacity
1772 */
1773static int
1774xmlSchemaParseUInt(const xmlChar **str, unsigned long *llo,
1775 unsigned long *lmi, unsigned long *lhi) {
1776 unsigned long lo = 0, mi = 0, hi = 0;
1777 const xmlChar *tmp, *cur = *str;
1778 int ret = 0, i = 0;
1779
1780 while (*cur == '0') {
1781 ret++;
1782 cur++;
1783 }
1784 tmp = cur;
1785 while ((*tmp != 0) && (*tmp >= '0') && (*tmp <= '9')) {
1786 i++;tmp++;ret++;
1787 }
1788 if (i > 24) {
1789 *str = tmp;
1790 return(-1);
1791 }
1792 while (i > 16) {
1793 hi = hi * 10 + (*cur++ - '0');
1794 i--;
1795 }
1796 while (i > 8) {
1797 mi = mi * 10 + (*cur++ - '0');
1798 i--;
1799 }
1800 while (i > 0) {
1801 lo = lo * 10 + (*cur++ - '0');
1802 i--;
1803 }
1804
1805 *str = cur;
1806 *llo = lo;
1807 *lmi = mi;
1808 *lhi = hi;
1809 return(ret);
1810}
1811
1812/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001813 * xmlSchemaValAtomicType:
1814 * @type: the predefined type
1815 * @value: the value to check
1816 * @val: the return computed value
1817 * @node: the node containing the value
1818 * flags: flags to control the vlidation
1819 *
1820 * Check that a value conforms to the lexical space of the atomic type.
1821 * if true a value is computed and returned in @val.
Daniel Veillard01fa6152004-06-29 17:04:39 +00001822 * This checks the value space for list types as well (IDREFS, NMTOKENS).
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001823 *
1824 * Returns 0 if this validates, a positive error code number otherwise
1825 * and -1 in case of internal or API error.
1826 */
1827static int
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001828xmlSchemaValAtomicType(xmlSchemaTypePtr type, const xmlChar * value,
1829 xmlSchemaValPtr * val, xmlNodePtr node, int flags)
1830{
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001831 xmlSchemaValPtr v;
1832 xmlChar *norm = NULL;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001833 int ret = 0;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001834
1835 if (xmlSchemaTypesInitialized == 0)
Daniel Veillard01fa6152004-06-29 17:04:39 +00001836 xmlSchemaInitTypes();
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001837 if (type == NULL)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001838 return (-1);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001839
Daniel Veillardeebd6332004-08-26 10:30:44 +00001840 /*
1841 * validating a non existant text node is similar to validating
1842 * an empty one.
1843 */
1844 if (value == NULL)
1845 value = BAD_CAST "";
1846
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001847 if (val != NULL)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001848 *val = NULL;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001849 if ((flags == 0) && (value != NULL)) {
Kasimier T. Buchcik91feaf82004-11-12 14:04:58 +00001850
Daniel Veillard01fa6152004-06-29 17:04:39 +00001851 if ((type->builtInType != XML_SCHEMAS_STRING) &&
Kasimier T. Buchcik91feaf82004-11-12 14:04:58 +00001852 (type->builtInType != XML_SCHEMAS_ANYTYPE) &&
1853 (type->builtInType != XML_SCHEMAS_ANYSIMPLETYPE)) {
1854 if (type->builtInType == XML_SCHEMAS_NORMSTRING)
1855 norm = xmlSchemaWhiteSpaceReplace(value);
1856 else
1857 norm = xmlSchemaCollapseString(value);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001858 if (norm != NULL)
1859 value = norm;
1860 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001861 }
1862
Daniel Veillard01fa6152004-06-29 17:04:39 +00001863 switch (type->builtInType) {
William M. Brack2f2a6632004-08-20 23:09:47 +00001864 case XML_SCHEMAS_UNKNOWN:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001865 goto error;
William M. Brack2f2a6632004-08-20 23:09:47 +00001866 case XML_SCHEMAS_ANYTYPE:
1867 case XML_SCHEMAS_ANYSIMPLETYPE:
1868 goto return0;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001869 case XML_SCHEMAS_STRING:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001870 goto return0;
Daniel Veillard1516d5b2004-01-22 07:27:45 +00001871 case XML_SCHEMAS_NORMSTRING:{
1872 const xmlChar *cur = value;
1873
1874 while (*cur != 0) {
1875 if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) {
1876 goto return1;
1877 } else {
1878 cur++;
1879 }
1880 }
1881 if (val != NULL) {
1882 v = xmlSchemaNewValue(XML_SCHEMAS_NORMSTRING);
1883 if (v != NULL) {
1884 v->value.str = xmlStrdup(value);
1885 *val = v;
1886 } else {
1887 goto error;
1888 }
1889 }
1890 goto return0;
1891 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001892 case XML_SCHEMAS_DECIMAL:{
1893 const xmlChar *cur = value, *tmp;
1894 unsigned int frac = 0, len, neg = 0;
1895 unsigned long base = 0;
1896
1897 if (cur == NULL)
1898 goto return1;
1899 if (*cur == '+')
1900 cur++;
1901 else if (*cur == '-') {
1902 neg = 1;
1903 cur++;
1904 }
1905 tmp = cur;
1906 while ((*cur >= '0') && (*cur <= '9')) {
1907 base = base * 10 + (*cur - '0');
1908 cur++;
1909 }
1910 len = cur - tmp;
1911 if (*cur == '.') {
1912 cur++;
1913 tmp = cur;
1914 while ((*cur >= '0') && (*cur <= '9')) {
1915 base = base * 10 + (*cur - '0');
1916 cur++;
1917 }
1918 frac = cur - tmp;
1919 }
1920 if (*cur != 0)
1921 goto return1;
1922 if (val != NULL) {
1923 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
1924 if (v != NULL) {
1925 v->value.decimal.lo = base;
1926 v->value.decimal.sign = neg;
1927 v->value.decimal.frac = frac;
1928 v->value.decimal.total = frac + len;
1929 *val = v;
1930 }
1931 }
1932 goto return0;
1933 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001934 case XML_SCHEMAS_TIME:
1935 case XML_SCHEMAS_GDAY:
1936 case XML_SCHEMAS_GMONTH:
1937 case XML_SCHEMAS_GMONTHDAY:
1938 case XML_SCHEMAS_GYEAR:
1939 case XML_SCHEMAS_GYEARMONTH:
1940 case XML_SCHEMAS_DATE:
1941 case XML_SCHEMAS_DATETIME:
Daniel Veillard01fa6152004-06-29 17:04:39 +00001942 ret = xmlSchemaValidateDates(type->builtInType, value, val);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001943 break;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001944 case XML_SCHEMAS_DURATION:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001945 ret = xmlSchemaValidateDuration(type, value, val);
1946 break;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001947 case XML_SCHEMAS_FLOAT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001948 case XML_SCHEMAS_DOUBLE:{
1949 const xmlChar *cur = value;
1950 int neg = 0;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001951
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001952 if (cur == NULL)
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00001953 goto return1;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001954 if ((cur[0] == 'N') && (cur[1] == 'a') && (cur[2] == 'N')) {
1955 cur += 3;
1956 if (*cur != 0)
1957 goto return1;
1958 if (val != NULL) {
1959 if (type == xmlSchemaTypeFloatDef) {
1960 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1961 if (v != NULL) {
1962 v->value.f = (float) xmlXPathNAN;
1963 } else {
1964 xmlSchemaFreeValue(v);
1965 goto error;
1966 }
1967 } else {
1968 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1969 if (v != NULL) {
1970 v->value.d = xmlXPathNAN;
1971 } else {
1972 xmlSchemaFreeValue(v);
1973 goto error;
1974 }
1975 }
1976 *val = v;
1977 }
1978 goto return0;
1979 }
1980 if (*cur == '-') {
1981 neg = 1;
1982 cur++;
1983 }
1984 if ((cur[0] == 'I') && (cur[1] == 'N') && (cur[2] == 'F')) {
1985 cur += 3;
1986 if (*cur != 0)
1987 goto return1;
1988 if (val != NULL) {
1989 if (type == xmlSchemaTypeFloatDef) {
1990 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1991 if (v != NULL) {
1992 if (neg)
1993 v->value.f = (float) xmlXPathNINF;
1994 else
1995 v->value.f = (float) xmlXPathPINF;
1996 } else {
1997 xmlSchemaFreeValue(v);
1998 goto error;
1999 }
2000 } else {
2001 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
2002 if (v != NULL) {
2003 if (neg)
2004 v->value.d = xmlXPathNINF;
2005 else
2006 v->value.d = xmlXPathPINF;
2007 } else {
2008 xmlSchemaFreeValue(v);
2009 goto error;
2010 }
2011 }
2012 *val = v;
2013 }
2014 goto return0;
2015 }
2016 if ((neg == 0) && (*cur == '+'))
2017 cur++;
2018 if ((cur[0] == 0) || (cur[0] == '+') || (cur[0] == '-'))
2019 goto return1;
2020 while ((*cur >= '0') && (*cur <= '9')) {
2021 cur++;
2022 }
2023 if (*cur == '.') {
2024 cur++;
2025 while ((*cur >= '0') && (*cur <= '9'))
2026 cur++;
2027 }
2028 if ((*cur == 'e') || (*cur == 'E')) {
2029 cur++;
2030 if ((*cur == '-') || (*cur == '+'))
2031 cur++;
2032 while ((*cur >= '0') && (*cur <= '9'))
2033 cur++;
2034 }
2035 if (*cur != 0)
2036 goto return1;
2037 if (val != NULL) {
2038 if (type == xmlSchemaTypeFloatDef) {
2039 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
2040 if (v != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002041 if (sscanf((const char *) value, "%f",
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002042 &(v->value.f)) == 1) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00002043 *val = v;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002044 } else {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002045 xmlSchemaFreeValue(v);
2046 goto return1;
2047 }
2048 } else {
2049 goto error;
2050 }
2051 } else {
2052 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
2053 if (v != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002054 if (sscanf((const char *) value, "%lf",
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002055 &(v->value.d)) == 1) {
2056 *val = v;
2057 } else {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002058 xmlSchemaFreeValue(v);
2059 goto return1;
2060 }
2061 } else {
2062 goto error;
2063 }
2064 }
2065 }
2066 goto return0;
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00002067 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002068 case XML_SCHEMAS_BOOLEAN:{
2069 const xmlChar *cur = value;
2070
2071 if ((cur[0] == '0') && (cur[1] == 0))
2072 ret = 0;
2073 else if ((cur[0] == '1') && (cur[1] == 0))
2074 ret = 1;
2075 else if ((cur[0] == 't') && (cur[1] == 'r')
2076 && (cur[2] == 'u') && (cur[3] == 'e')
2077 && (cur[4] == 0))
2078 ret = 1;
2079 else if ((cur[0] == 'f') && (cur[1] == 'a')
2080 && (cur[2] == 'l') && (cur[3] == 's')
2081 && (cur[4] == 'e') && (cur[5] == 0))
2082 ret = 0;
2083 else
2084 goto return1;
2085 if (val != NULL) {
2086 v = xmlSchemaNewValue(XML_SCHEMAS_BOOLEAN);
2087 if (v != NULL) {
2088 v->value.b = ret;
2089 *val = v;
2090 } else {
2091 goto error;
2092 }
2093 }
2094 goto return0;
2095 }
2096 case XML_SCHEMAS_TOKEN:{
2097 const xmlChar *cur = value;
2098
William M. Brack76e95df2003-10-18 16:20:14 +00002099 if (IS_BLANK_CH(*cur))
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002100 goto return1;
2101
2102 while (*cur != 0) {
2103 if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) {
2104 goto return1;
2105 } else if (*cur == ' ') {
2106 cur++;
2107 if (*cur == 0)
2108 goto return1;
2109 if (*cur == ' ')
2110 goto return1;
2111 } else {
2112 cur++;
2113 }
2114 }
2115 if (val != NULL) {
2116 v = xmlSchemaNewValue(XML_SCHEMAS_TOKEN);
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 case XML_SCHEMAS_LANGUAGE:
2127 if (xmlCheckLanguageID(value) == 1) {
2128 if (val != NULL) {
2129 v = xmlSchemaNewValue(XML_SCHEMAS_LANGUAGE);
2130 if (v != NULL) {
2131 v->value.str = xmlStrdup(value);
2132 *val = v;
2133 } else {
2134 goto error;
2135 }
2136 }
2137 goto return0;
2138 }
2139 goto return1;
2140 case XML_SCHEMAS_NMTOKEN:
2141 if (xmlValidateNMToken(value, 1) == 0) {
2142 if (val != NULL) {
2143 v = xmlSchemaNewValue(XML_SCHEMAS_NMTOKEN);
2144 if (v != NULL) {
2145 v->value.str = xmlStrdup(value);
2146 *val = v;
2147 } else {
2148 goto error;
2149 }
2150 }
2151 goto return0;
2152 }
2153 goto return1;
2154 case XML_SCHEMAS_NMTOKENS:
2155 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeNmtokenDef,
2156 value, val, node);
2157 if (ret > 0)
2158 ret = 0;
2159 else
2160 ret = 1;
2161 goto done;
2162 case XML_SCHEMAS_NAME:
2163 ret = xmlValidateName(value, 1);
Daniel Veillarddf292f72005-01-16 19:00:15 +00002164 if ((ret == 0) && (val != NULL) && (value != NULL)) {
2165 v = xmlSchemaNewValue(XML_SCHEMAS_NAME);
2166 if (v != NULL) {
2167 const xmlChar *start = value, *end;
2168 while (IS_BLANK_CH(*start)) start++;
2169 end = start;
2170 while ((*end != 0) && (!IS_BLANK_CH(*end))) end++;
2171 v->value.str = xmlStrndup(start, end - start);
2172 *val = v;
2173 } else {
2174 goto error;
2175 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002176 }
2177 goto done;
2178 case XML_SCHEMAS_QNAME:{
2179 xmlChar *uri = NULL;
2180 xmlChar *local = NULL;
2181
2182 ret = xmlValidateQName(value, 1);
2183 if ((ret == 0) && (node != NULL)) {
2184 xmlChar *prefix;
2185
2186 local = xmlSplitQName2(value, &prefix);
2187 if (prefix != NULL) {
2188 xmlNsPtr ns;
2189
2190 ns = xmlSearchNs(node->doc, node, prefix);
2191 if (ns == NULL)
2192 ret = 1;
2193 else if (val != NULL)
2194 uri = xmlStrdup(ns->href);
2195 }
2196 if ((local != NULL) && ((val == NULL) || (ret != 0)))
2197 xmlFree(local);
2198 if (prefix != NULL)
2199 xmlFree(prefix);
2200 }
2201 if ((ret == 0) && (val != NULL)) {
2202 v = xmlSchemaNewValue(XML_SCHEMAS_QNAME);
2203 if (v != NULL) {
2204 if (local != NULL)
2205 v->value.qname.name = local;
2206 else
2207 v->value.qname.name = xmlStrdup(value);
2208 if (uri != NULL)
2209 v->value.qname.uri = uri;
2210
2211 *val = v;
2212 } else {
2213 if (local != NULL)
2214 xmlFree(local);
2215 if (uri != NULL)
2216 xmlFree(uri);
2217 goto error;
2218 }
2219 }
2220 goto done;
2221 }
2222 case XML_SCHEMAS_NCNAME:
2223 ret = xmlValidateNCName(value, 1);
2224 if ((ret == 0) && (val != NULL)) {
2225 v = xmlSchemaNewValue(XML_SCHEMAS_NCNAME);
2226 if (v != NULL) {
2227 v->value.str = xmlStrdup(value);
2228 *val = v;
2229 } else {
2230 goto error;
2231 }
2232 }
2233 goto done;
2234 case XML_SCHEMAS_ID:
2235 ret = xmlValidateNCName(value, 1);
2236 if ((ret == 0) && (val != NULL)) {
2237 v = xmlSchemaNewValue(XML_SCHEMAS_ID);
2238 if (v != NULL) {
2239 v->value.str = xmlStrdup(value);
2240 *val = v;
2241 } else {
2242 goto error;
2243 }
2244 }
2245 if ((ret == 0) && (node != NULL) &&
2246 (node->type == XML_ATTRIBUTE_NODE)) {
2247 xmlAttrPtr attr = (xmlAttrPtr) node;
2248
2249 /*
2250 * NOTE: the IDness might have already be declared in the DTD
2251 */
2252 if (attr->atype != XML_ATTRIBUTE_ID) {
2253 xmlIDPtr res;
2254 xmlChar *strip;
2255
2256 strip = xmlSchemaStrip(value);
2257 if (strip != NULL) {
2258 res = xmlAddID(NULL, node->doc, strip, attr);
2259 xmlFree(strip);
2260 } else
2261 res = xmlAddID(NULL, node->doc, value, attr);
2262 if (res == NULL) {
2263 ret = 2;
2264 } else {
2265 attr->atype = XML_ATTRIBUTE_ID;
2266 }
2267 }
2268 }
2269 goto done;
2270 case XML_SCHEMAS_IDREF:
2271 ret = xmlValidateNCName(value, 1);
2272 if ((ret == 0) && (val != NULL)) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00002273 v = xmlSchemaNewValue(XML_SCHEMAS_IDREF);
2274 if (v == NULL)
2275 goto error;
2276 v->value.str = xmlStrdup(value);
2277 *val = v;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002278 }
2279 if ((ret == 0) && (node != NULL) &&
2280 (node->type == XML_ATTRIBUTE_NODE)) {
2281 xmlAttrPtr attr = (xmlAttrPtr) node;
2282 xmlChar *strip;
2283
2284 strip = xmlSchemaStrip(value);
2285 if (strip != NULL) {
2286 xmlAddRef(NULL, node->doc, strip, attr);
2287 xmlFree(strip);
2288 } else
2289 xmlAddRef(NULL, node->doc, value, attr);
2290 attr->atype = XML_ATTRIBUTE_IDREF;
2291 }
2292 goto done;
2293 case XML_SCHEMAS_IDREFS:
2294 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeIdrefDef,
2295 value, val, node);
2296 if (ret < 0)
2297 ret = 2;
2298 else
2299 ret = 0;
2300 if ((ret == 0) && (node != NULL) &&
2301 (node->type == XML_ATTRIBUTE_NODE)) {
2302 xmlAttrPtr attr = (xmlAttrPtr) node;
2303
2304 attr->atype = XML_ATTRIBUTE_IDREFS;
2305 }
2306 goto done;
2307 case XML_SCHEMAS_ENTITY:{
2308 xmlChar *strip;
2309
2310 ret = xmlValidateNCName(value, 1);
2311 if ((node == NULL) || (node->doc == NULL))
2312 ret = 3;
2313 if (ret == 0) {
2314 xmlEntityPtr ent;
2315
2316 strip = xmlSchemaStrip(value);
2317 if (strip != NULL) {
2318 ent = xmlGetDocEntity(node->doc, strip);
2319 xmlFree(strip);
2320 } else {
2321 ent = xmlGetDocEntity(node->doc, value);
2322 }
2323 if ((ent == NULL) ||
2324 (ent->etype !=
2325 XML_EXTERNAL_GENERAL_UNPARSED_ENTITY))
2326 ret = 4;
2327 }
2328 if ((ret == 0) && (val != NULL)) {
2329 TODO;
2330 }
2331 if ((ret == 0) && (node != NULL) &&
2332 (node->type == XML_ATTRIBUTE_NODE)) {
2333 xmlAttrPtr attr = (xmlAttrPtr) node;
2334
2335 attr->atype = XML_ATTRIBUTE_ENTITY;
2336 }
2337 goto done;
2338 }
2339 case XML_SCHEMAS_ENTITIES:
2340 if ((node == NULL) || (node->doc == NULL))
2341 goto return3;
2342 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeEntityDef,
2343 value, val, node);
2344 if (ret <= 0)
2345 ret = 1;
2346 else
2347 ret = 0;
2348 if ((ret == 0) && (node != NULL) &&
2349 (node->type == XML_ATTRIBUTE_NODE)) {
2350 xmlAttrPtr attr = (xmlAttrPtr) node;
2351
2352 attr->atype = XML_ATTRIBUTE_ENTITIES;
2353 }
2354 goto done;
2355 case XML_SCHEMAS_NOTATION:{
2356 xmlChar *uri = NULL;
2357 xmlChar *local = NULL;
2358
2359 ret = xmlValidateQName(value, 1);
2360 if ((ret == 0) && (node != NULL)) {
2361 xmlChar *prefix;
2362
2363 local = xmlSplitQName2(value, &prefix);
2364 if (prefix != NULL) {
2365 xmlNsPtr ns;
2366
2367 ns = xmlSearchNs(node->doc, node, prefix);
2368 if (ns == NULL)
2369 ret = 1;
2370 else if (val != NULL)
2371 uri = xmlStrdup(ns->href);
2372 }
2373 if ((local != NULL) && ((val == NULL) || (ret != 0)))
2374 xmlFree(local);
2375 if (prefix != NULL)
2376 xmlFree(prefix);
2377 }
2378 if ((node == NULL) || (node->doc == NULL))
2379 ret = 3;
2380 if (ret == 0) {
2381 ret = xmlValidateNotationUse(NULL, node->doc, value);
2382 if (ret == 1)
2383 ret = 0;
2384 else
2385 ret = 1;
2386 }
2387 if ((ret == 0) && (val != NULL)) {
2388 v = xmlSchemaNewValue(XML_SCHEMAS_NOTATION);
2389 if (v != NULL) {
2390 if (local != NULL)
2391 v->value.qname.name = local;
2392 else
2393 v->value.qname.name = xmlStrdup(value);
2394 if (uri != NULL)
2395 v->value.qname.uri = uri;
2396
2397 *val = v;
2398 } else {
2399 if (local != NULL)
2400 xmlFree(local);
2401 if (uri != NULL)
2402 xmlFree(uri);
2403 goto error;
2404 }
2405 }
2406 goto done;
2407 }
2408 case XML_SCHEMAS_ANYURI:{
Daniel Veillard11c466a2004-03-14 12:20:15 +00002409 if (*value != 0) {
2410 xmlURIPtr uri = xmlParseURI((const char *) value);
2411 if (uri == NULL)
2412 goto return1;
2413 xmlFreeURI(uri);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002414 }
Daniel Veillard11c466a2004-03-14 12:20:15 +00002415
2416 if (val != NULL) {
2417 v = xmlSchemaNewValue(XML_SCHEMAS_ANYURI);
2418 if (v == NULL)
2419 goto error;
2420 v->value.str = xmlStrdup(value);
2421 *val = v;
2422 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002423 goto return0;
2424 }
2425 case XML_SCHEMAS_HEXBINARY:{
2426 const xmlChar *cur = value;
2427 xmlChar *base;
2428 int total, i = 0;
2429
Daniel Veillardf34a20e2004-08-31 08:42:17 +00002430 if (cur == NULL)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002431 goto return1;
2432
2433 while (((*cur >= '0') && (*cur <= '9')) ||
2434 ((*cur >= 'A') && (*cur <= 'F')) ||
2435 ((*cur >= 'a') && (*cur <= 'f'))) {
2436 i++;
2437 cur++;
2438 }
2439
2440 if (*cur != 0)
2441 goto return1;
2442 if ((i % 2) != 0)
2443 goto return1;
2444
2445 if (val != NULL) {
2446
2447 v = xmlSchemaNewValue(XML_SCHEMAS_HEXBINARY);
2448 if (v == NULL)
2449 goto error;
2450
2451 cur = xmlStrdup(value);
2452 if (cur == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002453 xmlSchemaTypeErrMemory(node, "allocating hexbin data");
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002454 xmlFree(v);
2455 goto return1;
2456 }
2457
2458 total = i / 2; /* number of octets */
2459
2460 base = (xmlChar *) cur;
2461 while (i-- > 0) {
2462 if (*base >= 'a')
2463 *base = *base - ('a' - 'A');
2464 base++;
2465 }
2466
2467 v->value.hex.str = (xmlChar *) cur;
2468 v->value.hex.total = total;
2469 *val = v;
2470 }
2471 goto return0;
2472 }
2473 case XML_SCHEMAS_BASE64BINARY:{
2474 /* ISSUE:
2475 *
2476 * Ignore all stray characters? (yes, currently)
2477 * Worry about long lines? (no, currently)
2478 *
2479 * rfc2045.txt:
2480 *
2481 * "The encoded output stream must be represented in lines of
2482 * no more than 76 characters each. All line breaks or other
2483 * characters not found in Table 1 must be ignored by decoding
2484 * software. In base64 data, characters other than those in
2485 * Table 1, line breaks, and other white space probably
2486 * indicate a transmission error, about which a warning
2487 * message or even a message rejection might be appropriate
2488 * under some circumstances." */
2489 const xmlChar *cur = value;
2490 xmlChar *base;
2491 int total, i = 0, pad = 0;
2492
2493 if (cur == NULL)
2494 goto return1;
2495
2496 for (; *cur; ++cur) {
2497 int decc;
2498
2499 decc = _xmlSchemaBase64Decode(*cur);
2500 if (decc < 0) ;
2501 else if (decc < 64)
2502 i++;
2503 else
2504 break;
2505 }
2506 for (; *cur; ++cur) {
2507 int decc;
2508
2509 decc = _xmlSchemaBase64Decode(*cur);
2510 if (decc < 0) ;
2511 else if (decc < 64)
2512 goto return1;
2513 if (decc == 64)
2514 pad++;
2515 }
2516
2517 /* rfc2045.txt: "Special processing is performed if fewer than
2518 * 24 bits are available at the end of the data being encoded.
2519 * A full encoding quantum is always completed at the end of a
2520 * body. When fewer than 24 input bits are available in an
2521 * input group, zero bits are added (on the right) to form an
2522 * integral number of 6-bit groups. Padding at the end of the
2523 * data is performed using the "=" character. Since all
2524 * base64 input is an integral number of octets, only the
2525 * following cases can arise: (1) the final quantum of
2526 * encoding input is an integral multiple of 24 bits; here,
2527 * the final unit of encoded output will be an integral
2528 * multiple ofindent: Standard input:701: Warning:old style
2529 * assignment ambiguity in "=*". Assuming "= *" 4 characters
2530 * with no "=" padding, (2) the final
2531 * quantum of encoding input is exactly 8 bits; here, the
2532 * final unit of encoded output will be two characters
2533 * followed by two "=" padding characters, or (3) the final
2534 * quantum of encoding input is exactly 16 bits; here, the
2535 * final unit of encoded output will be three characters
2536 * followed by one "=" padding character." */
2537
2538 total = 3 * (i / 4);
2539 if (pad == 0) {
2540 if (i % 4 != 0)
2541 goto return1;
2542 } else if (pad == 1) {
2543 int decc;
2544
2545 if (i % 4 != 3)
2546 goto return1;
2547 for (decc = _xmlSchemaBase64Decode(*cur);
2548 (decc < 0) || (decc > 63);
2549 decc = _xmlSchemaBase64Decode(*cur))
2550 --cur;
2551 /* 16bits in 24bits means 2 pad bits: nnnnnn nnmmmm mmmm00*/
2552 /* 00111100 -> 0x3c */
2553 if (decc & ~0x3c)
2554 goto return1;
2555 total += 2;
2556 } else if (pad == 2) {
2557 int decc;
2558
2559 if (i % 4 != 2)
2560 goto return1;
2561 for (decc = _xmlSchemaBase64Decode(*cur);
2562 (decc < 0) || (decc > 63);
2563 decc = _xmlSchemaBase64Decode(*cur))
2564 --cur;
2565 /* 8bits in 12bits means 4 pad bits: nnnnnn nn0000 */
2566 /* 00110000 -> 0x30 */
2567 if (decc & ~0x30)
2568 goto return1;
2569 total += 1;
2570 } else
2571 goto return1;
2572
2573 if (val != NULL) {
2574 v = xmlSchemaNewValue(XML_SCHEMAS_BASE64BINARY);
2575 if (v == NULL)
2576 goto error;
2577 base =
2578 (xmlChar *) xmlMallocAtomic((i + pad + 1) *
2579 sizeof(xmlChar));
2580 if (base == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002581 xmlSchemaTypeErrMemory(node, "allocating base64 data");
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002582 xmlFree(v);
2583 goto return1;
2584 }
2585 v->value.base64.str = base;
2586 for (cur = value; *cur; ++cur)
2587 if (_xmlSchemaBase64Decode(*cur) >= 0) {
2588 *base = *cur;
2589 ++base;
2590 }
2591 *base = 0;
2592 v->value.base64.total = total;
2593 *val = v;
2594 }
2595 goto return0;
2596 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002597 case XML_SCHEMAS_INTEGER:
2598 case XML_SCHEMAS_PINTEGER:
2599 case XML_SCHEMAS_NPINTEGER:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002600 case XML_SCHEMAS_NINTEGER:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002601 case XML_SCHEMAS_NNINTEGER:{
2602 const xmlChar *cur = value;
2603 unsigned long lo, mi, hi;
2604 int sign = 0;
2605
2606 if (cur == NULL)
2607 goto return1;
2608 if (*cur == '-') {
2609 sign = 1;
2610 cur++;
2611 } else if (*cur == '+')
2612 cur++;
2613 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2614 if (ret == 0)
2615 goto return1;
2616 if (*cur != 0)
2617 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002618 if (type->builtInType == XML_SCHEMAS_NPINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002619 if ((sign == 0) &&
2620 ((hi != 0) || (mi != 0) || (lo != 0)))
2621 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002622 } else if (type->builtInType == XML_SCHEMAS_PINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002623 if (sign == 1)
2624 goto return1;
2625 if ((hi == 0) && (mi == 0) && (lo == 0))
2626 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002627 } else if (type->builtInType == XML_SCHEMAS_NINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002628 if (sign == 0)
2629 goto return1;
2630 if ((hi == 0) && (mi == 0) && (lo == 0))
2631 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002632 } else if (type->builtInType == XML_SCHEMAS_NNINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002633 if ((sign == 1) &&
2634 ((hi != 0) || (mi != 0) || (lo != 0)))
2635 goto return1;
2636 }
2637 /*
2638 * We can store a value only if no overflow occured
2639 */
2640 if ((ret > 0) && (val != NULL)) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00002641 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002642 if (v != NULL) {
2643 v->value.decimal.lo = lo;
2644 v->value.decimal.mi = lo;
2645 v->value.decimal.hi = lo;
2646 v->value.decimal.sign = sign;
2647 v->value.decimal.frac = 0;
2648 v->value.decimal.total = cur - value;
2649 *val = v;
2650 }
2651 }
2652 goto return0;
2653 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002654 case XML_SCHEMAS_LONG:
2655 case XML_SCHEMAS_BYTE:
2656 case XML_SCHEMAS_SHORT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002657 case XML_SCHEMAS_INT:{
2658 const xmlChar *cur = value;
2659 unsigned long lo, mi, hi;
2660 int total = 0;
2661 int sign = 0;
2662
2663 if (cur == NULL)
2664 goto return1;
2665 if (*cur == '-') {
2666 sign = 1;
2667 cur++;
2668 } else if (*cur == '+')
2669 cur++;
2670 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2671 if (ret <= 0)
2672 goto return1;
2673 if (*cur != 0)
2674 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002675 if (type->builtInType == XML_SCHEMAS_LONG) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002676 if (hi >= 922) {
2677 if (hi > 922)
2678 goto return1;
2679 if (mi >= 33720368) {
2680 if (mi > 33720368)
2681 goto return1;
2682 if ((sign == 0) && (lo > 54775807))
2683 goto return1;
2684 if ((sign == 1) && (lo > 54775808))
2685 goto return1;
2686 }
2687 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002688 } else if (type->builtInType == XML_SCHEMAS_INT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002689 if (hi != 0)
2690 goto return1;
2691 if (mi >= 21) {
2692 if (mi > 21)
2693 goto return1;
2694 if ((sign == 0) && (lo > 47483647))
2695 goto return1;
2696 if ((sign == 1) && (lo > 47483648))
2697 goto return1;
2698 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002699 } else if (type->builtInType == XML_SCHEMAS_SHORT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002700 if ((mi != 0) || (hi != 0))
2701 goto return1;
2702 if ((sign == 1) && (lo > 32768))
2703 goto return1;
2704 if ((sign == 0) && (lo > 32767))
2705 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002706 } else if (type->builtInType == XML_SCHEMAS_BYTE) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002707 if ((mi != 0) || (hi != 0))
2708 goto return1;
2709 if ((sign == 1) && (lo > 128))
2710 goto return1;
2711 if ((sign == 0) && (lo > 127))
2712 goto return1;
2713 }
2714 if (val != NULL) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00002715 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002716 if (v != NULL) {
2717 v->value.decimal.lo = lo;
2718 v->value.decimal.mi = lo;
2719 v->value.decimal.hi = lo;
2720 v->value.decimal.sign = sign;
2721 v->value.decimal.frac = 0;
2722 v->value.decimal.total = total;
2723 *val = v;
2724 }
2725 }
2726 goto return0;
2727 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002728 case XML_SCHEMAS_UINT:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002729 case XML_SCHEMAS_ULONG:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002730 case XML_SCHEMAS_USHORT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002731 case XML_SCHEMAS_UBYTE:{
2732 const xmlChar *cur = value;
2733 unsigned long lo, mi, hi;
2734 int total = 0;
2735
2736 if (cur == NULL)
2737 goto return1;
2738 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2739 if (ret <= 0)
2740 goto return1;
2741 if (*cur != 0)
2742 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002743 if (type->builtInType == XML_SCHEMAS_ULONG) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002744 if (hi >= 1844) {
2745 if (hi > 1844)
2746 goto return1;
2747 if (mi >= 67440737) {
2748 if (mi > 67440737)
2749 goto return1;
2750 if (lo > 9551615)
2751 goto return1;
2752 }
2753 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002754 } else if (type->builtInType == XML_SCHEMAS_UINT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002755 if (hi != 0)
2756 goto return1;
2757 if (mi >= 42) {
2758 if (mi > 42)
2759 goto return1;
2760 if (lo > 94967295)
2761 goto return1;
2762 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002763 } else if (type->builtInType == XML_SCHEMAS_USHORT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002764 if ((mi != 0) || (hi != 0))
2765 goto return1;
2766 if (lo > 65535)
2767 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002768 } else if (type->builtInType == XML_SCHEMAS_UBYTE) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002769 if ((mi != 0) || (hi != 0))
2770 goto return1;
2771 if (lo > 255)
2772 goto return1;
2773 }
2774 if (val != NULL) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00002775 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002776 if (v != NULL) {
2777 v->value.decimal.lo = lo;
2778 v->value.decimal.mi = mi;
2779 v->value.decimal.hi = hi;
2780 v->value.decimal.sign = 0;
2781 v->value.decimal.frac = 0;
2782 v->value.decimal.total = total;
2783 *val = v;
2784 }
2785 }
2786 goto return0;
2787 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002788 }
2789
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002790 done:
2791 if (norm != NULL)
2792 xmlFree(norm);
2793 return (ret);
2794 return3:
2795 if (norm != NULL)
2796 xmlFree(norm);
2797 return (3);
2798 return1:
2799 if (norm != NULL)
2800 xmlFree(norm);
2801 return (1);
2802 return0:
2803 if (norm != NULL)
2804 xmlFree(norm);
2805 return (0);
2806 error:
2807 if (norm != NULL)
2808 xmlFree(norm);
2809 return (-1);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002810}
2811
2812/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002813 * xmlSchemaValPredefTypeNode:
Daniel Veillard4255d502002-04-16 15:50:10 +00002814 * @type: the predefined type
2815 * @value: the value to check
2816 * @val: the return computed value
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002817 * @node: the node containing the value
Daniel Veillard4255d502002-04-16 15:50:10 +00002818 *
2819 * Check that a value conforms to the lexical space of the predefined type.
2820 * if true a value is computed and returned in @val.
2821 *
2822 * Returns 0 if this validates, a positive error code number otherwise
2823 * and -1 in case of internal or API error.
2824 */
2825int
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002826xmlSchemaValPredefTypeNode(xmlSchemaTypePtr type, const xmlChar *value,
2827 xmlSchemaValPtr *val, xmlNodePtr node) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002828 return(xmlSchemaValAtomicType(type, value, val, node, 0));
Daniel Veillard4255d502002-04-16 15:50:10 +00002829}
2830
2831/**
Daniel Veillardc0826a72004-08-10 14:17:33 +00002832 * xmlSchemaValPredefTypeNodeNoNorm:
2833 * @type: the predefined type
2834 * @value: the value to check
2835 * @val: the return computed value
2836 * @node: the node containing the value
2837 *
2838 * Check that a value conforms to the lexical space of the predefined type.
2839 * if true a value is computed and returned in @val.
2840 * This one does apply any normalization to the value.
2841 *
2842 * Returns 0 if this validates, a positive error code number otherwise
2843 * and -1 in case of internal or API error.
2844 */
2845int
2846xmlSchemaValPredefTypeNodeNoNorm(xmlSchemaTypePtr type, const xmlChar *value,
2847 xmlSchemaValPtr *val, xmlNodePtr node) {
2848 return(xmlSchemaValAtomicType(type, value, val, node, 1));
2849}
2850
2851/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002852 * xmlSchemaValidatePredefinedType:
2853 * @type: the predefined type
2854 * @value: the value to check
2855 * @val: the return computed value
2856 *
2857 * Check that a value conforms to the lexical space of the predefined type.
2858 * if true a value is computed and returned in @val.
2859 *
2860 * Returns 0 if this validates, a positive error code number otherwise
2861 * and -1 in case of internal or API error.
2862 */
2863int
2864xmlSchemaValidatePredefinedType(xmlSchemaTypePtr type, const xmlChar *value,
2865 xmlSchemaValPtr *val) {
2866 return(xmlSchemaValPredefTypeNode(type, value, val, NULL));
2867}
2868
2869/**
Daniel Veillard4255d502002-04-16 15:50:10 +00002870 * xmlSchemaCompareDecimals:
2871 * @x: a first decimal value
2872 * @y: a second decimal value
2873 *
2874 * Compare 2 decimals
2875 *
2876 * Returns -1 if x < y, 0 if x == y, 1 if x > y and -2 in case of error
2877 */
2878static int
2879xmlSchemaCompareDecimals(xmlSchemaValPtr x, xmlSchemaValPtr y)
2880{
2881 xmlSchemaValPtr swp;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002882 int order = 1, p;
Daniel Veillard4255d502002-04-16 15:50:10 +00002883 unsigned long tmp;
2884
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002885 if ((x->value.decimal.sign) &&
2886 ((x->value.decimal.lo != 0) ||
2887 (x->value.decimal.mi != 0) ||
2888 (x->value.decimal.hi != 0))) {
2889 if ((y->value.decimal.sign) &&
2890 ((y->value.decimal.lo != 0) ||
2891 (y->value.decimal.mi != 0) ||
2892 (y->value.decimal.hi != 0)))
Daniel Veillard80b19092003-03-28 13:29:53 +00002893 order = -1;
2894 else
2895 return (-1);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002896 } else if ((y->value.decimal.sign) &&
2897 ((y->value.decimal.lo != 0) ||
2898 (y->value.decimal.mi != 0) ||
2899 (y->value.decimal.hi != 0))) {
Daniel Veillard4255d502002-04-16 15:50:10 +00002900 return (1);
Daniel Veillard80b19092003-03-28 13:29:53 +00002901 }
Daniel Veillard4255d502002-04-16 15:50:10 +00002902 if (x->value.decimal.frac == y->value.decimal.frac) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002903 if (x->value.decimal.hi < y->value.decimal.hi)
2904 return (-order);
Daniel Veillard01fa6152004-06-29 17:04:39 +00002905 if (x->value.decimal.hi > y->value.decimal.hi)
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002906 return (order);
2907 if (x->value.decimal.mi < y->value.decimal.mi)
2908 return (-order);
Daniel Veillard01fa6152004-06-29 17:04:39 +00002909 if (x->value.decimal.mi > y->value.decimal.mi)
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002910 return (order);
2911 if (x->value.decimal.lo < y->value.decimal.lo)
Daniel Veillard80b19092003-03-28 13:29:53 +00002912 return (-order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002913 if (x->value.decimal.lo > y->value.decimal.lo)
Daniel Veillard80b19092003-03-28 13:29:53 +00002914 return(order);
2915 return(0);
Daniel Veillard4255d502002-04-16 15:50:10 +00002916 }
2917 if (y->value.decimal.frac > x->value.decimal.frac) {
2918 swp = y;
2919 y = x;
2920 x = swp;
2921 order = -order;
2922 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002923 p = powten[x->value.decimal.frac - y->value.decimal.frac];
2924 tmp = x->value.decimal.lo / p;
2925 if (tmp > y->value.decimal.lo)
Daniel Veillard4255d502002-04-16 15:50:10 +00002926 return (order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002927 if (tmp < y->value.decimal.lo)
Daniel Veillard4255d502002-04-16 15:50:10 +00002928 return (-order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002929 tmp = y->value.decimal.lo * p;
2930 if (x->value.decimal.lo < tmp)
Daniel Veillard4255d502002-04-16 15:50:10 +00002931 return (-order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002932 if (x->value.decimal.lo == tmp)
Daniel Veillard4255d502002-04-16 15:50:10 +00002933 return (0);
2934 return (order);
2935}
2936
2937/**
Daniel Veillard070803b2002-05-03 07:29:38 +00002938 * xmlSchemaCompareDurations:
2939 * @x: a first duration value
2940 * @y: a second duration value
2941 *
2942 * Compare 2 durations
2943 *
2944 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
2945 * case of error
2946 */
2947static int
2948xmlSchemaCompareDurations(xmlSchemaValPtr x, xmlSchemaValPtr y)
2949{
2950 long carry, mon, day;
2951 double sec;
Daniel Veillard80b19092003-03-28 13:29:53 +00002952 int invert = 1;
2953 long xmon, xday, myear, minday, maxday;
Daniel Veillard070803b2002-05-03 07:29:38 +00002954 static const long dayRange [2][12] = {
2955 { 0, 28, 59, 89, 120, 150, 181, 212, 242, 273, 303, 334, },
2956 { 0, 31, 62, 92, 123, 153, 184, 215, 245, 276, 306, 337} };
2957
2958 if ((x == NULL) || (y == NULL))
Daniel Veillard5a872412002-05-22 06:40:27 +00002959 return -2;
Daniel Veillard070803b2002-05-03 07:29:38 +00002960
2961 /* months */
2962 mon = x->value.dur.mon - y->value.dur.mon;
2963
2964 /* seconds */
2965 sec = x->value.dur.sec - y->value.dur.sec;
2966 carry = (long)sec / SECS_PER_DAY;
2967 sec -= (double)(carry * SECS_PER_DAY);
2968
2969 /* days */
2970 day = x->value.dur.day - y->value.dur.day + carry;
2971
2972 /* easy test */
2973 if (mon == 0) {
2974 if (day == 0)
2975 if (sec == 0.0)
2976 return 0;
2977 else if (sec < 0.0)
2978 return -1;
2979 else
2980 return 1;
2981 else if (day < 0)
2982 return -1;
2983 else
2984 return 1;
2985 }
2986
2987 if (mon > 0) {
2988 if ((day >= 0) && (sec >= 0.0))
2989 return 1;
2990 else {
2991 xmon = mon;
2992 xday = -day;
2993 }
2994 } else if ((day <= 0) && (sec <= 0.0)) {
2995 return -1;
2996 } else {
Daniel Veillard80b19092003-03-28 13:29:53 +00002997 invert = -1;
Daniel Veillard070803b2002-05-03 07:29:38 +00002998 xmon = -mon;
2999 xday = day;
3000 }
3001
3002 myear = xmon / 12;
Daniel Veillard80b19092003-03-28 13:29:53 +00003003 if (myear == 0) {
3004 minday = 0;
3005 maxday = 0;
3006 } else {
3007 maxday = 366 * ((myear + 3) / 4) +
3008 365 * ((myear - 1) % 4);
3009 minday = maxday - 1;
3010 }
3011
Daniel Veillard070803b2002-05-03 07:29:38 +00003012 xmon = xmon % 12;
3013 minday += dayRange[0][xmon];
3014 maxday += dayRange[1][xmon];
3015
Daniel Veillard80b19092003-03-28 13:29:53 +00003016 if ((maxday == minday) && (maxday == xday))
3017 return(0); /* can this really happen ? */
Daniel Veillard070803b2002-05-03 07:29:38 +00003018 if (maxday < xday)
Daniel Veillard80b19092003-03-28 13:29:53 +00003019 return(-invert);
3020 if (minday > xday)
3021 return(invert);
Daniel Veillard070803b2002-05-03 07:29:38 +00003022
3023 /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00003024 return 2;
3025}
3026
3027/*
3028 * macros for adding date/times and durations
3029 */
3030#define FQUOTIENT(a,b) (floor(((double)a/(double)b)))
3031#define MODULO(a,b) (a - FQUOTIENT(a,b) * b)
3032#define FQUOTIENT_RANGE(a,low,high) (FQUOTIENT((a-low),(high-low)))
3033#define MODULO_RANGE(a,low,high) ((MODULO((a-low),(high-low)))+low)
3034
3035/**
Daniel Veillard669adfc2004-05-29 20:12:46 +00003036 * xmlSchemaDupVal:
3037 * @v: the #xmlSchemaValPtr value to duplicate
3038 *
3039 * Makes a copy of @v. The calling program is responsible for freeing
3040 * the returned value.
3041 *
3042 * returns a pointer to a duplicated #xmlSchemaValPtr or NULL if error.
3043 */
3044static xmlSchemaValPtr
3045xmlSchemaDupVal (xmlSchemaValPtr v)
3046{
3047 xmlSchemaValPtr ret = xmlSchemaNewValue(v->type);
3048 if (ret == NULL)
3049 return NULL;
3050
3051 memcpy(ret, v, sizeof(xmlSchemaVal));
3052 return ret;
3053}
3054
3055/**
Kasimier T. Buchcik285ebab2005-03-04 18:04:59 +00003056 * xmlSchemaCopyValue:
3057 * @val: the precomputed value to be copied
3058 *
3059 * Copies the precomputed value. This duplicates any string within.
3060 *
3061 * Returns the copy or NULL if a copy for a data-type is not implemented.
3062 */
3063xmlSchemaValPtr
3064xmlSchemaCopyValue(xmlSchemaValPtr val)
3065{
3066 xmlSchemaValPtr ret;
3067
3068 if (val == NULL)
3069 return (NULL);
3070 /*
3071 * Copy the string values.
3072 */
3073 switch (val->type) {
3074 case XML_SCHEMAS_IDREFS:
3075 case XML_SCHEMAS_ENTITIES:
3076 case XML_SCHEMAS_NMTOKENS:
3077 case XML_SCHEMAS_ANYTYPE:
3078 case XML_SCHEMAS_ANYSIMPLETYPE:
3079 return (NULL);
3080 case XML_SCHEMAS_STRING:
3081 case XML_SCHEMAS_NORMSTRING:
3082 case XML_SCHEMAS_TOKEN:
3083 case XML_SCHEMAS_LANGUAGE:
3084 case XML_SCHEMAS_NAME:
3085 case XML_SCHEMAS_NCNAME:
3086 case XML_SCHEMAS_ID:
3087 case XML_SCHEMAS_IDREF:
3088 case XML_SCHEMAS_ENTITY:
3089 case XML_SCHEMAS_NMTOKEN:
Kasimier T. Buchcik2ee855d2005-03-07 11:14:14 +00003090 case XML_SCHEMAS_ANYURI:
Kasimier T. Buchcik285ebab2005-03-04 18:04:59 +00003091 ret = xmlSchemaDupVal(val);
3092 if (val->value.str != NULL)
3093 ret->value.str = xmlStrdup(BAD_CAST val->value.str);
3094 return (ret);
Kasimier T. Buchcik2ee855d2005-03-07 11:14:14 +00003095 case XML_SCHEMAS_QNAME:
Kasimier T. Buchcik285ebab2005-03-04 18:04:59 +00003096 case XML_SCHEMAS_NOTATION:
3097 ret = xmlSchemaDupVal(val);
3098 if (val->value.qname.name != NULL)
3099 ret->value.qname.name =
3100 xmlStrdup(BAD_CAST val->value.qname.name);
3101 if (val->value.qname.uri != NULL)
3102 ret->value.qname.uri =
3103 xmlStrdup(BAD_CAST val->value.qname.uri);
3104 return (ret);
3105 case XML_SCHEMAS_HEXBINARY:
3106 ret = xmlSchemaDupVal(val);
3107 if (val->value.hex.str != NULL)
3108 ret->value.hex.str = xmlStrdup(BAD_CAST val->value.hex.str);
3109 return (ret);
3110 case XML_SCHEMAS_BASE64BINARY:
3111 ret = xmlSchemaDupVal(val);
3112 if (val->value.base64.str != NULL)
3113 ret->value.base64.str =
3114 xmlStrdup(BAD_CAST val->value.base64.str);
3115 return (ret);
3116 default:
3117 return (xmlSchemaDupVal(val));
3118 }
3119 return (NULL);
3120}
3121
3122/**
Daniel Veillard5a872412002-05-22 06:40:27 +00003123 * _xmlSchemaDateAdd:
3124 * @dt: an #xmlSchemaValPtr
3125 * @dur: an #xmlSchemaValPtr of type #XS_DURATION
3126 *
3127 * Compute a new date/time from @dt and @dur. This function assumes @dt
3128 * is either #XML_SCHEMAS_DATETIME, #XML_SCHEMAS_DATE, #XML_SCHEMAS_GYEARMONTH,
Daniel Veillard669adfc2004-05-29 20:12:46 +00003129 * or #XML_SCHEMAS_GYEAR. The returned #xmlSchemaVal is the same type as
3130 * @dt. The calling program is responsible for freeing the returned value.
Daniel Veillard5a872412002-05-22 06:40:27 +00003131 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00003132 * Returns a pointer to a new #xmlSchemaVal or NULL if error.
Daniel Veillard5a872412002-05-22 06:40:27 +00003133 */
3134static xmlSchemaValPtr
3135_xmlSchemaDateAdd (xmlSchemaValPtr dt, xmlSchemaValPtr dur)
3136{
Daniel Veillard669adfc2004-05-29 20:12:46 +00003137 xmlSchemaValPtr ret, tmp;
Daniel Veillard5a872412002-05-22 06:40:27 +00003138 long carry, tempdays, temp;
3139 xmlSchemaValDatePtr r, d;
3140 xmlSchemaValDurationPtr u;
3141
3142 if ((dt == NULL) || (dur == NULL))
3143 return NULL;
3144
3145 ret = xmlSchemaNewValue(dt->type);
3146 if (ret == NULL)
3147 return NULL;
3148
Daniel Veillard669adfc2004-05-29 20:12:46 +00003149 /* make a copy so we don't alter the original value */
3150 tmp = xmlSchemaDupVal(dt);
3151 if (tmp == NULL) {
3152 xmlSchemaFreeValue(ret);
3153 return NULL;
3154 }
3155
Daniel Veillard5a872412002-05-22 06:40:27 +00003156 r = &(ret->value.date);
Daniel Veillard669adfc2004-05-29 20:12:46 +00003157 d = &(tmp->value.date);
Daniel Veillard5a872412002-05-22 06:40:27 +00003158 u = &(dur->value.dur);
3159
3160 /* normalization */
3161 if (d->mon == 0)
3162 d->mon = 1;
3163
3164 /* normalize for time zone offset */
3165 u->sec -= (d->tzo * 60);
3166 d->tzo = 0;
3167
3168 /* normalization */
3169 if (d->day == 0)
3170 d->day = 1;
3171
3172 /* month */
3173 carry = d->mon + u->mon;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003174 r->mon = (unsigned int) MODULO_RANGE(carry, 1, 13);
3175 carry = (long) FQUOTIENT_RANGE(carry, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00003176
3177 /* year (may be modified later) */
3178 r->year = d->year + carry;
3179 if (r->year == 0) {
3180 if (d->year > 0)
3181 r->year--;
3182 else
3183 r->year++;
3184 }
3185
3186 /* time zone */
3187 r->tzo = d->tzo;
3188 r->tz_flag = d->tz_flag;
3189
3190 /* seconds */
3191 r->sec = d->sec + u->sec;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003192 carry = (long) FQUOTIENT((long)r->sec, 60);
Daniel Veillard5a872412002-05-22 06:40:27 +00003193 if (r->sec != 0.0) {
3194 r->sec = MODULO(r->sec, 60.0);
3195 }
3196
3197 /* minute */
3198 carry += d->min;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003199 r->min = (unsigned int) MODULO(carry, 60);
3200 carry = (long) FQUOTIENT(carry, 60);
Daniel Veillard5a872412002-05-22 06:40:27 +00003201
3202 /* hours */
3203 carry += d->hour;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003204 r->hour = (unsigned int) MODULO(carry, 24);
3205 carry = (long)FQUOTIENT(carry, 24);
Daniel Veillard5a872412002-05-22 06:40:27 +00003206
3207 /*
3208 * days
3209 * Note we use tempdays because the temporary values may need more
3210 * than 5 bits
3211 */
3212 if ((VALID_YEAR(r->year)) && (VALID_MONTH(r->mon)) &&
3213 (d->day > MAX_DAYINMONTH(r->year, r->mon)))
3214 tempdays = MAX_DAYINMONTH(r->year, r->mon);
3215 else if (d->day < 1)
3216 tempdays = 1;
3217 else
3218 tempdays = d->day;
3219
3220 tempdays += u->day + carry;
3221
3222 while (1) {
3223 if (tempdays < 1) {
Daniel Veillardebe25d42004-03-25 09:35:49 +00003224 long tmon = (long) MODULO_RANGE(r->mon-1, 1, 13);
3225 long tyr = r->year + (long)FQUOTIENT_RANGE(r->mon-1, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00003226 if (tyr == 0)
3227 tyr--;
3228 tempdays += MAX_DAYINMONTH(tyr, tmon);
3229 carry = -1;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003230 } else if (tempdays > (long) MAX_DAYINMONTH(r->year, r->mon)) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003231 tempdays = tempdays - MAX_DAYINMONTH(r->year, r->mon);
3232 carry = 1;
3233 } else
3234 break;
3235
3236 temp = r->mon + carry;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003237 r->mon = (unsigned int) MODULO_RANGE(temp, 1, 13);
3238 r->year = r->year + (unsigned int) FQUOTIENT_RANGE(temp, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00003239 if (r->year == 0) {
3240 if (temp < 1)
3241 r->year--;
3242 else
3243 r->year++;
3244 }
3245 }
3246
3247 r->day = tempdays;
3248
3249 /*
3250 * adjust the date/time type to the date values
3251 */
3252 if (ret->type != XML_SCHEMAS_DATETIME) {
3253 if ((r->hour) || (r->min) || (r->sec))
3254 ret->type = XML_SCHEMAS_DATETIME;
3255 else if (ret->type != XML_SCHEMAS_DATE) {
3256 if ((r->mon != 1) && (r->day != 1))
3257 ret->type = XML_SCHEMAS_DATE;
3258 else if ((ret->type != XML_SCHEMAS_GYEARMONTH) && (r->mon != 1))
3259 ret->type = XML_SCHEMAS_GYEARMONTH;
3260 }
3261 }
3262
Daniel Veillard669adfc2004-05-29 20:12:46 +00003263 xmlSchemaFreeValue(tmp);
Daniel Veillard5a872412002-05-22 06:40:27 +00003264
Daniel Veillard5a872412002-05-22 06:40:27 +00003265 return ret;
3266}
3267
3268/**
3269 * xmlSchemaDateNormalize:
Daniel Veillard669adfc2004-05-29 20:12:46 +00003270 * @dt: an #xmlSchemaValPtr of a date/time type value.
3271 * @offset: number of seconds to adjust @dt by.
Daniel Veillard5a872412002-05-22 06:40:27 +00003272 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00003273 * Normalize @dt to GMT time. The @offset parameter is subtracted from
3274 * the return value is a time-zone offset is present on @dt.
Daniel Veillard5a872412002-05-22 06:40:27 +00003275 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00003276 * Returns a normalized copy of @dt or NULL if error.
Daniel Veillard5a872412002-05-22 06:40:27 +00003277 */
3278static xmlSchemaValPtr
3279xmlSchemaDateNormalize (xmlSchemaValPtr dt, double offset)
3280{
3281 xmlSchemaValPtr dur, ret;
3282
3283 if (dt == NULL)
3284 return NULL;
3285
3286 if (((dt->type != XML_SCHEMAS_TIME) &&
3287 (dt->type != XML_SCHEMAS_DATETIME)) || (dt->value.date.tzo == 0))
3288 return xmlSchemaDupVal(dt);
3289
3290 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
3291 if (dur == NULL)
3292 return NULL;
3293
3294 dur->value.date.sec -= offset;
3295
3296 ret = _xmlSchemaDateAdd(dt, dur);
3297 if (ret == NULL)
3298 return NULL;
3299
3300 xmlSchemaFreeValue(dur);
3301
3302 /* ret->value.date.tzo = 0; */
3303 return ret;
3304}
3305
3306/**
3307 * _xmlSchemaDateCastYMToDays:
3308 * @dt: an #xmlSchemaValPtr
3309 *
3310 * Convert mon and year of @dt to total number of days. Take the
3311 * number of years since (or before) 1 AD and add the number of leap
3312 * years. This is a function because negative
3313 * years must be handled a little differently and there is no zero year.
3314 *
3315 * Returns number of days.
3316 */
3317static long
3318_xmlSchemaDateCastYMToDays (const xmlSchemaValPtr dt)
3319{
3320 long ret;
Daniel Veillard49e89632004-09-23 16:24:36 +00003321 int mon;
Daniel Veillard5a872412002-05-22 06:40:27 +00003322
Daniel Veillard49e89632004-09-23 16:24:36 +00003323 mon = dt->value.date.mon;
3324 if (mon <= 0) mon = 1; /* normalization */
3325
3326 if (dt->value.date.year <= 0)
Daniel Veillard5a872412002-05-22 06:40:27 +00003327 ret = (dt->value.date.year * 365) +
3328 (((dt->value.date.year+1)/4)-((dt->value.date.year+1)/100)+
3329 ((dt->value.date.year+1)/400)) +
Daniel Veillard49e89632004-09-23 16:24:36 +00003330 DAY_IN_YEAR(0, mon, dt->value.date.year);
Daniel Veillard5a872412002-05-22 06:40:27 +00003331 else
3332 ret = ((dt->value.date.year-1) * 365) +
3333 (((dt->value.date.year-1)/4)-((dt->value.date.year-1)/100)+
3334 ((dt->value.date.year-1)/400)) +
Daniel Veillard49e89632004-09-23 16:24:36 +00003335 DAY_IN_YEAR(0, mon, dt->value.date.year);
Daniel Veillard5a872412002-05-22 06:40:27 +00003336
3337 return ret;
3338}
3339
3340/**
3341 * TIME_TO_NUMBER:
3342 * @dt: an #xmlSchemaValPtr
3343 *
3344 * Calculates the number of seconds in the time portion of @dt.
3345 *
3346 * Returns seconds.
3347 */
3348#define TIME_TO_NUMBER(dt) \
3349 ((double)((dt->value.date.hour * SECS_PER_HOUR) + \
Daniel Veillardb3721c22003-03-31 11:22:25 +00003350 (dt->value.date.min * SECS_PER_MIN) + \
3351 (dt->value.date.tzo * SECS_PER_MIN)) + \
3352 dt->value.date.sec)
Daniel Veillard5a872412002-05-22 06:40:27 +00003353
3354/**
3355 * xmlSchemaCompareDates:
3356 * @x: a first date/time value
3357 * @y: a second date/time value
3358 *
3359 * Compare 2 date/times
3360 *
3361 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3362 * case of error
3363 */
3364static int
3365xmlSchemaCompareDates (xmlSchemaValPtr x, xmlSchemaValPtr y)
3366{
3367 unsigned char xmask, ymask, xor_mask, and_mask;
3368 xmlSchemaValPtr p1, p2, q1, q2;
3369 long p1d, p2d, q1d, q2d;
3370
3371 if ((x == NULL) || (y == NULL))
3372 return -2;
3373
3374 if (x->value.date.tz_flag) {
3375
3376 if (!y->value.date.tz_flag) {
3377 p1 = xmlSchemaDateNormalize(x, 0);
3378 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3379 /* normalize y + 14:00 */
3380 q1 = xmlSchemaDateNormalize(y, (14 * SECS_PER_HOUR));
3381
3382 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003383 if (p1d < q1d) {
3384 xmlSchemaFreeValue(p1);
3385 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003386 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003387 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003388 double sec;
3389
3390 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00003391 if (sec < 0.0) {
3392 xmlSchemaFreeValue(p1);
3393 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003394 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003395 } else {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003396 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003397 /* normalize y - 14:00 */
3398 q2 = xmlSchemaDateNormalize(y, -(14 * SECS_PER_HOUR));
3399 q2d = _xmlSchemaDateCastYMToDays(q2) + q2->value.date.day;
3400 if (p1d > q2d)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003401 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003402 else if (p1d == q2d) {
3403 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q2);
3404 if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003405 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003406 else
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003407 ret = 2; /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00003408 }
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003409 xmlSchemaFreeValue(p1);
3410 xmlSchemaFreeValue(q1);
3411 xmlSchemaFreeValue(q2);
3412 if (ret != 0)
3413 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003414 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00003415 } else {
3416 xmlSchemaFreeValue(p1);
3417 xmlSchemaFreeValue(q1);
3418 }
Daniel Veillard5a872412002-05-22 06:40:27 +00003419 }
3420 } else if (y->value.date.tz_flag) {
3421 q1 = xmlSchemaDateNormalize(y, 0);
3422 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
3423
3424 /* normalize x - 14:00 */
3425 p1 = xmlSchemaDateNormalize(x, -(14 * SECS_PER_HOUR));
3426 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3427
Daniel Veillardfdc91562002-07-01 21:52:03 +00003428 if (p1d < q1d) {
3429 xmlSchemaFreeValue(p1);
3430 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003431 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003432 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003433 double sec;
3434
3435 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00003436 if (sec < 0.0) {
3437 xmlSchemaFreeValue(p1);
3438 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003439 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003440 } else {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003441 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003442 /* normalize x + 14:00 */
3443 p2 = xmlSchemaDateNormalize(x, (14 * SECS_PER_HOUR));
3444 p2d = _xmlSchemaDateCastYMToDays(p2) + p2->value.date.day;
3445
Daniel Veillard6560a422003-03-27 21:25:38 +00003446 if (p2d > q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003447 ret = 1;
Daniel Veillard6560a422003-03-27 21:25:38 +00003448 } else if (p2d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003449 sec = TIME_TO_NUMBER(p2) - TIME_TO_NUMBER(q1);
3450 if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003451 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003452 else
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003453 ret = 2; /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00003454 }
Daniel Veillard6560a422003-03-27 21:25:38 +00003455 xmlSchemaFreeValue(p1);
3456 xmlSchemaFreeValue(q1);
3457 xmlSchemaFreeValue(p2);
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003458 if (ret != 0)
3459 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003460 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00003461 } else {
3462 xmlSchemaFreeValue(p1);
3463 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003464 }
3465 }
3466
3467 /*
3468 * if the same type then calculate the difference
3469 */
3470 if (x->type == y->type) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003471 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003472 q1 = xmlSchemaDateNormalize(y, 0);
3473 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
3474
3475 p1 = xmlSchemaDateNormalize(x, 0);
3476 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3477
Daniel Veillardfdc91562002-07-01 21:52:03 +00003478 if (p1d < q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003479 ret = -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003480 } else if (p1d > q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003481 ret = 1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003482 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00003483 double sec;
3484
3485 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
3486 if (sec < 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003487 ret = -1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003488 else if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003489 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003490
3491 }
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003492 xmlSchemaFreeValue(p1);
3493 xmlSchemaFreeValue(q1);
3494 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003495 }
3496
3497 switch (x->type) {
3498 case XML_SCHEMAS_DATETIME:
3499 xmask = 0xf;
3500 break;
3501 case XML_SCHEMAS_DATE:
3502 xmask = 0x7;
3503 break;
3504 case XML_SCHEMAS_GYEAR:
3505 xmask = 0x1;
3506 break;
3507 case XML_SCHEMAS_GMONTH:
3508 xmask = 0x2;
3509 break;
3510 case XML_SCHEMAS_GDAY:
3511 xmask = 0x3;
3512 break;
3513 case XML_SCHEMAS_GYEARMONTH:
3514 xmask = 0x3;
3515 break;
3516 case XML_SCHEMAS_GMONTHDAY:
3517 xmask = 0x6;
3518 break;
3519 case XML_SCHEMAS_TIME:
3520 xmask = 0x8;
3521 break;
3522 default:
3523 xmask = 0;
3524 break;
3525 }
3526
3527 switch (y->type) {
3528 case XML_SCHEMAS_DATETIME:
3529 ymask = 0xf;
3530 break;
3531 case XML_SCHEMAS_DATE:
3532 ymask = 0x7;
3533 break;
3534 case XML_SCHEMAS_GYEAR:
3535 ymask = 0x1;
3536 break;
3537 case XML_SCHEMAS_GMONTH:
3538 ymask = 0x2;
3539 break;
3540 case XML_SCHEMAS_GDAY:
3541 ymask = 0x3;
3542 break;
3543 case XML_SCHEMAS_GYEARMONTH:
3544 ymask = 0x3;
3545 break;
3546 case XML_SCHEMAS_GMONTHDAY:
3547 ymask = 0x6;
3548 break;
3549 case XML_SCHEMAS_TIME:
3550 ymask = 0x8;
3551 break;
3552 default:
3553 ymask = 0;
3554 break;
3555 }
3556
3557 xor_mask = xmask ^ ymask; /* mark type differences */
3558 and_mask = xmask & ymask; /* mark field specification */
3559
3560 /* year */
3561 if (xor_mask & 1)
3562 return 2; /* indeterminate */
3563 else if (and_mask & 1) {
3564 if (x->value.date.year < y->value.date.year)
3565 return -1;
3566 else if (x->value.date.year > y->value.date.year)
3567 return 1;
3568 }
3569
3570 /* month */
3571 if (xor_mask & 2)
3572 return 2; /* indeterminate */
3573 else if (and_mask & 2) {
3574 if (x->value.date.mon < y->value.date.mon)
3575 return -1;
3576 else if (x->value.date.mon > y->value.date.mon)
3577 return 1;
3578 }
3579
3580 /* day */
3581 if (xor_mask & 4)
3582 return 2; /* indeterminate */
3583 else if (and_mask & 4) {
3584 if (x->value.date.day < y->value.date.day)
3585 return -1;
3586 else if (x->value.date.day > y->value.date.day)
3587 return 1;
3588 }
3589
3590 /* time */
3591 if (xor_mask & 8)
3592 return 2; /* indeterminate */
3593 else if (and_mask & 8) {
3594 if (x->value.date.hour < y->value.date.hour)
3595 return -1;
3596 else if (x->value.date.hour > y->value.date.hour)
3597 return 1;
3598 else if (x->value.date.min < y->value.date.min)
3599 return -1;
3600 else if (x->value.date.min > y->value.date.min)
3601 return 1;
3602 else if (x->value.date.sec < y->value.date.sec)
3603 return -1;
3604 else if (x->value.date.sec > y->value.date.sec)
3605 return 1;
3606 }
3607
Daniel Veillard070803b2002-05-03 07:29:38 +00003608 return 0;
3609}
3610
3611/**
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003612 * xmlSchemaComparePreserveReplaceStrings:
3613 * @x: a first string value
3614 * @y: a second string value
3615 * @invert: inverts the result if x < y or x > y.
3616 *
3617 * Compare 2 string for their normalized values.
3618 * @x is a string with whitespace of "preserve", @y is
3619 * a string with a whitespace of "replace". I.e. @x could
3620 * be an "xsd:string" and @y an "xsd:normalizedString".
3621 *
3622 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
3623 * case of error
3624 */
3625static int
3626xmlSchemaComparePreserveReplaceStrings(xmlSchemaValPtr x, xmlSchemaValPtr y,
3627 int invert)
3628{
3629 const xmlChar *utf1;
3630 const xmlChar *utf2;
3631 int tmp;
3632
3633 if ((x == NULL) || (y == NULL))
3634 return(-2);
3635 utf1 = x->value.str;
3636 utf2 = y->value.str;
3637
3638 while ((*utf1 != 0) && (*utf2 != 0)) {
3639 if (IS_WSP_REPLACE_CH(*utf2)) {
3640 if (! IS_WSP_SPACE_CH(*utf1)) {
3641 if ((*utf1 - 0x20) < 0) {
3642 if (invert)
3643 return(1);
3644 else
3645 return(-1);
3646 } else {
3647 if (invert)
3648 return(-1);
3649 else
3650 return(1);
3651 }
3652 }
3653 } else {
3654 tmp = *utf1 - *utf2;
3655 if (tmp < 0) {
3656 if (invert)
3657 return(1);
3658 else
3659 return(-1);
3660 }
3661 if (tmp > 0) {
3662 if (invert)
3663 return(-1);
3664 else
3665 return(1);
3666 }
3667 }
3668 utf1++;
3669 utf2++;
3670 }
3671 if (*utf1 != 0) {
3672 if (invert)
3673 return(-1);
3674 else
3675 return(1);
3676 }
3677 if (*utf2 != 0) {
3678 if (invert)
3679 return(1);
3680 else
3681 return(-1);
3682 }
3683 return(0);
3684}
3685
3686/**
3687 * xmlSchemaComparePreserveCollapseStrings:
3688 * @x: a first string value
3689 * @y: a second string value
3690 *
3691 * Compare 2 string for their normalized values.
3692 * @x is a string with whitespace of "preserve", @y is
3693 * a string with a whitespace of "collapse". I.e. @x could
3694 * be an "xsd:string" and @y an "xsd:normalizedString".
3695 *
3696 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
3697 * case of error
3698 */
3699static int
3700xmlSchemaComparePreserveCollapseStrings(xmlSchemaValPtr x, xmlSchemaValPtr y,
3701 int invert)
3702{
3703 const xmlChar *utf1;
3704 const xmlChar *utf2;
3705 int tmp;
3706
3707 if ((x == NULL) || (y == NULL))
3708 return(-2);
3709 utf1 = x->value.str;
3710 utf2 = y->value.str;
3711
3712 /*
3713 * Skip leading blank chars of the collapsed string.
3714 */
3715 while (IS_WSP_SPACE_CH(*utf2) || IS_WSP_REPLACE_CH(*utf2))
3716 utf2++;
3717
3718 while ((*utf1 != 0) && (*utf2 != 0)) {
3719 if (IS_WSP_SPACE_CH(*utf2) || IS_WSP_REPLACE_CH(*utf2)) {
3720 if (! IS_WSP_SPACE_CH(*utf1)) {
3721 /*
3722 * The utf2 character would have been replaced to 0x20.
3723 */
3724 if ((*utf1 - 0x20) < 0) {
3725 if (invert)
3726 return(1);
3727 else
3728 return(-1);
3729 } else {
3730 if (invert)
3731 return(-1);
3732 else
3733 return(1);
3734 }
3735 }
3736 utf1++;
3737 utf2++;
3738 /*
3739 * Skip contiguous blank chars of the collapsed string.
3740 */
3741 while (IS_WSP_SPACE_CH(*utf2) || IS_WSP_REPLACE_CH(*utf2))
3742 utf2++;
3743 } else {
3744 tmp = *utf1++ - *utf2++;
3745 if (tmp < 0) {
3746 if (invert)
3747 return(1);
3748 else
3749 return(-1);
3750 }
3751 if (tmp > 0) {
3752 if (invert)
3753 return(-1);
3754 else
3755 return(1);
3756 }
3757 }
3758 }
3759 if (*utf1 != 0) {
3760 if (invert)
3761 return(-1);
3762 else
3763 return(1);
3764 }
3765 if (*utf2 != 0) {
3766 /*
3767 * Skip trailing blank chars of the collapsed string.
3768 */
3769 while (IS_WSP_SPACE_CH(*utf2) || IS_WSP_REPLACE_CH(*utf2))
3770 utf2++;
3771 if (*utf2 != 0) {
3772 if (invert)
3773 return(1);
3774 else
3775 return(-1);
3776 }
3777 }
3778 return(0);
3779}
3780
3781/**
3782 * xmlSchemaComparePreserveCollapseStrings:
3783 * @x: a first string value
3784 * @y: a second string value
3785 *
3786 * Compare 2 string for their normalized values.
3787 * @x is a string with whitespace of "preserve", @y is
3788 * a string with a whitespace of "collapse". I.e. @x could
3789 * be an "xsd:string" and @y an "xsd:normalizedString".
3790 *
3791 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
3792 * case of error
3793 */
3794static int
3795xmlSchemaCompareReplaceCollapseStrings(xmlSchemaValPtr x, xmlSchemaValPtr y,
3796 int invert)
3797{
3798 const xmlChar *utf1;
3799 const xmlChar *utf2;
3800 int tmp;
3801
3802 if ((x == NULL) || (y == NULL))
3803 return(-2);
3804 utf1 = x->value.str;
3805 utf2 = y->value.str;
3806
3807 /*
3808 * Skip leading blank chars of the collapsed string.
3809 */
3810 while (IS_WSP_SPACE_CH(*utf2) || IS_WSP_REPLACE_CH(*utf2))
3811 utf2++;
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 /*
3817 * The utf2 character would have been replaced to 0x20.
3818 */
3819 if ((*utf1 - 0x20) < 0) {
3820 if (invert)
3821 return(1);
3822 else
3823 return(-1);
3824 } else {
3825 if (invert)
3826 return(-1);
3827 else
3828 return(1);
3829 }
3830 }
3831 utf1++;
3832 utf2++;
3833 /*
3834 * Skip contiguous blank chars of the collapsed string.
3835 */
3836 while (IS_WSP_SPACE_CH(*utf2) || IS_WSP_REPLACE_CH(*utf2))
3837 utf2++;
3838 } else {
3839 if (IS_WSP_SPACE_CH(*utf1) || IS_WSP_REPLACE_CH(*utf1)) {
3840 /*
3841 * The utf1 character would have been replaced to 0x20.
3842 */
3843 if ((0x20 - *utf2) < 0) {
3844 if (invert)
3845 return(1);
3846 else
3847 return(-1);
3848 } else {
3849 if (invert)
3850 return(-1);
3851 else
3852 return(1);
3853 }
3854 }
3855 tmp = *utf1++ - *utf2++;
3856 if (tmp < 0)
3857 return(-1);
3858 if (tmp > 0)
3859 return(1);
3860 }
3861 }
3862 if (*utf1 != 0) {
3863 if (invert)
3864 return(-1);
3865 else
3866 return(1);
3867 }
3868 if (*utf2 != 0) {
3869 /*
3870 * Skip trailing blank chars of the collapsed string.
3871 */
3872 while (IS_WSP_SPACE_CH(*utf2) || IS_WSP_REPLACE_CH(*utf2))
3873 utf2++;
3874 if (*utf2 != 0) {
3875 if (invert)
3876 return(1);
3877 else
3878 return(-1);
3879 }
3880 }
3881 return(0);
3882}
3883
3884
3885/**
3886 * xmlSchemaCompareReplacedStrings:
3887 * @x: a first string value
3888 * @y: a second string value
3889 *
3890 * Compare 2 string for their normalized values.
3891 *
3892 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
3893 * case of error
3894 */
3895static int
3896xmlSchemaCompareReplacedStrings(xmlSchemaValPtr x, xmlSchemaValPtr y)
3897{
3898 const xmlChar *utf1;
3899 const xmlChar *utf2;
3900 int tmp;
3901
3902 if ((x == NULL) || (y == NULL))
3903 return(-2);
3904 utf1 = x->value.str;
3905 utf2 = y->value.str;
3906
3907 while ((*utf1 != 0) && (*utf2 != 0)) {
3908 if (IS_WSP_SPACE_CH(*utf2) || IS_WSP_REPLACE_CH(*utf2)) {
3909 if (! (IS_WSP_SPACE_CH(*utf1) || IS_WSP_REPLACE_CH(*utf1))) {
3910 if ((*utf1 - 0x20) < 0)
3911 return(-1);
3912 else
3913 return(1);
3914 }
3915 } else {
3916 if (IS_WSP_SPACE_CH(*utf1) || IS_WSP_REPLACE_CH(*utf1)) {
3917 if ((0x20 - *utf2) < 0)
3918 return(-1);
3919 else
3920 return(1);
3921 }
3922 tmp = *utf1 - *utf2;
3923 if (tmp < 0)
3924 return(-1);
3925 if (tmp > 0)
3926 return(1);
3927 }
3928 utf1++;
3929 utf2++;
3930 }
3931 if (*utf1 != 0)
3932 return(1);
3933 if (*utf2 != 0)
3934 return(-1);
3935 return(0);
3936}
3937
3938/**
Daniel Veillardc4c21552003-03-29 10:53:38 +00003939 * xmlSchemaCompareNormStrings:
3940 * @x: a first string value
3941 * @y: a second string value
3942 *
3943 * Compare 2 string for their normalized values.
3944 *
3945 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
3946 * case of error
3947 */
3948static int
3949xmlSchemaCompareNormStrings(xmlSchemaValPtr x, xmlSchemaValPtr y) {
3950 const xmlChar *utf1;
3951 const xmlChar *utf2;
3952 int tmp;
3953
3954 if ((x == NULL) || (y == NULL))
3955 return(-2);
3956 utf1 = x->value.str;
3957 utf2 = y->value.str;
3958
William M. Brack76e95df2003-10-18 16:20:14 +00003959 while (IS_BLANK_CH(*utf1)) utf1++;
3960 while (IS_BLANK_CH(*utf2)) utf2++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003961 while ((*utf1 != 0) && (*utf2 != 0)) {
William M. Brack76e95df2003-10-18 16:20:14 +00003962 if (IS_BLANK_CH(*utf1)) {
3963 if (!IS_BLANK_CH(*utf2)) {
Daniel Veillardc4c21552003-03-29 10:53:38 +00003964 tmp = *utf1 - *utf2;
3965 return(tmp);
3966 }
William M. Brack76e95df2003-10-18 16:20:14 +00003967 while (IS_BLANK_CH(*utf1)) utf1++;
3968 while (IS_BLANK_CH(*utf2)) utf2++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003969 } else {
3970 tmp = *utf1++ - *utf2++;
3971 if (tmp < 0)
3972 return(-1);
3973 if (tmp > 0)
3974 return(1);
3975 }
3976 }
3977 if (*utf1 != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00003978 while (IS_BLANK_CH(*utf1)) utf1++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003979 if (*utf1 != 0)
3980 return(1);
3981 }
3982 if (*utf2 != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00003983 while (IS_BLANK_CH(*utf2)) utf2++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003984 if (*utf2 != 0)
3985 return(-1);
3986 }
3987 return(0);
3988}
3989
3990/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003991 * xmlSchemaCompareFloats:
3992 * @x: a first float or double value
3993 * @y: a second float or double value
3994 *
3995 * Compare 2 values
3996 *
3997 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3998 * case of error
3999 */
4000static int
4001xmlSchemaCompareFloats(xmlSchemaValPtr x, xmlSchemaValPtr y) {
4002 double d1, d2;
4003
4004 if ((x == NULL) || (y == NULL))
4005 return(-2);
4006
4007 /*
4008 * Cast everything to doubles.
4009 */
4010 if (x->type == XML_SCHEMAS_DOUBLE)
4011 d1 = x->value.d;
4012 else if (x->type == XML_SCHEMAS_FLOAT)
4013 d1 = x->value.f;
4014 else
4015 return(-2);
4016
4017 if (y->type == XML_SCHEMAS_DOUBLE)
4018 d2 = y->value.d;
4019 else if (y->type == XML_SCHEMAS_FLOAT)
4020 d2 = y->value.f;
4021 else
4022 return(-2);
4023
4024 /*
4025 * Check for special cases.
4026 */
4027 if (xmlXPathIsNaN(d1)) {
4028 if (xmlXPathIsNaN(d2))
4029 return(0);
4030 return(1);
4031 }
4032 if (xmlXPathIsNaN(d2))
4033 return(-1);
4034 if (d1 == xmlXPathPINF) {
4035 if (d2 == xmlXPathPINF)
4036 return(0);
4037 return(1);
4038 }
4039 if (d2 == xmlXPathPINF)
4040 return(-1);
4041 if (d1 == xmlXPathNINF) {
4042 if (d2 == xmlXPathNINF)
4043 return(0);
4044 return(-1);
4045 }
4046 if (d2 == xmlXPathNINF)
4047 return(1);
4048
4049 /*
4050 * basic tests, the last one we should have equality, but
4051 * portability is more important than speed and handling
4052 * NaN or Inf in a portable way is always a challenge, so ...
4053 */
4054 if (d1 < d2)
4055 return(-1);
4056 if (d1 > d2)
4057 return(1);
4058 if (d1 == d2)
4059 return(0);
4060 return(2);
4061}
4062
4063/**
Daniel Veillard4255d502002-04-16 15:50:10 +00004064 * xmlSchemaCompareValues:
4065 * @x: a first value
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004066 * @xwtsp: the whitespace type
Daniel Veillard4255d502002-04-16 15:50:10 +00004067 * @y: a second value
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004068 * @ywtsp: the whitespace type
Daniel Veillard4255d502002-04-16 15:50:10 +00004069 *
4070 * Compare 2 values
4071 *
Daniel Veillard5a872412002-05-22 06:40:27 +00004072 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
4073 * case of error
Daniel Veillard4255d502002-04-16 15:50:10 +00004074 */
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004075static int
4076xmlSchemaCompareValuesInternal(xmlSchemaValPtr x,
4077 xmlSchemaWhitespaceValueType xws,
4078 xmlSchemaValPtr y,
4079 xmlSchemaWhitespaceValueType yws) {
Daniel Veillard4255d502002-04-16 15:50:10 +00004080 if ((x == NULL) || (y == NULL))
4081 return(-2);
4082
4083 switch (x->type) {
Daniel Veillard80b19092003-03-28 13:29:53 +00004084 case XML_SCHEMAS_UNKNOWN:
William M. Brack2f2a6632004-08-20 23:09:47 +00004085 case XML_SCHEMAS_ANYTYPE:
Daniel Veillard80b19092003-03-28 13:29:53 +00004086 return(-2);
4087 case XML_SCHEMAS_INTEGER:
4088 case XML_SCHEMAS_NPINTEGER:
4089 case XML_SCHEMAS_NINTEGER:
4090 case XML_SCHEMAS_NNINTEGER:
4091 case XML_SCHEMAS_PINTEGER:
4092 case XML_SCHEMAS_INT:
4093 case XML_SCHEMAS_UINT:
4094 case XML_SCHEMAS_LONG:
4095 case XML_SCHEMAS_ULONG:
4096 case XML_SCHEMAS_SHORT:
4097 case XML_SCHEMAS_USHORT:
4098 case XML_SCHEMAS_BYTE:
4099 case XML_SCHEMAS_UBYTE:
Daniel Veillard4255d502002-04-16 15:50:10 +00004100 case XML_SCHEMAS_DECIMAL:
Daniel Veillard80b19092003-03-28 13:29:53 +00004101 if (y->type == x->type)
4102 return(xmlSchemaCompareDecimals(x, y));
4103 if ((y->type == XML_SCHEMAS_DECIMAL) ||
4104 (y->type == XML_SCHEMAS_INTEGER) ||
4105 (y->type == XML_SCHEMAS_NPINTEGER) ||
4106 (y->type == XML_SCHEMAS_NINTEGER) ||
4107 (y->type == XML_SCHEMAS_NNINTEGER) ||
4108 (y->type == XML_SCHEMAS_PINTEGER) ||
4109 (y->type == XML_SCHEMAS_INT) ||
4110 (y->type == XML_SCHEMAS_UINT) ||
4111 (y->type == XML_SCHEMAS_LONG) ||
4112 (y->type == XML_SCHEMAS_ULONG) ||
4113 (y->type == XML_SCHEMAS_SHORT) ||
4114 (y->type == XML_SCHEMAS_USHORT) ||
4115 (y->type == XML_SCHEMAS_BYTE) ||
4116 (y->type == XML_SCHEMAS_UBYTE))
Daniel Veillard4255d502002-04-16 15:50:10 +00004117 return(xmlSchemaCompareDecimals(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00004118 return(-2);
Daniel Veillard070803b2002-05-03 07:29:38 +00004119 case XML_SCHEMAS_DURATION:
4120 if (y->type == XML_SCHEMAS_DURATION)
4121 return(xmlSchemaCompareDurations(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00004122 return(-2);
4123 case XML_SCHEMAS_TIME:
4124 case XML_SCHEMAS_GDAY:
4125 case XML_SCHEMAS_GMONTH:
4126 case XML_SCHEMAS_GMONTHDAY:
4127 case XML_SCHEMAS_GYEAR:
4128 case XML_SCHEMAS_GYEARMONTH:
4129 case XML_SCHEMAS_DATE:
4130 case XML_SCHEMAS_DATETIME:
4131 if ((y->type == XML_SCHEMAS_DATETIME) ||
4132 (y->type == XML_SCHEMAS_TIME) ||
4133 (y->type == XML_SCHEMAS_GDAY) ||
4134 (y->type == XML_SCHEMAS_GMONTH) ||
4135 (y->type == XML_SCHEMAS_GMONTHDAY) ||
4136 (y->type == XML_SCHEMAS_GYEAR) ||
4137 (y->type == XML_SCHEMAS_DATE) ||
4138 (y->type == XML_SCHEMAS_GYEARMONTH))
4139 return (xmlSchemaCompareDates(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00004140 return (-2);
Kasimier T. Buchcik2ee855d2005-03-07 11:14:14 +00004141 /*
4142 * Note that we will support comparison of string types against
4143 * anySimpleType as well.
4144 */
4145 case XML_SCHEMAS_ANYSIMPLETYPE:
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004146 case XML_SCHEMAS_STRING:
4147 case XML_SCHEMAS_NORMSTRING:
Daniel Veillard80b19092003-03-28 13:29:53 +00004148 case XML_SCHEMAS_TOKEN:
4149 case XML_SCHEMAS_LANGUAGE:
4150 case XML_SCHEMAS_NMTOKEN:
Daniel Veillard80b19092003-03-28 13:29:53 +00004151 case XML_SCHEMAS_NAME:
Daniel Veillard80b19092003-03-28 13:29:53 +00004152 case XML_SCHEMAS_NCNAME:
4153 case XML_SCHEMAS_ID:
4154 case XML_SCHEMAS_IDREF:
Daniel Veillard80b19092003-03-28 13:29:53 +00004155 case XML_SCHEMAS_ENTITY:
Daniel Veillard80b19092003-03-28 13:29:53 +00004156 case XML_SCHEMAS_NOTATION:
4157 case XML_SCHEMAS_ANYURI:
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004158 /*
4159 * TODO: Compare those against QName.
4160 */
4161 if (y->type == XML_SCHEMAS_QNAME) {
4162 TODO
4163 return (-2);
4164 }
Kasimier T. Buchcik2ee855d2005-03-07 11:14:14 +00004165 if ((y->type == XML_SCHEMAS_ANYSIMPLETYPE) ||
4166 (y->type == XML_SCHEMAS_STRING) ||
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004167 (y->type == XML_SCHEMAS_NORMSTRING) ||
Daniel Veillardc4c21552003-03-29 10:53:38 +00004168 (y->type == XML_SCHEMAS_TOKEN) ||
4169 (y->type == XML_SCHEMAS_LANGUAGE) ||
4170 (y->type == XML_SCHEMAS_NMTOKEN) ||
4171 (y->type == XML_SCHEMAS_NAME) ||
Daniel Veillardc4c21552003-03-29 10:53:38 +00004172 (y->type == XML_SCHEMAS_NCNAME) ||
4173 (y->type == XML_SCHEMAS_ID) ||
4174 (y->type == XML_SCHEMAS_IDREF) ||
4175 (y->type == XML_SCHEMAS_ENTITY) ||
4176 (y->type == XML_SCHEMAS_NOTATION) ||
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004177 (y->type == XML_SCHEMAS_ANYURI)) {
4178
4179 if (xws == XML_SCHEMA_WHITESPACE_PRESERVE) {
4180
4181 if (yws == XML_SCHEMA_WHITESPACE_PRESERVE) {
4182 /* TODO: What about x < y or x > y. */
4183 if (xmlStrEqual(x->value.str, y->value.str))
4184 return (0);
4185 else
4186 return (2);
4187 } else if (yws == XML_SCHEMA_WHITESPACE_REPLACE)
4188 return (xmlSchemaComparePreserveReplaceStrings(x, y, 0));
4189 else if (yws == XML_SCHEMA_WHITESPACE_COLLAPSE)
4190 return (xmlSchemaComparePreserveCollapseStrings(x, y, 0));
4191
4192 } else if (xws == XML_SCHEMA_WHITESPACE_REPLACE) {
4193
4194 if (yws == XML_SCHEMA_WHITESPACE_PRESERVE)
4195 return (xmlSchemaComparePreserveReplaceStrings(y, x, 1));
4196 if (yws == XML_SCHEMA_WHITESPACE_REPLACE)
4197 return (xmlSchemaCompareReplacedStrings(x, y));
4198 if (yws == XML_SCHEMA_WHITESPACE_COLLAPSE)
4199 return (xmlSchemaCompareReplaceCollapseStrings(x, y, 0));
4200
4201 } else if (xws == XML_SCHEMA_WHITESPACE_COLLAPSE) {
4202
4203 if (yws == XML_SCHEMA_WHITESPACE_PRESERVE)
4204 return (xmlSchemaComparePreserveCollapseStrings(y, x, 1));
4205 if (yws == XML_SCHEMA_WHITESPACE_REPLACE)
4206 return (xmlSchemaCompareReplaceCollapseStrings(y, x, 1));
4207 if (yws == XML_SCHEMA_WHITESPACE_COLLAPSE)
4208 return (xmlSchemaCompareNormStrings(x, y));
4209 } else
4210 return (-2);
4211
4212 }
Daniel Veillardc4c21552003-03-29 10:53:38 +00004213 return (-2);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004214 case XML_SCHEMAS_QNAME:
4215 if (y->type == XML_SCHEMAS_QNAME) {
4216 if ((xmlStrEqual(x->value.qname.name, y->value.qname.name)) &&
4217 (xmlStrEqual(x->value.qname.uri, y->value.qname.uri)))
4218 return(0);
4219 return(2);
4220 }
4221 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00004222 case XML_SCHEMAS_FLOAT:
4223 case XML_SCHEMAS_DOUBLE:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00004224 if ((y->type == XML_SCHEMAS_FLOAT) ||
4225 (y->type == XML_SCHEMAS_DOUBLE))
4226 return (xmlSchemaCompareFloats(x, y));
4227 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00004228 case XML_SCHEMAS_BOOLEAN:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00004229 if (y->type == XML_SCHEMAS_BOOLEAN) {
4230 if (x->value.b == y->value.b)
4231 return(0);
4232 if (x->value.b == 0)
4233 return(-1);
4234 return(1);
4235 }
4236 return (-2);
Daniel Veillard560c2a42003-07-06 21:13:49 +00004237 case XML_SCHEMAS_HEXBINARY:
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004238 if (y->type == XML_SCHEMAS_HEXBINARY) {
4239 if (x->value.hex.total == y->value.hex.total) {
4240 int ret = xmlStrcmp(x->value.hex.str, y->value.hex.str);
4241 if (ret > 0)
4242 return(1);
4243 else if (ret == 0)
4244 return(0);
4245 }
4246 else if (x->value.hex.total > y->value.hex.total)
4247 return(1);
4248
4249 return(-1);
4250 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00004251 return (-2);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00004252 case XML_SCHEMAS_BASE64BINARY:
4253 if (y->type == XML_SCHEMAS_BASE64BINARY) {
4254 if (x->value.base64.total == y->value.base64.total) {
4255 int ret = xmlStrcmp(x->value.base64.str,
4256 y->value.base64.str);
4257 if (ret > 0)
4258 return(1);
4259 else if (ret == 0)
4260 return(0);
4261 }
4262 else if (x->value.base64.total > y->value.base64.total)
4263 return(1);
4264 else
4265 return(-1);
4266 }
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004267 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00004268 case XML_SCHEMAS_IDREFS:
4269 case XML_SCHEMAS_ENTITIES:
4270 case XML_SCHEMAS_NMTOKENS:
4271 TODO
4272 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00004273 }
Daniel Veillard5a872412002-05-22 06:40:27 +00004274 return -2;
Daniel Veillard4255d502002-04-16 15:50:10 +00004275}
4276
4277/**
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004278 * xmlSchemaCompareValues:
4279 * @x: a first value
4280 * @y: a second value
4281 *
4282 * Compare 2 values
4283 *
4284 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
4285 * case of error
4286 */
4287int
4288xmlSchemaCompareValues(xmlSchemaValPtr x, xmlSchemaValPtr y) {
4289 xmlSchemaWhitespaceValueType xws, yws;
4290
Daniel Veillard5e094142005-02-18 19:36:12 +00004291 if ((x == NULL) || (y == NULL))
4292 return(-2);
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004293 if (x->type == XML_SCHEMAS_STRING)
4294 xws = XML_SCHEMA_WHITESPACE_PRESERVE;
4295 else if (x->type == XML_SCHEMAS_NORMSTRING)
4296 xws = XML_SCHEMA_WHITESPACE_REPLACE;
4297 else
4298 xws = XML_SCHEMA_WHITESPACE_COLLAPSE;
4299
4300 if (y->type == XML_SCHEMAS_STRING)
4301 yws = XML_SCHEMA_WHITESPACE_PRESERVE;
4302 else if (x->type == XML_SCHEMAS_NORMSTRING)
4303 yws = XML_SCHEMA_WHITESPACE_REPLACE;
4304 else
4305 yws = XML_SCHEMA_WHITESPACE_COLLAPSE;
4306
4307 return(xmlSchemaCompareValuesInternal(x, xws, y, yws));
4308}
4309
4310/**
4311 * xmlSchemaCompareValuesWhtsp:
4312 * @x: a first value
4313 * @xws: the whitespace value of x
4314 * @y: a second value
4315 * @yws: the whitespace value of y
4316 *
4317 * Compare 2 values
4318 *
4319 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
4320 * case of error
4321 */
4322int
4323xmlSchemaCompareValuesWhtsp(xmlSchemaValPtr x,
4324 xmlSchemaWhitespaceValueType xws,
4325 xmlSchemaValPtr y,
4326 xmlSchemaWhitespaceValueType yws) {
4327 return(xmlSchemaCompareValuesInternal(x, xws, y, yws));
4328}
4329
4330/**
Daniel Veillardc4c21552003-03-29 10:53:38 +00004331 * xmlSchemaNormLen:
4332 * @value: a string
4333 *
4334 * Computes the UTF8 length of the normalized value of the string
4335 *
4336 * Returns the length or -1 in case of error.
4337 */
4338static int
4339xmlSchemaNormLen(const xmlChar *value) {
4340 const xmlChar *utf;
4341 int ret = 0;
4342
4343 if (value == NULL)
4344 return(-1);
4345 utf = value;
William M. Brack76e95df2003-10-18 16:20:14 +00004346 while (IS_BLANK_CH(*utf)) utf++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00004347 while (*utf != 0) {
4348 if (utf[0] & 0x80) {
4349 if ((utf[1] & 0xc0) != 0x80)
4350 return(-1);
4351 if ((utf[0] & 0xe0) == 0xe0) {
4352 if ((utf[2] & 0xc0) != 0x80)
4353 return(-1);
4354 if ((utf[0] & 0xf0) == 0xf0) {
4355 if ((utf[0] & 0xf8) != 0xf0 || (utf[3] & 0xc0) != 0x80)
4356 return(-1);
4357 utf += 4;
4358 } else {
4359 utf += 3;
4360 }
4361 } else {
4362 utf += 2;
4363 }
William M. Brack76e95df2003-10-18 16:20:14 +00004364 } else if (IS_BLANK_CH(*utf)) {
4365 while (IS_BLANK_CH(*utf)) utf++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00004366 if (*utf == 0)
4367 break;
4368 } else {
4369 utf++;
4370 }
4371 ret++;
4372 }
4373 return(ret);
4374}
4375
Daniel Veillard6927b102004-10-27 17:29:04 +00004376/**
4377 * xmlSchemaGetFacetValueAsULong:
4378 * @facet: an schemas type facet
4379 *
4380 * Extract the value of a facet
4381 *
4382 * Returns the value as a long
4383 */
Daniel Veillardc0826a72004-08-10 14:17:33 +00004384unsigned long
4385xmlSchemaGetFacetValueAsULong(xmlSchemaFacetPtr facet)
4386{
4387 /*
4388 * TODO: Check if this is a decimal.
4389 */
William M. Brack094dd862004-11-14 14:28:34 +00004390 if (facet == NULL)
4391 return 0;
Daniel Veillardc0826a72004-08-10 14:17:33 +00004392 return ((unsigned long) facet->val->value.decimal.lo);
4393}
4394
Daniel Veillardc4c21552003-03-29 10:53:38 +00004395/**
Daniel Veillard01fa6152004-06-29 17:04:39 +00004396 * xmlSchemaValidateListSimpleTypeFacet:
4397 * @facet: the facet to check
4398 * @value: the lexical repr of the value to validate
4399 * @actualLen: the number of list items
4400 * @expectedLen: the resulting expected number of list items
4401 *
4402 * Checks the value of a list simple type against a facet.
4403 *
4404 * Returns 0 if the value is valid, a positive error code
4405 * number otherwise and -1 in case of an internal error.
4406 */
4407int
4408xmlSchemaValidateListSimpleTypeFacet(xmlSchemaFacetPtr facet,
4409 const xmlChar *value,
4410 unsigned long actualLen,
4411 unsigned long *expectedLen)
4412{
Daniel Veillardce682bc2004-11-05 17:22:25 +00004413 if (facet == NULL)
4414 return(-1);
Daniel Veillard01fa6152004-06-29 17:04:39 +00004415 /*
4416 * TODO: Check if this will work with large numbers.
4417 * (compare value.decimal.mi and value.decimal.hi as well?).
4418 */
4419 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
4420 if (actualLen != facet->val->value.decimal.lo) {
Daniel Veillardc0826a72004-08-10 14:17:33 +00004421 if (expectedLen != 0)
4422 *expectedLen = facet->val->value.decimal.lo;
Daniel Veillard01fa6152004-06-29 17:04:39 +00004423 return (XML_SCHEMAV_CVC_LENGTH_VALID);
4424 }
4425 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
4426 if (actualLen < facet->val->value.decimal.lo) {
Daniel Veillardc0826a72004-08-10 14:17:33 +00004427 if (expectedLen != 0)
4428 *expectedLen = facet->val->value.decimal.lo;
Daniel Veillard01fa6152004-06-29 17:04:39 +00004429 return (XML_SCHEMAV_CVC_MINLENGTH_VALID);
4430 }
4431 } else if (facet->type == XML_SCHEMA_FACET_MAXLENGTH) {
4432 if (actualLen > facet->val->value.decimal.lo) {
Daniel Veillardc0826a72004-08-10 14:17:33 +00004433 if (expectedLen != 0)
4434 *expectedLen = facet->val->value.decimal.lo;
Daniel Veillard01fa6152004-06-29 17:04:39 +00004435 return (XML_SCHEMAV_CVC_MAXLENGTH_VALID);
4436 }
4437 } else
4438 /*
4439 * NOTE: That we can pass NULL as xmlSchemaValPtr to
4440 * xmlSchemaValidateFacet, since the remaining facet types
4441 * are: XML_SCHEMA_FACET_PATTERN, XML_SCHEMA_FACET_ENUMERATION.
4442 */
4443 return(xmlSchemaValidateFacet(NULL, facet, value, NULL));
4444 return (0);
4445}
4446
4447/**
Daniel Veillard6927b102004-10-27 17:29:04 +00004448 * xmlSchemaValidateLengthFacet:
Daniel Veillardc0826a72004-08-10 14:17:33 +00004449 * @type: the built-in type
4450 * @facet: the facet to check
4451 * @value: the lexical repr. of the value to be validated
4452 * @val: the precomputed value
4453 * @length: the actual length of the value
4454 *
4455 * Checka a value against a "length", "minLength" and "maxLength"
4456 * facet; sets @length to the computed length of @value.
4457 *
4458 * Returns 0 if the value is valid, a positive error code
4459 * otherwise and -1 in case of an internal or API error.
4460 */
4461int
4462xmlSchemaValidateLengthFacet(xmlSchemaTypePtr type,
4463 xmlSchemaFacetPtr facet,
4464 const xmlChar *value,
4465 xmlSchemaValPtr val,
4466 unsigned long *length)
4467{
4468 unsigned int len = 0;
4469
Daniel Veillardce682bc2004-11-05 17:22:25 +00004470 if ((length == NULL) || (facet == NULL) || (type == NULL))
4471 return (-1);
Daniel Veillardc0826a72004-08-10 14:17:33 +00004472 *length = 0;
4473 if ((facet->type != XML_SCHEMA_FACET_LENGTH) &&
4474 (facet->type != XML_SCHEMA_FACET_MAXLENGTH) &&
4475 (facet->type != XML_SCHEMA_FACET_MINLENGTH))
4476 return (-1);
4477
4478 if ((facet->val == NULL) ||
4479 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
4480 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
4481 (facet->val->value.decimal.frac != 0)) {
4482 return(-1);
4483 }
4484 if ((val != NULL) && (val->type == XML_SCHEMAS_HEXBINARY))
4485 len = val->value.hex.total;
4486 else if ((val != NULL) && (val->type == XML_SCHEMAS_BASE64BINARY))
4487 len = val->value.base64.total;
4488 else {
4489 switch (type->builtInType) {
4490 case XML_SCHEMAS_IDREF:
4491 case XML_SCHEMAS_NORMSTRING:
4492 case XML_SCHEMAS_TOKEN:
4493 case XML_SCHEMAS_LANGUAGE:
4494 case XML_SCHEMAS_NMTOKEN:
4495 case XML_SCHEMAS_NAME:
4496 case XML_SCHEMAS_NCNAME:
4497 case XML_SCHEMAS_ID:
4498 len = xmlSchemaNormLen(value);
4499 break;
4500 case XML_SCHEMAS_STRING:
4501 /*
4502 * FIXME: What exactly to do with anyURI?
4503 */
4504 case XML_SCHEMAS_ANYURI:
4505 if (value != NULL)
4506 len = xmlUTF8Strlen(value);
4507 break;
4508 default:
4509 TODO
4510 }
4511 }
4512 *length = (unsigned long) len;
4513 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
4514 if (len != facet->val->value.decimal.lo)
4515 return(XML_SCHEMAV_CVC_LENGTH_VALID);
4516 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
4517 if (len < facet->val->value.decimal.lo)
4518 return(XML_SCHEMAV_CVC_MINLENGTH_VALID);
4519 } else {
4520 if (len > facet->val->value.decimal.lo)
4521 return(XML_SCHEMAV_CVC_MAXLENGTH_VALID);
4522 }
4523
4524 return (0);
4525}
4526
4527/**
4528 * xmlSchemaValidateFacet:
Daniel Veillard01c13b52002-12-10 15:19:08 +00004529 * @base: the base type
Daniel Veillard4255d502002-04-16 15:50:10 +00004530 * @facet: the facet to check
4531 * @value: the lexical repr of the value to validate
4532 * @val: the precomputed value
4533 *
4534 * Check a value against a facet condition
4535 *
4536 * Returns 0 if the element is schemas valid, a positive error code
4537 * number otherwise and -1 in case of internal or API error.
4538 */
4539int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00004540xmlSchemaValidateFacet(xmlSchemaTypePtr base ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +00004541 xmlSchemaFacetPtr facet,
Daniel Veillard4255d502002-04-16 15:50:10 +00004542 const xmlChar *value, xmlSchemaValPtr val)
4543{
4544 int ret;
4545
Daniel Veillardce682bc2004-11-05 17:22:25 +00004546 if ((facet == NULL) || (value == NULL))
4547 return(-1);
Daniel Veillard4255d502002-04-16 15:50:10 +00004548 switch (facet->type) {
4549 case XML_SCHEMA_FACET_PATTERN:
4550 ret = xmlRegexpExec(facet->regexp, value);
4551 if (ret == 1)
4552 return(0);
4553 if (ret == 0) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00004554 return(XML_SCHEMAV_CVC_PATTERN_VALID);
Daniel Veillard4255d502002-04-16 15:50:10 +00004555 }
4556 return(ret);
4557 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
4558 ret = xmlSchemaCompareValues(val, facet->val);
4559 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004560 /* TODO error code */
Daniel Veillard4255d502002-04-16 15:50:10 +00004561 return(-1);
4562 }
4563 if (ret == -1)
4564 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00004565 /* error code */
Daniel Veillard01fa6152004-06-29 17:04:39 +00004566 return(XML_SCHEMAV_CVC_MAXEXCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00004567 case XML_SCHEMA_FACET_MAXINCLUSIVE:
4568 ret = xmlSchemaCompareValues(val, facet->val);
4569 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004570 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00004571 return(-1);
4572 }
4573 if ((ret == -1) || (ret == 0))
4574 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00004575 /* error code */
Daniel Veillard01fa6152004-06-29 17:04:39 +00004576 return(XML_SCHEMAV_CVC_MAXINCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00004577 case XML_SCHEMA_FACET_MINEXCLUSIVE:
4578 ret = xmlSchemaCompareValues(val, facet->val);
4579 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004580 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00004581 return(-1);
4582 }
4583 if (ret == 1)
4584 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00004585 /* error code */
Daniel Veillard01fa6152004-06-29 17:04:39 +00004586 return(XML_SCHEMAV_CVC_MINEXCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00004587 case XML_SCHEMA_FACET_MININCLUSIVE:
4588 ret = xmlSchemaCompareValues(val, facet->val);
4589 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004590 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00004591 return(-1);
4592 }
4593 if ((ret == 1) || (ret == 0))
4594 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00004595 /* error code */
Daniel Veillard01fa6152004-06-29 17:04:39 +00004596 return(XML_SCHEMAV_CVC_MININCLUSIVE_VALID);
Daniel Veillard8651f532002-04-17 09:06:27 +00004597 case XML_SCHEMA_FACET_WHITESPACE:
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004598 /* TODO whitespaces */
Daniel Veillard01fa6152004-06-29 17:04:39 +00004599 /*
4600 * NOTE: Whitespace should be handled to normalize
4601 * the value to be validated against a the facets;
4602 * not to normalize the value in-between.
4603 */
Daniel Veillard8651f532002-04-17 09:06:27 +00004604 return(0);
Daniel Veillard88c58912002-04-23 07:12:20 +00004605 case XML_SCHEMA_FACET_ENUMERATION:
4606 if ((facet->value != NULL) &&
4607 (xmlStrEqual(facet->value, value)))
4608 return(0);
Daniel Veillard01fa6152004-06-29 17:04:39 +00004609 return(XML_SCHEMAV_CVC_ENUMERATION_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004610 case XML_SCHEMA_FACET_LENGTH:
4611 case XML_SCHEMA_FACET_MAXLENGTH:
4612 case XML_SCHEMA_FACET_MINLENGTH: {
4613 unsigned int len = 0;
4614
4615 if ((facet->val == NULL) ||
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004616 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
4617 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004618 (facet->val->value.decimal.frac != 0)) {
4619 return(-1);
4620 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00004621 if ((val != NULL) && (val->type == XML_SCHEMAS_HEXBINARY))
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004622 len = val->value.hex.total;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00004623 else if ((val != NULL) && (val->type == XML_SCHEMAS_BASE64BINARY))
4624 len = val->value.base64.total;
4625 else {
Daniel Veillard01fa6152004-06-29 17:04:39 +00004626 switch (base->builtInType) {
Daniel Veillard560c2a42003-07-06 21:13:49 +00004627 case XML_SCHEMAS_IDREF:
4628 case XML_SCHEMAS_NORMSTRING:
4629 case XML_SCHEMAS_TOKEN:
4630 case XML_SCHEMAS_LANGUAGE:
4631 case XML_SCHEMAS_NMTOKEN:
4632 case XML_SCHEMAS_NAME:
4633 case XML_SCHEMAS_NCNAME:
4634 case XML_SCHEMAS_ID:
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004635 len = xmlSchemaNormLen(value);
4636 break;
Daniel Veillard560c2a42003-07-06 21:13:49 +00004637 case XML_SCHEMAS_STRING:
Daniel Veillard01fa6152004-06-29 17:04:39 +00004638 /*
4639 * FIXME: What exactly to do with anyURI?
4640 */
4641 case XML_SCHEMAS_ANYURI:
William M. Brackfbf2c5e2004-02-03 17:55:56 +00004642 if (value != NULL)
4643 len = xmlUTF8Strlen(value);
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004644 break;
Daniel Veillard560c2a42003-07-06 21:13:49 +00004645 default:
4646 TODO
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004647 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004648 }
4649 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004650 if (len != facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004651 return(XML_SCHEMAV_CVC_LENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004652 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004653 if (len < facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004654 return(XML_SCHEMAV_CVC_MINLENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004655 } else {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004656 if (len > facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004657 return(XML_SCHEMAV_CVC_MAXLENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004658 }
4659 break;
4660 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00004661 case XML_SCHEMA_FACET_TOTALDIGITS:
4662 case XML_SCHEMA_FACET_FRACTIONDIGITS:
4663
4664 if ((facet->val == NULL) ||
4665 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
4666 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
4667 (facet->val->value.decimal.frac != 0)) {
4668 return(-1);
4669 }
4670 if ((val == NULL) ||
4671 ((val->type != XML_SCHEMAS_DECIMAL) &&
4672 (val->type != XML_SCHEMAS_INTEGER) &&
4673 (val->type != XML_SCHEMAS_NPINTEGER) &&
4674 (val->type != XML_SCHEMAS_NINTEGER) &&
4675 (val->type != XML_SCHEMAS_NNINTEGER) &&
4676 (val->type != XML_SCHEMAS_PINTEGER) &&
4677 (val->type != XML_SCHEMAS_INT) &&
4678 (val->type != XML_SCHEMAS_UINT) &&
4679 (val->type != XML_SCHEMAS_LONG) &&
4680 (val->type != XML_SCHEMAS_ULONG) &&
4681 (val->type != XML_SCHEMAS_SHORT) &&
4682 (val->type != XML_SCHEMAS_USHORT) &&
4683 (val->type != XML_SCHEMAS_BYTE) &&
4684 (val->type != XML_SCHEMAS_UBYTE))) {
4685 return(-1);
4686 }
4687 if (facet->type == XML_SCHEMA_FACET_TOTALDIGITS) {
4688 if (val->value.decimal.total > facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004689 return(XML_SCHEMAV_CVC_TOTALDIGITS_VALID);
Daniel Veillard560c2a42003-07-06 21:13:49 +00004690
4691 } else if (facet->type == XML_SCHEMA_FACET_FRACTIONDIGITS) {
4692 if (val->value.decimal.frac > facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004693 return(XML_SCHEMAV_CVC_FRACTIONDIGITS_VALID);
Daniel Veillard560c2a42003-07-06 21:13:49 +00004694 }
4695 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00004696 default:
4697 TODO
4698 }
4699 return(0);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00004700
Daniel Veillard4255d502002-04-16 15:50:10 +00004701}
4702
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004703/**
4704 * xmlSchemaGetCanonValue:
4705 * @val: the precomputed value
4706 * @retValue: the returned value
4707 *
Daniel Veillardb5839c32005-02-19 18:27:14 +00004708 * Get a the cononical representation of the value.
4709 * The caller has to free the returned retValue.
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004710 *
4711 * Returns 0 if the value could be built and -1 in case of
4712 * API errors or if the value type is not supported yet.
4713 */
4714int
Daniel Veillardb5839c32005-02-19 18:27:14 +00004715xmlSchemaGetCanonValue(xmlSchemaValPtr val, const xmlChar **retValue)
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004716{
Daniel Veillardb5839c32005-02-19 18:27:14 +00004717 if ((retValue == NULL) || (val == NULL))
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004718 return (-1);
4719 *retValue = NULL;
4720 switch (val->type) {
4721 case XML_SCHEMAS_STRING:
4722 case XML_SCHEMAS_NORMSTRING:
4723 /*
4724 case XML_SCHEMAS_TOKEN:
4725 case XML_SCHEMAS_LANGUAGE:
4726 case XML_SCHEMAS_NMTOKEN:
4727 case XML_SCHEMAS_NAME:
4728 case XML_SCHEMAS_QNAME:
4729 case XML_SCHEMAS_NCNAME:
4730 case XML_SCHEMAS_ID:
4731 case XML_SCHEMAS_IDREF:
4732 case XML_SCHEMAS_ENTITY:
4733 case XML_SCHEMAS_NOTATION:
4734 case XML_SCHEMAS_ANYURI:
4735 */
4736 if (val->value.str == NULL)
4737 *retValue = NULL;
4738 else
4739 /* TODO: This is not yet correct for non-normalized values. */
4740 *retValue =
4741 BAD_CAST xmlStrdup((const xmlChar *) val->value.str);
4742 return (0);
4743 default:
4744 return (-1);
4745 }
4746 return (-1);
4747}
4748
Daniel Veillard4255d502002-04-16 15:50:10 +00004749#endif /* LIBXML_SCHEMAS_ENABLED */