blob: 6ee6a1ea80c960ce7f2cc2b914f45eef23a37190 [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
690 * of XML_SCHEMAS_STRING.
691 *
692 * Returns a pointer to the new value or NULL in case of error
693 */
694xmlSchemaValPtr
695xmlSchemaNewStringValue(xmlSchemaValType type,
696 const xmlChar *value)
697{
698 xmlSchemaValPtr val;
699
700 if (type != XML_SCHEMAS_STRING)
701 return(NULL);
702 val = (xmlSchemaValPtr) xmlMalloc(sizeof(xmlSchemaVal));
703 if (val == NULL) {
704 return(NULL);
705 }
706 memset(val, 0, sizeof(xmlSchemaVal));
707 val->type = type;
708 val->value.str = (xmlChar *) value;
709 return(val);
710}
711
Kasimier T. Buchcikb06b4de2005-02-17 19:00:23 +0000712/**
713 * xmlSchemaNewNOTATIONValue:
Daniel Veillardb5839c32005-02-19 18:27:14 +0000714 * @name: the notation name
715 * @ns: the notation namespace name or NULL
Kasimier T. Buchcikb06b4de2005-02-17 19:00:23 +0000716 *
717 * Allocate a new NOTATION value.
718 *
719 * Returns a pointer to the new value or NULL in case of error
720 */
721xmlSchemaValPtr
722xmlSchemaNewNOTATIONValue(const xmlChar *name,
723 const xmlChar *ns)
724{
725 xmlSchemaValPtr val;
726
727 val = xmlSchemaNewValue(XML_SCHEMAS_NOTATION);
728 if (val == NULL)
729 return (NULL);
730
William M. Brack12d37ab2005-02-21 13:54:07 +0000731 val->value.qname.name = (xmlChar *)name;
Kasimier T. Buchcikb06b4de2005-02-17 19:00:23 +0000732 if (ns != NULL)
William M. Brack12d37ab2005-02-21 13:54:07 +0000733 val->value.qname.uri = (xmlChar *)ns;
Kasimier T. Buchcikb06b4de2005-02-17 19:00:23 +0000734 return(val);
735}
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +0000736
737/**
Daniel Veillard4255d502002-04-16 15:50:10 +0000738 * xmlSchemaFreeValue:
739 * @value: the value to free
740 *
741 * Cleanup the default XML Schemas type library
742 */
743void
744xmlSchemaFreeValue(xmlSchemaValPtr value) {
745 if (value == NULL)
746 return;
Daniel Veillardc4c21552003-03-29 10:53:38 +0000747 switch (value->type) {
748 case XML_SCHEMAS_STRING:
749 case XML_SCHEMAS_NORMSTRING:
750 case XML_SCHEMAS_TOKEN:
751 case XML_SCHEMAS_LANGUAGE:
752 case XML_SCHEMAS_NMTOKEN:
753 case XML_SCHEMAS_NMTOKENS:
754 case XML_SCHEMAS_NAME:
Daniel Veillardc4c21552003-03-29 10:53:38 +0000755 case XML_SCHEMAS_NCNAME:
756 case XML_SCHEMAS_ID:
757 case XML_SCHEMAS_IDREF:
758 case XML_SCHEMAS_IDREFS:
759 case XML_SCHEMAS_ENTITY:
Kasimier T. Buchcikb06b4de2005-02-17 19:00:23 +0000760 case XML_SCHEMAS_ENTITIES:
Daniel Veillardc4c21552003-03-29 10:53:38 +0000761 case XML_SCHEMAS_ANYURI:
762 if (value->value.str != NULL)
763 xmlFree(value->value.str);
764 break;
Kasimier T. Buchcikb06b4de2005-02-17 19:00:23 +0000765 case XML_SCHEMAS_NOTATION:
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000766 case XML_SCHEMAS_QNAME:
767 if (value->value.qname.uri != NULL)
768 xmlFree(value->value.qname.uri);
769 if (value->value.qname.name != NULL)
770 xmlFree(value->value.qname.name);
771 break;
Daniel Veillard70bcb0e2003-08-08 14:00:28 +0000772 case XML_SCHEMAS_HEXBINARY:
773 if (value->value.hex.str != NULL)
774 xmlFree(value->value.hex.str);
775 break;
Daniel Veillard1ac24d32003-08-27 14:15:15 +0000776 case XML_SCHEMAS_BASE64BINARY:
777 if (value->value.base64.str != NULL)
778 xmlFree(value->value.base64.str);
779 break;
Daniel Veillardc4c21552003-03-29 10:53:38 +0000780 default:
781 break;
782 }
Daniel Veillard4255d502002-04-16 15:50:10 +0000783 xmlFree(value);
784}
785
786/**
787 * xmlSchemaGetPredefinedType:
788 * @name: the type name
789 * @ns: the URI of the namespace usually "http://www.w3.org/2001/XMLSchema"
790 *
791 * Lookup a type in the default XML Schemas type library
792 *
793 * Returns the type if found, NULL otherwise
794 */
795xmlSchemaTypePtr
796xmlSchemaGetPredefinedType(const xmlChar *name, const xmlChar *ns) {
797 if (xmlSchemaTypesInitialized == 0)
798 xmlSchemaInitTypes();
799 if (name == NULL)
800 return(NULL);
801 return((xmlSchemaTypePtr) xmlHashLookup2(xmlSchemaTypesBank, name, ns));
802}
Daniel Veillard070803b2002-05-03 07:29:38 +0000803
Daniel Veillard01fa6152004-06-29 17:04:39 +0000804/**
805 * xmlSchemaGetBuiltInListSimpleTypeItemType:
806 * @type: the built-in simple type.
807 *
Daniel Veillard6927b102004-10-27 17:29:04 +0000808 * Lookup function
809 *
Daniel Veillardc0826a72004-08-10 14:17:33 +0000810 * Returns the item type of @type as defined by the built-in datatype
811 * hierarchy of XML Schema Part 2: Datatypes, or NULL in case of an error.
Daniel Veillard01fa6152004-06-29 17:04:39 +0000812 */
813xmlSchemaTypePtr
814xmlSchemaGetBuiltInListSimpleTypeItemType(xmlSchemaTypePtr type)
815{
Daniel Veillard42595322004-11-08 10:52:06 +0000816 if ((type == NULL) || (type->type != XML_SCHEMA_TYPE_BASIC))
Daniel Veillard01fa6152004-06-29 17:04:39 +0000817 return (NULL);
818 switch (type->builtInType) {
819 case XML_SCHEMAS_NMTOKENS:
820 return (xmlSchemaTypeNmtokenDef );
821 case XML_SCHEMAS_IDREFS:
822 return (xmlSchemaTypeIdrefDef);
823 case XML_SCHEMAS_ENTITIES:
824 return (xmlSchemaTypeEntityDef);
825 default:
826 return (NULL);
827 }
828}
829
Daniel Veillard070803b2002-05-03 07:29:38 +0000830/****************************************************************
831 * *
832 * Convenience macros and functions *
833 * *
834 ****************************************************************/
835
836#define IS_TZO_CHAR(c) \
837 ((c == 0) || (c == 'Z') || (c == '+') || (c == '-'))
838
839#define VALID_YEAR(yr) (yr != 0)
840#define VALID_MONTH(mon) ((mon >= 1) && (mon <= 12))
841/* VALID_DAY should only be used when month is unknown */
842#define VALID_DAY(day) ((day >= 1) && (day <= 31))
843#define VALID_HOUR(hr) ((hr >= 0) && (hr <= 23))
844#define VALID_MIN(min) ((min >= 0) && (min <= 59))
845#define VALID_SEC(sec) ((sec >= 0) && (sec < 60))
846#define VALID_TZO(tzo) ((tzo > -1440) && (tzo < 1440))
847#define IS_LEAP(y) \
848 (((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0))
849
Daniel Veillardebe25d42004-03-25 09:35:49 +0000850static const unsigned int daysInMonth[12] =
Daniel Veillard070803b2002-05-03 07:29:38 +0000851 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
Daniel Veillardebe25d42004-03-25 09:35:49 +0000852static const unsigned int daysInMonthLeap[12] =
Daniel Veillard070803b2002-05-03 07:29:38 +0000853 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
854
Daniel Veillard5a872412002-05-22 06:40:27 +0000855#define MAX_DAYINMONTH(yr,mon) \
856 (IS_LEAP(yr) ? daysInMonthLeap[mon - 1] : daysInMonth[mon - 1])
857
Daniel Veillard070803b2002-05-03 07:29:38 +0000858#define VALID_MDAY(dt) \
859 (IS_LEAP(dt->year) ? \
860 (dt->day <= daysInMonthLeap[dt->mon - 1]) : \
861 (dt->day <= daysInMonth[dt->mon - 1]))
862
863#define VALID_DATE(dt) \
864 (VALID_YEAR(dt->year) && VALID_MONTH(dt->mon) && VALID_MDAY(dt))
865
866#define VALID_TIME(dt) \
867 (VALID_HOUR(dt->hour) && VALID_MIN(dt->min) && \
868 VALID_SEC(dt->sec) && VALID_TZO(dt->tzo))
869
870#define VALID_DATETIME(dt) \
871 (VALID_DATE(dt) && VALID_TIME(dt))
872
873#define SECS_PER_MIN (60)
874#define SECS_PER_HOUR (60 * SECS_PER_MIN)
875#define SECS_PER_DAY (24 * SECS_PER_HOUR)
876
Daniel Veillard5a872412002-05-22 06:40:27 +0000877static const long dayInYearByMonth[12] =
878 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
879static const long dayInLeapYearByMonth[12] =
880 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 };
881
882#define DAY_IN_YEAR(day, month, year) \
883 ((IS_LEAP(year) ? \
884 dayInLeapYearByMonth[month - 1] : \
885 dayInYearByMonth[month - 1]) + day)
886
887#ifdef DEBUG
888#define DEBUG_DATE(dt) \
889 xmlGenericError(xmlGenericErrorContext, \
890 "type=%o %04ld-%02u-%02uT%02u:%02u:%03f", \
891 dt->type,dt->value.date.year,dt->value.date.mon, \
892 dt->value.date.day,dt->value.date.hour,dt->value.date.min, \
893 dt->value.date.sec); \
894 if (dt->value.date.tz_flag) \
895 if (dt->value.date.tzo != 0) \
896 xmlGenericError(xmlGenericErrorContext, \
897 "%+05d\n",dt->value.date.tzo); \
898 else \
899 xmlGenericError(xmlGenericErrorContext, "Z\n"); \
900 else \
901 xmlGenericError(xmlGenericErrorContext,"\n")
902#else
903#define DEBUG_DATE(dt)
904#endif
905
Daniel Veillard070803b2002-05-03 07:29:38 +0000906/**
907 * _xmlSchemaParseGYear:
908 * @dt: pointer to a date structure
909 * @str: pointer to the string to analyze
910 *
911 * Parses a xs:gYear without time zone and fills in the appropriate
912 * field of the @dt structure. @str is updated to point just after the
913 * xs:gYear. It is supposed that @dt->year is big enough to contain
914 * the year.
915 *
916 * Returns 0 or the error code
917 */
918static int
919_xmlSchemaParseGYear (xmlSchemaValDatePtr dt, const xmlChar **str) {
920 const xmlChar *cur = *str, *firstChar;
921 int isneg = 0, digcnt = 0;
922
923 if (((*cur < '0') || (*cur > '9')) &&
924 (*cur != '-') && (*cur != '+'))
925 return -1;
926
927 if (*cur == '-') {
928 isneg = 1;
929 cur++;
930 }
931
932 firstChar = cur;
933
934 while ((*cur >= '0') && (*cur <= '9')) {
935 dt->year = dt->year * 10 + (*cur - '0');
936 cur++;
937 digcnt++;
938 }
939
940 /* year must be at least 4 digits (CCYY); over 4
941 * digits cannot have a leading zero. */
942 if ((digcnt < 4) || ((digcnt > 4) && (*firstChar == '0')))
943 return 1;
944
945 if (isneg)
946 dt->year = - dt->year;
947
948 if (!VALID_YEAR(dt->year))
949 return 2;
950
951 *str = cur;
952 return 0;
953}
954
955/**
956 * PARSE_2_DIGITS:
957 * @num: the integer to fill in
958 * @cur: an #xmlChar *
959 * @invalid: an integer
960 *
961 * Parses a 2-digits integer and updates @num with the value. @cur is
962 * updated to point just after the integer.
963 * In case of error, @invalid is set to %TRUE, values of @num and
964 * @cur are undefined.
965 */
966#define PARSE_2_DIGITS(num, cur, invalid) \
967 if ((cur[0] < '0') || (cur[0] > '9') || \
968 (cur[1] < '0') || (cur[1] > '9')) \
969 invalid = 1; \
970 else \
971 num = (cur[0] - '0') * 10 + (cur[1] - '0'); \
972 cur += 2;
973
974/**
975 * PARSE_FLOAT:
976 * @num: the double to fill in
977 * @cur: an #xmlChar *
978 * @invalid: an integer
979 *
980 * Parses a float and updates @num with the value. @cur is
981 * updated to point just after the float. The float must have a
982 * 2-digits integer part and may or may not have a decimal part.
983 * In case of error, @invalid is set to %TRUE, values of @num and
984 * @cur are undefined.
985 */
986#define PARSE_FLOAT(num, cur, invalid) \
987 PARSE_2_DIGITS(num, cur, invalid); \
988 if (!invalid && (*cur == '.')) { \
989 double mult = 1; \
990 cur++; \
991 if ((*cur < '0') || (*cur > '9')) \
992 invalid = 1; \
993 while ((*cur >= '0') && (*cur <= '9')) { \
994 mult /= 10; \
995 num += (*cur - '0') * mult; \
996 cur++; \
997 } \
998 }
999
1000/**
1001 * _xmlSchemaParseGMonth:
1002 * @dt: pointer to a date structure
1003 * @str: pointer to the string to analyze
1004 *
1005 * Parses a xs:gMonth without time zone and fills in the appropriate
1006 * field of the @dt structure. @str is updated to point just after the
1007 * xs:gMonth.
1008 *
1009 * Returns 0 or the error code
1010 */
1011static int
1012_xmlSchemaParseGMonth (xmlSchemaValDatePtr dt, const xmlChar **str) {
1013 const xmlChar *cur = *str;
1014 int ret = 0;
1015
1016 PARSE_2_DIGITS(dt->mon, cur, ret);
1017 if (ret != 0)
1018 return ret;
1019
1020 if (!VALID_MONTH(dt->mon))
1021 return 2;
1022
1023 *str = cur;
1024 return 0;
1025}
1026
1027/**
1028 * _xmlSchemaParseGDay:
1029 * @dt: pointer to a date structure
1030 * @str: pointer to the string to analyze
1031 *
1032 * Parses a xs:gDay without time zone and fills in the appropriate
1033 * field of the @dt structure. @str is updated to point just after the
1034 * xs:gDay.
1035 *
1036 * Returns 0 or the error code
1037 */
1038static int
1039_xmlSchemaParseGDay (xmlSchemaValDatePtr dt, const xmlChar **str) {
1040 const xmlChar *cur = *str;
1041 int ret = 0;
1042
1043 PARSE_2_DIGITS(dt->day, cur, ret);
1044 if (ret != 0)
1045 return ret;
1046
1047 if (!VALID_DAY(dt->day))
1048 return 2;
1049
1050 *str = cur;
1051 return 0;
1052}
1053
1054/**
1055 * _xmlSchemaParseTime:
1056 * @dt: pointer to a date structure
1057 * @str: pointer to the string to analyze
1058 *
1059 * Parses a xs:time without time zone and fills in the appropriate
1060 * fields of the @dt structure. @str is updated to point just after the
1061 * xs:time.
1062 * In case of error, values of @dt fields are undefined.
1063 *
1064 * Returns 0 or the error code
1065 */
1066static int
1067_xmlSchemaParseTime (xmlSchemaValDatePtr dt, const xmlChar **str) {
1068 const xmlChar *cur = *str;
1069 unsigned int hour = 0; /* use temp var in case str is not xs:time */
1070 int ret = 0;
1071
1072 PARSE_2_DIGITS(hour, cur, ret);
1073 if (ret != 0)
1074 return ret;
1075
1076 if (*cur != ':')
1077 return 1;
1078 cur++;
1079
1080 /* the ':' insures this string is xs:time */
1081 dt->hour = hour;
1082
1083 PARSE_2_DIGITS(dt->min, cur, ret);
1084 if (ret != 0)
1085 return ret;
1086
1087 if (*cur != ':')
1088 return 1;
1089 cur++;
1090
1091 PARSE_FLOAT(dt->sec, cur, ret);
1092 if (ret != 0)
1093 return ret;
1094
1095 if (!VALID_TIME(dt))
1096 return 2;
1097
1098 *str = cur;
1099 return 0;
1100}
1101
1102/**
1103 * _xmlSchemaParseTimeZone:
1104 * @dt: pointer to a date structure
1105 * @str: pointer to the string to analyze
1106 *
1107 * Parses a time zone without time zone and fills in the appropriate
1108 * field of the @dt structure. @str is updated to point just after the
1109 * time zone.
1110 *
1111 * Returns 0 or the error code
1112 */
1113static int
1114_xmlSchemaParseTimeZone (xmlSchemaValDatePtr dt, const xmlChar **str) {
1115 const xmlChar *cur = *str;
1116 int ret = 0;
1117
1118 if (str == NULL)
1119 return -1;
1120
1121 switch (*cur) {
1122 case 0:
1123 dt->tz_flag = 0;
1124 dt->tzo = 0;
1125 break;
1126
1127 case 'Z':
1128 dt->tz_flag = 1;
1129 dt->tzo = 0;
1130 cur++;
1131 break;
1132
1133 case '+':
1134 case '-': {
1135 int isneg = 0, tmp = 0;
1136 isneg = (*cur == '-');
1137
1138 cur++;
1139
1140 PARSE_2_DIGITS(tmp, cur, ret);
1141 if (ret != 0)
1142 return ret;
1143 if (!VALID_HOUR(tmp))
1144 return 2;
1145
1146 if (*cur != ':')
1147 return 1;
1148 cur++;
1149
1150 dt->tzo = tmp * 60;
1151
1152 PARSE_2_DIGITS(tmp, cur, ret);
1153 if (ret != 0)
1154 return ret;
1155 if (!VALID_MIN(tmp))
1156 return 2;
1157
1158 dt->tzo += tmp;
1159 if (isneg)
1160 dt->tzo = - dt->tzo;
1161
1162 if (!VALID_TZO(dt->tzo))
1163 return 2;
1164
Daniel Veillard5a872412002-05-22 06:40:27 +00001165 dt->tz_flag = 1;
Daniel Veillard070803b2002-05-03 07:29:38 +00001166 break;
1167 }
1168 default:
1169 return 1;
1170 }
1171
1172 *str = cur;
1173 return 0;
1174}
1175
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001176/**
1177 * _xmlSchemaBase64Decode:
1178 * @ch: a character
1179 *
1180 * Converts a base64 encoded character to its base 64 value.
1181 *
1182 * Returns 0-63 (value), 64 (pad), or -1 (not recognized)
1183 */
1184static int
1185_xmlSchemaBase64Decode (const xmlChar ch) {
1186 if (('A' <= ch) && (ch <= 'Z')) return ch - 'A';
1187 if (('a' <= ch) && (ch <= 'z')) return ch - 'a' + 26;
1188 if (('0' <= ch) && (ch <= '9')) return ch - '0' + 52;
1189 if ('+' == ch) return 62;
1190 if ('/' == ch) return 63;
1191 if ('=' == ch) return 64;
1192 return -1;
1193}
1194
Daniel Veillard070803b2002-05-03 07:29:38 +00001195/****************************************************************
1196 * *
1197 * XML Schema Dates/Times Datatypes Handling *
1198 * *
1199 ****************************************************************/
1200
1201/**
1202 * PARSE_DIGITS:
1203 * @num: the integer to fill in
1204 * @cur: an #xmlChar *
1205 * @num_type: an integer flag
1206 *
1207 * Parses a digits integer and updates @num with the value. @cur is
1208 * updated to point just after the integer.
1209 * In case of error, @num_type is set to -1, values of @num and
1210 * @cur are undefined.
1211 */
1212#define PARSE_DIGITS(num, cur, num_type) \
1213 if ((*cur < '0') || (*cur > '9')) \
1214 num_type = -1; \
1215 else \
1216 while ((*cur >= '0') && (*cur <= '9')) { \
1217 num = num * 10 + (*cur - '0'); \
1218 cur++; \
1219 }
1220
1221/**
1222 * PARSE_NUM:
1223 * @num: the double to fill in
1224 * @cur: an #xmlChar *
1225 * @num_type: an integer flag
1226 *
1227 * Parses a float or integer and updates @num with the value. @cur is
1228 * updated to point just after the number. If the number is a float,
1229 * then it must have an integer part and a decimal part; @num_type will
1230 * be set to 1. If there is no decimal part, @num_type is set to zero.
1231 * In case of error, @num_type is set to -1, values of @num and
1232 * @cur are undefined.
1233 */
1234#define PARSE_NUM(num, cur, num_type) \
1235 num = 0; \
1236 PARSE_DIGITS(num, cur, num_type); \
1237 if (!num_type && (*cur == '.')) { \
1238 double mult = 1; \
1239 cur++; \
1240 if ((*cur < '0') || (*cur > '9')) \
1241 num_type = -1; \
1242 else \
1243 num_type = 1; \
1244 while ((*cur >= '0') && (*cur <= '9')) { \
1245 mult /= 10; \
1246 num += (*cur - '0') * mult; \
1247 cur++; \
1248 } \
1249 }
1250
1251/**
Daniel Veillard5a872412002-05-22 06:40:27 +00001252 * xmlSchemaValidateDates:
Daniel Veillard455cc072003-03-31 10:13:23 +00001253 * @type: the expected type or XML_SCHEMAS_UNKNOWN
Daniel Veillard070803b2002-05-03 07:29:38 +00001254 * @dateTime: string to analyze
1255 * @val: the return computed value
1256 *
1257 * Check that @dateTime conforms to the lexical space of one of the date types.
1258 * if true a value is computed and returned in @val.
1259 *
1260 * Returns 0 if this validates, a positive error code number otherwise
1261 * and -1 in case of internal or API error.
1262 */
1263static int
Daniel Veillard455cc072003-03-31 10:13:23 +00001264xmlSchemaValidateDates (xmlSchemaValType type,
Daniel Veillard118aed72002-09-24 14:13:13 +00001265 const xmlChar *dateTime, xmlSchemaValPtr *val) {
Daniel Veillard070803b2002-05-03 07:29:38 +00001266 xmlSchemaValPtr dt;
1267 int ret;
1268 const xmlChar *cur = dateTime;
1269
1270#define RETURN_TYPE_IF_VALID(t) \
1271 if (IS_TZO_CHAR(*cur)) { \
1272 ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur); \
1273 if (ret == 0) { \
1274 if (*cur != 0) \
1275 goto error; \
1276 dt->type = t; \
Daniel Veillard455cc072003-03-31 10:13:23 +00001277 goto done; \
Daniel Veillard070803b2002-05-03 07:29:38 +00001278 } \
1279 }
1280
1281 if (dateTime == NULL)
1282 return -1;
1283
1284 if ((*cur != '-') && (*cur < '0') && (*cur > '9'))
1285 return 1;
1286
1287 dt = xmlSchemaNewValue(XML_SCHEMAS_UNKNOWN);
1288 if (dt == NULL)
1289 return -1;
1290
1291 if ((cur[0] == '-') && (cur[1] == '-')) {
1292 /*
1293 * It's an incomplete date (xs:gMonthDay, xs:gMonth or
1294 * xs:gDay)
1295 */
1296 cur += 2;
1297
1298 /* is it an xs:gDay? */
1299 if (*cur == '-') {
Daniel Veillard455cc072003-03-31 10:13:23 +00001300 if (type == XML_SCHEMAS_GMONTH)
1301 goto error;
Daniel Veillard070803b2002-05-03 07:29:38 +00001302 ++cur;
1303 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
1304 if (ret != 0)
1305 goto error;
1306
1307 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GDAY);
1308
1309 goto error;
1310 }
1311
1312 /*
1313 * it should be an xs:gMonthDay or xs:gMonth
1314 */
1315 ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
1316 if (ret != 0)
1317 goto error;
1318
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001319 /*
1320 * a '-' char could indicate this type is xs:gMonthDay or
1321 * a negative time zone offset. Check for xs:gMonthDay first.
1322 * Also the first three char's of a negative tzo (-MM:SS) can
1323 * appear to be a valid day; so even if the day portion
1324 * of the xs:gMonthDay verifies, we must insure it was not
1325 * a tzo.
1326 */
1327 if (*cur == '-') {
1328 const xmlChar *rewnd = cur;
1329 cur++;
Daniel Veillard070803b2002-05-03 07:29:38 +00001330
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001331 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
1332 if ((ret == 0) && ((*cur == 0) || (*cur != ':'))) {
1333
1334 /*
1335 * we can use the VALID_MDAY macro to validate the month
1336 * and day because the leap year test will flag year zero
1337 * as a leap year (even though zero is an invalid year).
1338 */
1339 if (VALID_MDAY((&(dt->value.date)))) {
1340
1341 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTHDAY);
1342
1343 goto error;
1344 }
1345 }
1346
1347 /*
1348 * not xs:gMonthDay so rewind and check if just xs:gMonth
1349 * with an optional time zone.
1350 */
1351 cur = rewnd;
1352 }
1353
1354 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTH);
Daniel Veillard070803b2002-05-03 07:29:38 +00001355
1356 goto error;
1357 }
1358
1359 /*
1360 * It's a right-truncated date or an xs:time.
1361 * Try to parse an xs:time then fallback on right-truncated dates.
1362 */
1363 if ((*cur >= '0') && (*cur <= '9')) {
1364 ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
1365 if (ret == 0) {
1366 /* it's an xs:time */
1367 RETURN_TYPE_IF_VALID(XML_SCHEMAS_TIME);
1368 }
1369 }
1370
1371 /* fallback on date parsing */
1372 cur = dateTime;
1373
1374 ret = _xmlSchemaParseGYear(&(dt->value.date), &cur);
1375 if (ret != 0)
1376 goto error;
1377
1378 /* is it an xs:gYear? */
1379 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEAR);
1380
1381 if (*cur != '-')
1382 goto error;
1383 cur++;
1384
1385 ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
1386 if (ret != 0)
1387 goto error;
1388
1389 /* is it an xs:gYearMonth? */
1390 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEARMONTH);
1391
1392 if (*cur != '-')
1393 goto error;
1394 cur++;
1395
1396 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
1397 if ((ret != 0) || !VALID_DATE((&(dt->value.date))))
1398 goto error;
1399
1400 /* is it an xs:date? */
1401 RETURN_TYPE_IF_VALID(XML_SCHEMAS_DATE);
1402
1403 if (*cur != 'T')
1404 goto error;
1405 cur++;
1406
1407 /* it should be an xs:dateTime */
1408 ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
1409 if (ret != 0)
1410 goto error;
1411
1412 ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur);
1413 if ((ret != 0) || (*cur != 0) || !VALID_DATETIME((&(dt->value.date))))
1414 goto error;
1415
Daniel Veillard455cc072003-03-31 10:13:23 +00001416
Daniel Veillard070803b2002-05-03 07:29:38 +00001417 dt->type = XML_SCHEMAS_DATETIME;
1418
Daniel Veillard455cc072003-03-31 10:13:23 +00001419done:
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001420#if 1
1421 if ((type != XML_SCHEMAS_UNKNOWN) && (type != dt->type))
1422 goto error;
1423#else
1424 /*
1425 * insure the parsed type is equal to or less significant (right
1426 * truncated) than the desired type.
1427 */
1428 if ((type != XML_SCHEMAS_UNKNOWN) && (type != dt->type)) {
1429
1430 /* time only matches time */
1431 if ((type == XML_SCHEMAS_TIME) && (dt->type == XML_SCHEMAS_TIME))
1432 goto error;
1433
1434 if ((type == XML_SCHEMAS_DATETIME) &&
1435 ((dt->type != XML_SCHEMAS_DATE) ||
1436 (dt->type != XML_SCHEMAS_GYEARMONTH) ||
1437 (dt->type != XML_SCHEMAS_GYEAR)))
1438 goto error;
1439
1440 if ((type == XML_SCHEMAS_DATE) &&
1441 ((dt->type != XML_SCHEMAS_GYEAR) ||
1442 (dt->type != XML_SCHEMAS_GYEARMONTH)))
1443 goto error;
1444
1445 if ((type == XML_SCHEMAS_GYEARMONTH) && (dt->type != XML_SCHEMAS_GYEAR))
1446 goto error;
1447
1448 if ((type == XML_SCHEMAS_GMONTHDAY) && (dt->type != XML_SCHEMAS_GMONTH))
1449 goto error;
1450 }
Daniel Veillard455cc072003-03-31 10:13:23 +00001451#endif
1452
Daniel Veillard070803b2002-05-03 07:29:38 +00001453 if (val != NULL)
1454 *val = dt;
Daniel Veillard80b19092003-03-28 13:29:53 +00001455 else
1456 xmlSchemaFreeValue(dt);
Daniel Veillard070803b2002-05-03 07:29:38 +00001457
1458 return 0;
1459
1460error:
1461 if (dt != NULL)
1462 xmlSchemaFreeValue(dt);
1463 return 1;
1464}
1465
1466/**
Daniel Veillard5a872412002-05-22 06:40:27 +00001467 * xmlSchemaValidateDuration:
Daniel Veillard070803b2002-05-03 07:29:38 +00001468 * @type: the predefined type
1469 * @duration: string to analyze
1470 * @val: the return computed value
1471 *
1472 * Check that @duration conforms to the lexical space of the duration type.
1473 * if true a value is computed and returned in @val.
1474 *
1475 * Returns 0 if this validates, a positive error code number otherwise
1476 * and -1 in case of internal or API error.
1477 */
1478static int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00001479xmlSchemaValidateDuration (xmlSchemaTypePtr type ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +00001480 const xmlChar *duration, xmlSchemaValPtr *val) {
Daniel Veillard070803b2002-05-03 07:29:38 +00001481 const xmlChar *cur = duration;
1482 xmlSchemaValPtr dur;
1483 int isneg = 0;
1484 unsigned int seq = 0;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001485 double num;
1486 int num_type = 0; /* -1 = invalid, 0 = int, 1 = floating */
1487 const xmlChar desig[] = {'Y', 'M', 'D', 'H', 'M', 'S'};
1488 const double multi[] = { 0.0, 0.0, 86400.0, 3600.0, 60.0, 1.0, 0.0};
Daniel Veillard070803b2002-05-03 07:29:38 +00001489
1490 if (duration == NULL)
1491 return -1;
1492
1493 if (*cur == '-') {
1494 isneg = 1;
1495 cur++;
1496 }
1497
1498 /* duration must start with 'P' (after sign) */
1499 if (*cur++ != 'P')
1500 return 1;
1501
Daniel Veillard80b19092003-03-28 13:29:53 +00001502 if (*cur == 0)
1503 return 1;
1504
Daniel Veillard070803b2002-05-03 07:29:38 +00001505 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
1506 if (dur == NULL)
1507 return -1;
1508
1509 while (*cur != 0) {
Daniel Veillard070803b2002-05-03 07:29:38 +00001510
1511 /* input string should be empty or invalid date/time item */
1512 if (seq >= sizeof(desig))
1513 goto error;
1514
1515 /* T designator must be present for time items */
1516 if (*cur == 'T') {
1517 if (seq <= 3) {
1518 seq = 3;
1519 cur++;
1520 } else
1521 return 1;
1522 } else if (seq == 3)
1523 goto error;
1524
1525 /* parse the number portion of the item */
1526 PARSE_NUM(num, cur, num_type);
1527
1528 if ((num_type == -1) || (*cur == 0))
1529 goto error;
1530
1531 /* update duration based on item type */
1532 while (seq < sizeof(desig)) {
1533 if (*cur == desig[seq]) {
1534
1535 /* verify numeric type; only seconds can be float */
1536 if ((num_type != 0) && (seq < (sizeof(desig)-1)))
1537 goto error;
1538
1539 switch (seq) {
1540 case 0:
1541 dur->value.dur.mon = (long)num * 12;
1542 break;
1543 case 1:
1544 dur->value.dur.mon += (long)num;
1545 break;
1546 default:
1547 /* convert to seconds using multiplier */
1548 dur->value.dur.sec += num * multi[seq];
1549 seq++;
1550 break;
1551 }
1552
1553 break; /* exit loop */
1554 }
1555 /* no date designators found? */
1556 if (++seq == 3)
1557 goto error;
1558 }
1559 cur++;
1560 }
1561
1562 if (isneg) {
1563 dur->value.dur.mon = -dur->value.dur.mon;
1564 dur->value.dur.day = -dur->value.dur.day;
1565 dur->value.dur.sec = -dur->value.dur.sec;
1566 }
1567
1568 if (val != NULL)
1569 *val = dur;
Daniel Veillard80b19092003-03-28 13:29:53 +00001570 else
1571 xmlSchemaFreeValue(dur);
Daniel Veillard070803b2002-05-03 07:29:38 +00001572
1573 return 0;
1574
1575error:
1576 if (dur != NULL)
1577 xmlSchemaFreeValue(dur);
1578 return 1;
1579}
1580
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001581/**
1582 * xmlSchemaStrip:
1583 * @value: a value
1584 *
1585 * Removes the leading and ending spaces of a string
1586 *
1587 * Returns the new string or NULL if no change was required.
1588 */
1589static xmlChar *
1590xmlSchemaStrip(const xmlChar *value) {
1591 const xmlChar *start = value, *end, *f;
1592
1593 if (value == NULL) return(NULL);
William M. Brack76e95df2003-10-18 16:20:14 +00001594 while ((*start != 0) && (IS_BLANK_CH(*start))) start++;
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001595 end = start;
1596 while (*end != 0) end++;
1597 f = end;
1598 end--;
William M. Brack76e95df2003-10-18 16:20:14 +00001599 while ((end > start) && (IS_BLANK_CH(*end))) end--;
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001600 end++;
1601 if ((start == value) && (f == end)) return(NULL);
1602 return(xmlStrndup(start, end - start));
1603}
Daniel Veillard96a4b252003-02-06 08:22:32 +00001604
1605/**
Kasimier T. Buchcik91feaf82004-11-12 14:04:58 +00001606 * xmlSchemaWhiteSpaceReplace:
1607 * @value: a value
1608 *
1609 * Replaces 0xd, 0x9 and 0xa with a space.
1610 *
1611 * Returns the new string or NULL if no change was required.
1612 */
1613xmlChar *
1614xmlSchemaWhiteSpaceReplace(const xmlChar *value) {
1615 const xmlChar *cur = value;
1616 xmlChar *ret = NULL, *mcur;
1617
1618 if (value == NULL)
1619 return(NULL);
1620
1621 while ((*cur != 0) &&
1622 (((*cur) != 0xd) && ((*cur) != 0x9) && ((*cur) != 0xa))) {
1623 cur++;
1624 }
1625 if (*cur == 0)
1626 return (NULL);
1627 ret = xmlStrdup(value);
1628 /* TODO FIXME: I guess gcc will bark at this. */
1629 mcur = (xmlChar *) (ret + (cur - value));
1630 do {
1631 if ( ((*mcur) == 0xd) || ((*mcur) == 0x9) || ((*mcur) == 0xa) )
1632 *mcur = ' ';
1633 mcur++;
1634 } while (*mcur != 0);
1635 return(ret);
1636}
1637
1638/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001639 * xmlSchemaCollapseString:
1640 * @value: a value
1641 *
1642 * Removes and normalize white spaces in the string
1643 *
1644 * Returns the new string or NULL if no change was required.
1645 */
Daniel Veillard01fa6152004-06-29 17:04:39 +00001646xmlChar *
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001647xmlSchemaCollapseString(const xmlChar *value) {
1648 const xmlChar *start = value, *end, *f;
1649 xmlChar *g;
1650 int col = 0;
1651
1652 if (value == NULL) return(NULL);
William M. Brack76e95df2003-10-18 16:20:14 +00001653 while ((*start != 0) && (IS_BLANK_CH(*start))) start++;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001654 end = start;
1655 while (*end != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00001656 if ((*end == ' ') && (IS_BLANK_CH(end[1]))) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001657 col = end - start;
1658 break;
1659 } else if ((*end == 0xa) || (*end == 0x9) || (*end == 0xd)) {
1660 col = end - start;
1661 break;
1662 }
1663 end++;
1664 }
1665 if (col == 0) {
1666 f = end;
1667 end--;
William M. Brack76e95df2003-10-18 16:20:14 +00001668 while ((end > start) && (IS_BLANK_CH(*end))) end--;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001669 end++;
1670 if ((start == value) && (f == end)) return(NULL);
1671 return(xmlStrndup(start, end - start));
1672 }
1673 start = xmlStrdup(start);
1674 if (start == NULL) return(NULL);
1675 g = (xmlChar *) (start + col);
1676 end = g;
1677 while (*end != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00001678 if (IS_BLANK_CH(*end)) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001679 end++;
William M. Brack76e95df2003-10-18 16:20:14 +00001680 while (IS_BLANK_CH(*end)) end++;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001681 if (*end != 0)
1682 *g++ = ' ';
1683 } else
1684 *g++ = *end++;
1685 }
1686 *g = 0;
1687 return((xmlChar *) start);
1688}
1689
1690/**
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001691 * xmlSchemaValAtomicListNode:
1692 * @type: the predefined atomic type for a token in the list
1693 * @value: the list value to check
1694 * @ret: the return computed value
1695 * @node: the node containing the value
1696 *
1697 * Check that a value conforms to the lexical space of the predefined
1698 * list type. if true a value is computed and returned in @ret.
1699 *
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001700 * Returns the number of items if this validates, a negative error code
1701 * number otherwise
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001702 */
1703static int
1704xmlSchemaValAtomicListNode(xmlSchemaTypePtr type, const xmlChar *value,
1705 xmlSchemaValPtr *ret, xmlNodePtr node) {
1706 xmlChar *val, *cur, *endval;
1707 int nb_values = 0;
Daniel Veillard580ced82003-03-21 21:22:48 +00001708 int tmp = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001709
1710 if (value == NULL) {
1711 return(-1);
1712 }
1713 val = xmlStrdup(value);
1714 if (val == NULL) {
1715 return(-1);
1716 }
Daniel Veillard6fc5db02005-01-16 00:05:58 +00001717 if (ret != NULL) {
1718 *ret = NULL;
1719 }
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001720 cur = val;
1721 /*
1722 * Split the list
1723 */
William M. Brack76e95df2003-10-18 16:20:14 +00001724 while (IS_BLANK_CH(*cur)) *cur++ = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001725 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00001726 if (IS_BLANK_CH(*cur)) {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001727 *cur = 0;
1728 cur++;
William M. Brack76e95df2003-10-18 16:20:14 +00001729 while (IS_BLANK_CH(*cur)) *cur++ = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001730 } else {
1731 nb_values++;
1732 cur++;
William M. Brack76e95df2003-10-18 16:20:14 +00001733 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001734 }
1735 }
1736 if (nb_values == 0) {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001737 xmlFree(val);
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001738 return(nb_values);
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001739 }
1740 endval = cur;
1741 cur = val;
1742 while ((*cur == 0) && (cur != endval)) cur++;
1743 while (cur != endval) {
1744 tmp = xmlSchemaValPredefTypeNode(type, cur, NULL, node);
1745 if (tmp != 0)
1746 break;
1747 while (*cur != 0) cur++;
1748 while ((*cur == 0) && (cur != endval)) cur++;
1749 }
Daniel Veillard6fc5db02005-01-16 00:05:58 +00001750 /* TODO what return value ? c.f. bug #158628
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001751 if (ret != NULL) {
1752 TODO
Daniel Veillard6fc5db02005-01-16 00:05:58 +00001753 } */
1754 xmlFree(val);
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001755 if (tmp == 0)
1756 return(nb_values);
1757 return(-1);
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001758}
1759
1760/**
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001761 * xmlSchemaParseUInt:
1762 * @str: pointer to the string R/W
1763 * @llo: pointer to the low result
1764 * @lmi: pointer to the mid result
1765 * @lhi: pointer to the high result
1766 *
1767 * Parse an unsigned long into 3 fields.
1768 *
1769 * Returns the number of chars parsed or -1 if overflow of the capacity
1770 */
1771static int
1772xmlSchemaParseUInt(const xmlChar **str, unsigned long *llo,
1773 unsigned long *lmi, unsigned long *lhi) {
1774 unsigned long lo = 0, mi = 0, hi = 0;
1775 const xmlChar *tmp, *cur = *str;
1776 int ret = 0, i = 0;
1777
1778 while (*cur == '0') {
1779 ret++;
1780 cur++;
1781 }
1782 tmp = cur;
1783 while ((*tmp != 0) && (*tmp >= '0') && (*tmp <= '9')) {
1784 i++;tmp++;ret++;
1785 }
1786 if (i > 24) {
1787 *str = tmp;
1788 return(-1);
1789 }
1790 while (i > 16) {
1791 hi = hi * 10 + (*cur++ - '0');
1792 i--;
1793 }
1794 while (i > 8) {
1795 mi = mi * 10 + (*cur++ - '0');
1796 i--;
1797 }
1798 while (i > 0) {
1799 lo = lo * 10 + (*cur++ - '0');
1800 i--;
1801 }
1802
1803 *str = cur;
1804 *llo = lo;
1805 *lmi = mi;
1806 *lhi = hi;
1807 return(ret);
1808}
1809
1810/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001811 * xmlSchemaValAtomicType:
1812 * @type: the predefined type
1813 * @value: the value to check
1814 * @val: the return computed value
1815 * @node: the node containing the value
1816 * flags: flags to control the vlidation
1817 *
1818 * Check that a value conforms to the lexical space of the atomic type.
1819 * if true a value is computed and returned in @val.
Daniel Veillard01fa6152004-06-29 17:04:39 +00001820 * This checks the value space for list types as well (IDREFS, NMTOKENS).
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001821 *
1822 * Returns 0 if this validates, a positive error code number otherwise
1823 * and -1 in case of internal or API error.
1824 */
1825static int
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001826xmlSchemaValAtomicType(xmlSchemaTypePtr type, const xmlChar * value,
1827 xmlSchemaValPtr * val, xmlNodePtr node, int flags)
1828{
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001829 xmlSchemaValPtr v;
1830 xmlChar *norm = NULL;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001831 int ret = 0;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001832
1833 if (xmlSchemaTypesInitialized == 0)
Daniel Veillard01fa6152004-06-29 17:04:39 +00001834 xmlSchemaInitTypes();
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001835 if (type == NULL)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001836 return (-1);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001837
Daniel Veillardeebd6332004-08-26 10:30:44 +00001838 /*
1839 * validating a non existant text node is similar to validating
1840 * an empty one.
1841 */
1842 if (value == NULL)
1843 value = BAD_CAST "";
1844
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001845 if (val != NULL)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001846 *val = NULL;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001847 if ((flags == 0) && (value != NULL)) {
Kasimier T. Buchcik91feaf82004-11-12 14:04:58 +00001848
Daniel Veillard01fa6152004-06-29 17:04:39 +00001849 if ((type->builtInType != XML_SCHEMAS_STRING) &&
Kasimier T. Buchcik91feaf82004-11-12 14:04:58 +00001850 (type->builtInType != XML_SCHEMAS_ANYTYPE) &&
1851 (type->builtInType != XML_SCHEMAS_ANYSIMPLETYPE)) {
1852 if (type->builtInType == XML_SCHEMAS_NORMSTRING)
1853 norm = xmlSchemaWhiteSpaceReplace(value);
1854 else
1855 norm = xmlSchemaCollapseString(value);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001856 if (norm != NULL)
1857 value = norm;
1858 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001859 }
1860
Daniel Veillard01fa6152004-06-29 17:04:39 +00001861 switch (type->builtInType) {
William M. Brack2f2a6632004-08-20 23:09:47 +00001862 case XML_SCHEMAS_UNKNOWN:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001863 goto error;
William M. Brack2f2a6632004-08-20 23:09:47 +00001864 case XML_SCHEMAS_ANYTYPE:
1865 case XML_SCHEMAS_ANYSIMPLETYPE:
1866 goto return0;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001867 case XML_SCHEMAS_STRING:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001868 goto return0;
Daniel Veillard1516d5b2004-01-22 07:27:45 +00001869 case XML_SCHEMAS_NORMSTRING:{
1870 const xmlChar *cur = value;
1871
1872 while (*cur != 0) {
1873 if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) {
1874 goto return1;
1875 } else {
1876 cur++;
1877 }
1878 }
1879 if (val != NULL) {
1880 v = xmlSchemaNewValue(XML_SCHEMAS_NORMSTRING);
1881 if (v != NULL) {
1882 v->value.str = xmlStrdup(value);
1883 *val = v;
1884 } else {
1885 goto error;
1886 }
1887 }
1888 goto return0;
1889 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001890 case XML_SCHEMAS_DECIMAL:{
1891 const xmlChar *cur = value, *tmp;
1892 unsigned int frac = 0, len, neg = 0;
1893 unsigned long base = 0;
1894
1895 if (cur == NULL)
1896 goto return1;
1897 if (*cur == '+')
1898 cur++;
1899 else if (*cur == '-') {
1900 neg = 1;
1901 cur++;
1902 }
1903 tmp = cur;
1904 while ((*cur >= '0') && (*cur <= '9')) {
1905 base = base * 10 + (*cur - '0');
1906 cur++;
1907 }
1908 len = cur - tmp;
1909 if (*cur == '.') {
1910 cur++;
1911 tmp = cur;
1912 while ((*cur >= '0') && (*cur <= '9')) {
1913 base = base * 10 + (*cur - '0');
1914 cur++;
1915 }
1916 frac = cur - tmp;
1917 }
1918 if (*cur != 0)
1919 goto return1;
1920 if (val != NULL) {
1921 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
1922 if (v != NULL) {
1923 v->value.decimal.lo = base;
1924 v->value.decimal.sign = neg;
1925 v->value.decimal.frac = frac;
1926 v->value.decimal.total = frac + len;
1927 *val = v;
1928 }
1929 }
1930 goto return0;
1931 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001932 case XML_SCHEMAS_TIME:
1933 case XML_SCHEMAS_GDAY:
1934 case XML_SCHEMAS_GMONTH:
1935 case XML_SCHEMAS_GMONTHDAY:
1936 case XML_SCHEMAS_GYEAR:
1937 case XML_SCHEMAS_GYEARMONTH:
1938 case XML_SCHEMAS_DATE:
1939 case XML_SCHEMAS_DATETIME:
Daniel Veillard01fa6152004-06-29 17:04:39 +00001940 ret = xmlSchemaValidateDates(type->builtInType, value, val);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001941 break;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001942 case XML_SCHEMAS_DURATION:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001943 ret = xmlSchemaValidateDuration(type, value, val);
1944 break;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001945 case XML_SCHEMAS_FLOAT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001946 case XML_SCHEMAS_DOUBLE:{
1947 const xmlChar *cur = value;
1948 int neg = 0;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001949
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001950 if (cur == NULL)
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00001951 goto return1;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001952 if ((cur[0] == 'N') && (cur[1] == 'a') && (cur[2] == 'N')) {
1953 cur += 3;
1954 if (*cur != 0)
1955 goto return1;
1956 if (val != NULL) {
1957 if (type == xmlSchemaTypeFloatDef) {
1958 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1959 if (v != NULL) {
1960 v->value.f = (float) xmlXPathNAN;
1961 } else {
1962 xmlSchemaFreeValue(v);
1963 goto error;
1964 }
1965 } else {
1966 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1967 if (v != NULL) {
1968 v->value.d = xmlXPathNAN;
1969 } else {
1970 xmlSchemaFreeValue(v);
1971 goto error;
1972 }
1973 }
1974 *val = v;
1975 }
1976 goto return0;
1977 }
1978 if (*cur == '-') {
1979 neg = 1;
1980 cur++;
1981 }
1982 if ((cur[0] == 'I') && (cur[1] == 'N') && (cur[2] == 'F')) {
1983 cur += 3;
1984 if (*cur != 0)
1985 goto return1;
1986 if (val != NULL) {
1987 if (type == xmlSchemaTypeFloatDef) {
1988 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1989 if (v != NULL) {
1990 if (neg)
1991 v->value.f = (float) xmlXPathNINF;
1992 else
1993 v->value.f = (float) xmlXPathPINF;
1994 } else {
1995 xmlSchemaFreeValue(v);
1996 goto error;
1997 }
1998 } else {
1999 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
2000 if (v != NULL) {
2001 if (neg)
2002 v->value.d = xmlXPathNINF;
2003 else
2004 v->value.d = xmlXPathPINF;
2005 } else {
2006 xmlSchemaFreeValue(v);
2007 goto error;
2008 }
2009 }
2010 *val = v;
2011 }
2012 goto return0;
2013 }
2014 if ((neg == 0) && (*cur == '+'))
2015 cur++;
2016 if ((cur[0] == 0) || (cur[0] == '+') || (cur[0] == '-'))
2017 goto return1;
2018 while ((*cur >= '0') && (*cur <= '9')) {
2019 cur++;
2020 }
2021 if (*cur == '.') {
2022 cur++;
2023 while ((*cur >= '0') && (*cur <= '9'))
2024 cur++;
2025 }
2026 if ((*cur == 'e') || (*cur == 'E')) {
2027 cur++;
2028 if ((*cur == '-') || (*cur == '+'))
2029 cur++;
2030 while ((*cur >= '0') && (*cur <= '9'))
2031 cur++;
2032 }
2033 if (*cur != 0)
2034 goto return1;
2035 if (val != NULL) {
2036 if (type == xmlSchemaTypeFloatDef) {
2037 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
2038 if (v != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002039 if (sscanf((const char *) value, "%f",
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002040 &(v->value.f)) == 1) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00002041 *val = v;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002042 } else {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002043 xmlSchemaFreeValue(v);
2044 goto return1;
2045 }
2046 } else {
2047 goto error;
2048 }
2049 } else {
2050 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
2051 if (v != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002052 if (sscanf((const char *) value, "%lf",
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002053 &(v->value.d)) == 1) {
2054 *val = v;
2055 } else {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002056 xmlSchemaFreeValue(v);
2057 goto return1;
2058 }
2059 } else {
2060 goto error;
2061 }
2062 }
2063 }
2064 goto return0;
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00002065 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002066 case XML_SCHEMAS_BOOLEAN:{
2067 const xmlChar *cur = value;
2068
2069 if ((cur[0] == '0') && (cur[1] == 0))
2070 ret = 0;
2071 else if ((cur[0] == '1') && (cur[1] == 0))
2072 ret = 1;
2073 else if ((cur[0] == 't') && (cur[1] == 'r')
2074 && (cur[2] == 'u') && (cur[3] == 'e')
2075 && (cur[4] == 0))
2076 ret = 1;
2077 else if ((cur[0] == 'f') && (cur[1] == 'a')
2078 && (cur[2] == 'l') && (cur[3] == 's')
2079 && (cur[4] == 'e') && (cur[5] == 0))
2080 ret = 0;
2081 else
2082 goto return1;
2083 if (val != NULL) {
2084 v = xmlSchemaNewValue(XML_SCHEMAS_BOOLEAN);
2085 if (v != NULL) {
2086 v->value.b = ret;
2087 *val = v;
2088 } else {
2089 goto error;
2090 }
2091 }
2092 goto return0;
2093 }
2094 case XML_SCHEMAS_TOKEN:{
2095 const xmlChar *cur = value;
2096
William M. Brack76e95df2003-10-18 16:20:14 +00002097 if (IS_BLANK_CH(*cur))
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002098 goto return1;
2099
2100 while (*cur != 0) {
2101 if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) {
2102 goto return1;
2103 } else if (*cur == ' ') {
2104 cur++;
2105 if (*cur == 0)
2106 goto return1;
2107 if (*cur == ' ')
2108 goto return1;
2109 } else {
2110 cur++;
2111 }
2112 }
2113 if (val != NULL) {
2114 v = xmlSchemaNewValue(XML_SCHEMAS_TOKEN);
2115 if (v != NULL) {
2116 v->value.str = xmlStrdup(value);
2117 *val = v;
2118 } else {
2119 goto error;
2120 }
2121 }
2122 goto return0;
2123 }
2124 case XML_SCHEMAS_LANGUAGE:
2125 if (xmlCheckLanguageID(value) == 1) {
2126 if (val != NULL) {
2127 v = xmlSchemaNewValue(XML_SCHEMAS_LANGUAGE);
2128 if (v != NULL) {
2129 v->value.str = xmlStrdup(value);
2130 *val = v;
2131 } else {
2132 goto error;
2133 }
2134 }
2135 goto return0;
2136 }
2137 goto return1;
2138 case XML_SCHEMAS_NMTOKEN:
2139 if (xmlValidateNMToken(value, 1) == 0) {
2140 if (val != NULL) {
2141 v = xmlSchemaNewValue(XML_SCHEMAS_NMTOKEN);
2142 if (v != NULL) {
2143 v->value.str = xmlStrdup(value);
2144 *val = v;
2145 } else {
2146 goto error;
2147 }
2148 }
2149 goto return0;
2150 }
2151 goto return1;
2152 case XML_SCHEMAS_NMTOKENS:
2153 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeNmtokenDef,
2154 value, val, node);
2155 if (ret > 0)
2156 ret = 0;
2157 else
2158 ret = 1;
2159 goto done;
2160 case XML_SCHEMAS_NAME:
2161 ret = xmlValidateName(value, 1);
Daniel Veillarddf292f72005-01-16 19:00:15 +00002162 if ((ret == 0) && (val != NULL) && (value != NULL)) {
2163 v = xmlSchemaNewValue(XML_SCHEMAS_NAME);
2164 if (v != NULL) {
2165 const xmlChar *start = value, *end;
2166 while (IS_BLANK_CH(*start)) start++;
2167 end = start;
2168 while ((*end != 0) && (!IS_BLANK_CH(*end))) end++;
2169 v->value.str = xmlStrndup(start, end - start);
2170 *val = v;
2171 } else {
2172 goto error;
2173 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002174 }
2175 goto done;
2176 case XML_SCHEMAS_QNAME:{
2177 xmlChar *uri = NULL;
2178 xmlChar *local = NULL;
2179
2180 ret = xmlValidateQName(value, 1);
2181 if ((ret == 0) && (node != NULL)) {
2182 xmlChar *prefix;
2183
2184 local = xmlSplitQName2(value, &prefix);
2185 if (prefix != NULL) {
2186 xmlNsPtr ns;
2187
2188 ns = xmlSearchNs(node->doc, node, prefix);
2189 if (ns == NULL)
2190 ret = 1;
2191 else if (val != NULL)
2192 uri = xmlStrdup(ns->href);
2193 }
2194 if ((local != NULL) && ((val == NULL) || (ret != 0)))
2195 xmlFree(local);
2196 if (prefix != NULL)
2197 xmlFree(prefix);
2198 }
2199 if ((ret == 0) && (val != NULL)) {
2200 v = xmlSchemaNewValue(XML_SCHEMAS_QNAME);
2201 if (v != NULL) {
2202 if (local != NULL)
2203 v->value.qname.name = local;
2204 else
2205 v->value.qname.name = xmlStrdup(value);
2206 if (uri != NULL)
2207 v->value.qname.uri = uri;
2208
2209 *val = v;
2210 } else {
2211 if (local != NULL)
2212 xmlFree(local);
2213 if (uri != NULL)
2214 xmlFree(uri);
2215 goto error;
2216 }
2217 }
2218 goto done;
2219 }
2220 case XML_SCHEMAS_NCNAME:
2221 ret = xmlValidateNCName(value, 1);
2222 if ((ret == 0) && (val != NULL)) {
2223 v = xmlSchemaNewValue(XML_SCHEMAS_NCNAME);
2224 if (v != NULL) {
2225 v->value.str = xmlStrdup(value);
2226 *val = v;
2227 } else {
2228 goto error;
2229 }
2230 }
2231 goto done;
2232 case XML_SCHEMAS_ID:
2233 ret = xmlValidateNCName(value, 1);
2234 if ((ret == 0) && (val != NULL)) {
2235 v = xmlSchemaNewValue(XML_SCHEMAS_ID);
2236 if (v != NULL) {
2237 v->value.str = xmlStrdup(value);
2238 *val = v;
2239 } else {
2240 goto error;
2241 }
2242 }
2243 if ((ret == 0) && (node != NULL) &&
2244 (node->type == XML_ATTRIBUTE_NODE)) {
2245 xmlAttrPtr attr = (xmlAttrPtr) node;
2246
2247 /*
2248 * NOTE: the IDness might have already be declared in the DTD
2249 */
2250 if (attr->atype != XML_ATTRIBUTE_ID) {
2251 xmlIDPtr res;
2252 xmlChar *strip;
2253
2254 strip = xmlSchemaStrip(value);
2255 if (strip != NULL) {
2256 res = xmlAddID(NULL, node->doc, strip, attr);
2257 xmlFree(strip);
2258 } else
2259 res = xmlAddID(NULL, node->doc, value, attr);
2260 if (res == NULL) {
2261 ret = 2;
2262 } else {
2263 attr->atype = XML_ATTRIBUTE_ID;
2264 }
2265 }
2266 }
2267 goto done;
2268 case XML_SCHEMAS_IDREF:
2269 ret = xmlValidateNCName(value, 1);
2270 if ((ret == 0) && (val != NULL)) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00002271 v = xmlSchemaNewValue(XML_SCHEMAS_IDREF);
2272 if (v == NULL)
2273 goto error;
2274 v->value.str = xmlStrdup(value);
2275 *val = v;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002276 }
2277 if ((ret == 0) && (node != NULL) &&
2278 (node->type == XML_ATTRIBUTE_NODE)) {
2279 xmlAttrPtr attr = (xmlAttrPtr) node;
2280 xmlChar *strip;
2281
2282 strip = xmlSchemaStrip(value);
2283 if (strip != NULL) {
2284 xmlAddRef(NULL, node->doc, strip, attr);
2285 xmlFree(strip);
2286 } else
2287 xmlAddRef(NULL, node->doc, value, attr);
2288 attr->atype = XML_ATTRIBUTE_IDREF;
2289 }
2290 goto done;
2291 case XML_SCHEMAS_IDREFS:
2292 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeIdrefDef,
2293 value, val, node);
2294 if (ret < 0)
2295 ret = 2;
2296 else
2297 ret = 0;
2298 if ((ret == 0) && (node != NULL) &&
2299 (node->type == XML_ATTRIBUTE_NODE)) {
2300 xmlAttrPtr attr = (xmlAttrPtr) node;
2301
2302 attr->atype = XML_ATTRIBUTE_IDREFS;
2303 }
2304 goto done;
2305 case XML_SCHEMAS_ENTITY:{
2306 xmlChar *strip;
2307
2308 ret = xmlValidateNCName(value, 1);
2309 if ((node == NULL) || (node->doc == NULL))
2310 ret = 3;
2311 if (ret == 0) {
2312 xmlEntityPtr ent;
2313
2314 strip = xmlSchemaStrip(value);
2315 if (strip != NULL) {
2316 ent = xmlGetDocEntity(node->doc, strip);
2317 xmlFree(strip);
2318 } else {
2319 ent = xmlGetDocEntity(node->doc, value);
2320 }
2321 if ((ent == NULL) ||
2322 (ent->etype !=
2323 XML_EXTERNAL_GENERAL_UNPARSED_ENTITY))
2324 ret = 4;
2325 }
2326 if ((ret == 0) && (val != NULL)) {
2327 TODO;
2328 }
2329 if ((ret == 0) && (node != NULL) &&
2330 (node->type == XML_ATTRIBUTE_NODE)) {
2331 xmlAttrPtr attr = (xmlAttrPtr) node;
2332
2333 attr->atype = XML_ATTRIBUTE_ENTITY;
2334 }
2335 goto done;
2336 }
2337 case XML_SCHEMAS_ENTITIES:
2338 if ((node == NULL) || (node->doc == NULL))
2339 goto return3;
2340 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeEntityDef,
2341 value, val, node);
2342 if (ret <= 0)
2343 ret = 1;
2344 else
2345 ret = 0;
2346 if ((ret == 0) && (node != NULL) &&
2347 (node->type == XML_ATTRIBUTE_NODE)) {
2348 xmlAttrPtr attr = (xmlAttrPtr) node;
2349
2350 attr->atype = XML_ATTRIBUTE_ENTITIES;
2351 }
2352 goto done;
2353 case XML_SCHEMAS_NOTATION:{
2354 xmlChar *uri = NULL;
2355 xmlChar *local = NULL;
2356
2357 ret = xmlValidateQName(value, 1);
2358 if ((ret == 0) && (node != NULL)) {
2359 xmlChar *prefix;
2360
2361 local = xmlSplitQName2(value, &prefix);
2362 if (prefix != NULL) {
2363 xmlNsPtr ns;
2364
2365 ns = xmlSearchNs(node->doc, node, prefix);
2366 if (ns == NULL)
2367 ret = 1;
2368 else if (val != NULL)
2369 uri = xmlStrdup(ns->href);
2370 }
2371 if ((local != NULL) && ((val == NULL) || (ret != 0)))
2372 xmlFree(local);
2373 if (prefix != NULL)
2374 xmlFree(prefix);
2375 }
2376 if ((node == NULL) || (node->doc == NULL))
2377 ret = 3;
2378 if (ret == 0) {
2379 ret = xmlValidateNotationUse(NULL, node->doc, value);
2380 if (ret == 1)
2381 ret = 0;
2382 else
2383 ret = 1;
2384 }
2385 if ((ret == 0) && (val != NULL)) {
2386 v = xmlSchemaNewValue(XML_SCHEMAS_NOTATION);
2387 if (v != NULL) {
2388 if (local != NULL)
2389 v->value.qname.name = local;
2390 else
2391 v->value.qname.name = xmlStrdup(value);
2392 if (uri != NULL)
2393 v->value.qname.uri = uri;
2394
2395 *val = v;
2396 } else {
2397 if (local != NULL)
2398 xmlFree(local);
2399 if (uri != NULL)
2400 xmlFree(uri);
2401 goto error;
2402 }
2403 }
2404 goto done;
2405 }
2406 case XML_SCHEMAS_ANYURI:{
Daniel Veillard11c466a2004-03-14 12:20:15 +00002407 if (*value != 0) {
2408 xmlURIPtr uri = xmlParseURI((const char *) value);
2409 if (uri == NULL)
2410 goto return1;
2411 xmlFreeURI(uri);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002412 }
Daniel Veillard11c466a2004-03-14 12:20:15 +00002413
2414 if (val != NULL) {
2415 v = xmlSchemaNewValue(XML_SCHEMAS_ANYURI);
2416 if (v == NULL)
2417 goto error;
2418 v->value.str = xmlStrdup(value);
2419 *val = v;
2420 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002421 goto return0;
2422 }
2423 case XML_SCHEMAS_HEXBINARY:{
2424 const xmlChar *cur = value;
2425 xmlChar *base;
2426 int total, i = 0;
2427
Daniel Veillardf34a20e2004-08-31 08:42:17 +00002428 if (cur == NULL)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002429 goto return1;
2430
2431 while (((*cur >= '0') && (*cur <= '9')) ||
2432 ((*cur >= 'A') && (*cur <= 'F')) ||
2433 ((*cur >= 'a') && (*cur <= 'f'))) {
2434 i++;
2435 cur++;
2436 }
2437
2438 if (*cur != 0)
2439 goto return1;
2440 if ((i % 2) != 0)
2441 goto return1;
2442
2443 if (val != NULL) {
2444
2445 v = xmlSchemaNewValue(XML_SCHEMAS_HEXBINARY);
2446 if (v == NULL)
2447 goto error;
2448
2449 cur = xmlStrdup(value);
2450 if (cur == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002451 xmlSchemaTypeErrMemory(node, "allocating hexbin data");
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002452 xmlFree(v);
2453 goto return1;
2454 }
2455
2456 total = i / 2; /* number of octets */
2457
2458 base = (xmlChar *) cur;
2459 while (i-- > 0) {
2460 if (*base >= 'a')
2461 *base = *base - ('a' - 'A');
2462 base++;
2463 }
2464
2465 v->value.hex.str = (xmlChar *) cur;
2466 v->value.hex.total = total;
2467 *val = v;
2468 }
2469 goto return0;
2470 }
2471 case XML_SCHEMAS_BASE64BINARY:{
2472 /* ISSUE:
2473 *
2474 * Ignore all stray characters? (yes, currently)
2475 * Worry about long lines? (no, currently)
2476 *
2477 * rfc2045.txt:
2478 *
2479 * "The encoded output stream must be represented in lines of
2480 * no more than 76 characters each. All line breaks or other
2481 * characters not found in Table 1 must be ignored by decoding
2482 * software. In base64 data, characters other than those in
2483 * Table 1, line breaks, and other white space probably
2484 * indicate a transmission error, about which a warning
2485 * message or even a message rejection might be appropriate
2486 * under some circumstances." */
2487 const xmlChar *cur = value;
2488 xmlChar *base;
2489 int total, i = 0, pad = 0;
2490
2491 if (cur == NULL)
2492 goto return1;
2493
2494 for (; *cur; ++cur) {
2495 int decc;
2496
2497 decc = _xmlSchemaBase64Decode(*cur);
2498 if (decc < 0) ;
2499 else if (decc < 64)
2500 i++;
2501 else
2502 break;
2503 }
2504 for (; *cur; ++cur) {
2505 int decc;
2506
2507 decc = _xmlSchemaBase64Decode(*cur);
2508 if (decc < 0) ;
2509 else if (decc < 64)
2510 goto return1;
2511 if (decc == 64)
2512 pad++;
2513 }
2514
2515 /* rfc2045.txt: "Special processing is performed if fewer than
2516 * 24 bits are available at the end of the data being encoded.
2517 * A full encoding quantum is always completed at the end of a
2518 * body. When fewer than 24 input bits are available in an
2519 * input group, zero bits are added (on the right) to form an
2520 * integral number of 6-bit groups. Padding at the end of the
2521 * data is performed using the "=" character. Since all
2522 * base64 input is an integral number of octets, only the
2523 * following cases can arise: (1) the final quantum of
2524 * encoding input is an integral multiple of 24 bits; here,
2525 * the final unit of encoded output will be an integral
2526 * multiple ofindent: Standard input:701: Warning:old style
2527 * assignment ambiguity in "=*". Assuming "= *" 4 characters
2528 * with no "=" padding, (2) the final
2529 * quantum of encoding input is exactly 8 bits; here, the
2530 * final unit of encoded output will be two characters
2531 * followed by two "=" padding characters, or (3) the final
2532 * quantum of encoding input is exactly 16 bits; here, the
2533 * final unit of encoded output will be three characters
2534 * followed by one "=" padding character." */
2535
2536 total = 3 * (i / 4);
2537 if (pad == 0) {
2538 if (i % 4 != 0)
2539 goto return1;
2540 } else if (pad == 1) {
2541 int decc;
2542
2543 if (i % 4 != 3)
2544 goto return1;
2545 for (decc = _xmlSchemaBase64Decode(*cur);
2546 (decc < 0) || (decc > 63);
2547 decc = _xmlSchemaBase64Decode(*cur))
2548 --cur;
2549 /* 16bits in 24bits means 2 pad bits: nnnnnn nnmmmm mmmm00*/
2550 /* 00111100 -> 0x3c */
2551 if (decc & ~0x3c)
2552 goto return1;
2553 total += 2;
2554 } else if (pad == 2) {
2555 int decc;
2556
2557 if (i % 4 != 2)
2558 goto return1;
2559 for (decc = _xmlSchemaBase64Decode(*cur);
2560 (decc < 0) || (decc > 63);
2561 decc = _xmlSchemaBase64Decode(*cur))
2562 --cur;
2563 /* 8bits in 12bits means 4 pad bits: nnnnnn nn0000 */
2564 /* 00110000 -> 0x30 */
2565 if (decc & ~0x30)
2566 goto return1;
2567 total += 1;
2568 } else
2569 goto return1;
2570
2571 if (val != NULL) {
2572 v = xmlSchemaNewValue(XML_SCHEMAS_BASE64BINARY);
2573 if (v == NULL)
2574 goto error;
2575 base =
2576 (xmlChar *) xmlMallocAtomic((i + pad + 1) *
2577 sizeof(xmlChar));
2578 if (base == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002579 xmlSchemaTypeErrMemory(node, "allocating base64 data");
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002580 xmlFree(v);
2581 goto return1;
2582 }
2583 v->value.base64.str = base;
2584 for (cur = value; *cur; ++cur)
2585 if (_xmlSchemaBase64Decode(*cur) >= 0) {
2586 *base = *cur;
2587 ++base;
2588 }
2589 *base = 0;
2590 v->value.base64.total = total;
2591 *val = v;
2592 }
2593 goto return0;
2594 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002595 case XML_SCHEMAS_INTEGER:
2596 case XML_SCHEMAS_PINTEGER:
2597 case XML_SCHEMAS_NPINTEGER:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002598 case XML_SCHEMAS_NINTEGER:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002599 case XML_SCHEMAS_NNINTEGER:{
2600 const xmlChar *cur = value;
2601 unsigned long lo, mi, hi;
2602 int sign = 0;
2603
2604 if (cur == NULL)
2605 goto return1;
2606 if (*cur == '-') {
2607 sign = 1;
2608 cur++;
2609 } else if (*cur == '+')
2610 cur++;
2611 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2612 if (ret == 0)
2613 goto return1;
2614 if (*cur != 0)
2615 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002616 if (type->builtInType == XML_SCHEMAS_NPINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002617 if ((sign == 0) &&
2618 ((hi != 0) || (mi != 0) || (lo != 0)))
2619 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002620 } else if (type->builtInType == XML_SCHEMAS_PINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002621 if (sign == 1)
2622 goto return1;
2623 if ((hi == 0) && (mi == 0) && (lo == 0))
2624 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002625 } else if (type->builtInType == XML_SCHEMAS_NINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002626 if (sign == 0)
2627 goto return1;
2628 if ((hi == 0) && (mi == 0) && (lo == 0))
2629 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002630 } else if (type->builtInType == XML_SCHEMAS_NNINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002631 if ((sign == 1) &&
2632 ((hi != 0) || (mi != 0) || (lo != 0)))
2633 goto return1;
2634 }
2635 /*
2636 * We can store a value only if no overflow occured
2637 */
2638 if ((ret > 0) && (val != NULL)) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00002639 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002640 if (v != NULL) {
2641 v->value.decimal.lo = lo;
2642 v->value.decimal.mi = lo;
2643 v->value.decimal.hi = lo;
2644 v->value.decimal.sign = sign;
2645 v->value.decimal.frac = 0;
2646 v->value.decimal.total = cur - value;
2647 *val = v;
2648 }
2649 }
2650 goto return0;
2651 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002652 case XML_SCHEMAS_LONG:
2653 case XML_SCHEMAS_BYTE:
2654 case XML_SCHEMAS_SHORT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002655 case XML_SCHEMAS_INT:{
2656 const xmlChar *cur = value;
2657 unsigned long lo, mi, hi;
2658 int total = 0;
2659 int sign = 0;
2660
2661 if (cur == NULL)
2662 goto return1;
2663 if (*cur == '-') {
2664 sign = 1;
2665 cur++;
2666 } else if (*cur == '+')
2667 cur++;
2668 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2669 if (ret <= 0)
2670 goto return1;
2671 if (*cur != 0)
2672 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002673 if (type->builtInType == XML_SCHEMAS_LONG) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002674 if (hi >= 922) {
2675 if (hi > 922)
2676 goto return1;
2677 if (mi >= 33720368) {
2678 if (mi > 33720368)
2679 goto return1;
2680 if ((sign == 0) && (lo > 54775807))
2681 goto return1;
2682 if ((sign == 1) && (lo > 54775808))
2683 goto return1;
2684 }
2685 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002686 } else if (type->builtInType == XML_SCHEMAS_INT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002687 if (hi != 0)
2688 goto return1;
2689 if (mi >= 21) {
2690 if (mi > 21)
2691 goto return1;
2692 if ((sign == 0) && (lo > 47483647))
2693 goto return1;
2694 if ((sign == 1) && (lo > 47483648))
2695 goto return1;
2696 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002697 } else if (type->builtInType == XML_SCHEMAS_SHORT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002698 if ((mi != 0) || (hi != 0))
2699 goto return1;
2700 if ((sign == 1) && (lo > 32768))
2701 goto return1;
2702 if ((sign == 0) && (lo > 32767))
2703 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002704 } else if (type->builtInType == XML_SCHEMAS_BYTE) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002705 if ((mi != 0) || (hi != 0))
2706 goto return1;
2707 if ((sign == 1) && (lo > 128))
2708 goto return1;
2709 if ((sign == 0) && (lo > 127))
2710 goto return1;
2711 }
2712 if (val != NULL) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00002713 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002714 if (v != NULL) {
2715 v->value.decimal.lo = lo;
2716 v->value.decimal.mi = lo;
2717 v->value.decimal.hi = lo;
2718 v->value.decimal.sign = sign;
2719 v->value.decimal.frac = 0;
2720 v->value.decimal.total = total;
2721 *val = v;
2722 }
2723 }
2724 goto return0;
2725 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002726 case XML_SCHEMAS_UINT:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002727 case XML_SCHEMAS_ULONG:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002728 case XML_SCHEMAS_USHORT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002729 case XML_SCHEMAS_UBYTE:{
2730 const xmlChar *cur = value;
2731 unsigned long lo, mi, hi;
2732 int total = 0;
2733
2734 if (cur == NULL)
2735 goto return1;
2736 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2737 if (ret <= 0)
2738 goto return1;
2739 if (*cur != 0)
2740 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002741 if (type->builtInType == XML_SCHEMAS_ULONG) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002742 if (hi >= 1844) {
2743 if (hi > 1844)
2744 goto return1;
2745 if (mi >= 67440737) {
2746 if (mi > 67440737)
2747 goto return1;
2748 if (lo > 9551615)
2749 goto return1;
2750 }
2751 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002752 } else if (type->builtInType == XML_SCHEMAS_UINT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002753 if (hi != 0)
2754 goto return1;
2755 if (mi >= 42) {
2756 if (mi > 42)
2757 goto return1;
2758 if (lo > 94967295)
2759 goto return1;
2760 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002761 } else if (type->builtInType == XML_SCHEMAS_USHORT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002762 if ((mi != 0) || (hi != 0))
2763 goto return1;
2764 if (lo > 65535)
2765 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002766 } else if (type->builtInType == XML_SCHEMAS_UBYTE) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002767 if ((mi != 0) || (hi != 0))
2768 goto return1;
2769 if (lo > 255)
2770 goto return1;
2771 }
2772 if (val != NULL) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00002773 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002774 if (v != NULL) {
2775 v->value.decimal.lo = lo;
2776 v->value.decimal.mi = mi;
2777 v->value.decimal.hi = hi;
2778 v->value.decimal.sign = 0;
2779 v->value.decimal.frac = 0;
2780 v->value.decimal.total = total;
2781 *val = v;
2782 }
2783 }
2784 goto return0;
2785 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002786 }
2787
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002788 done:
2789 if (norm != NULL)
2790 xmlFree(norm);
2791 return (ret);
2792 return3:
2793 if (norm != NULL)
2794 xmlFree(norm);
2795 return (3);
2796 return1:
2797 if (norm != NULL)
2798 xmlFree(norm);
2799 return (1);
2800 return0:
2801 if (norm != NULL)
2802 xmlFree(norm);
2803 return (0);
2804 error:
2805 if (norm != NULL)
2806 xmlFree(norm);
2807 return (-1);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002808}
2809
2810/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002811 * xmlSchemaValPredefTypeNode:
Daniel Veillard4255d502002-04-16 15:50:10 +00002812 * @type: the predefined type
2813 * @value: the value to check
2814 * @val: the return computed value
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002815 * @node: the node containing the value
Daniel Veillard4255d502002-04-16 15:50:10 +00002816 *
2817 * Check that a value conforms to the lexical space of the predefined type.
2818 * if true a value is computed and returned in @val.
2819 *
2820 * Returns 0 if this validates, a positive error code number otherwise
2821 * and -1 in case of internal or API error.
2822 */
2823int
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002824xmlSchemaValPredefTypeNode(xmlSchemaTypePtr type, const xmlChar *value,
2825 xmlSchemaValPtr *val, xmlNodePtr node) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002826 return(xmlSchemaValAtomicType(type, value, val, node, 0));
Daniel Veillard4255d502002-04-16 15:50:10 +00002827}
2828
2829/**
Daniel Veillardc0826a72004-08-10 14:17:33 +00002830 * xmlSchemaValPredefTypeNodeNoNorm:
2831 * @type: the predefined type
2832 * @value: the value to check
2833 * @val: the return computed value
2834 * @node: the node containing the value
2835 *
2836 * Check that a value conforms to the lexical space of the predefined type.
2837 * if true a value is computed and returned in @val.
2838 * This one does apply any normalization to the value.
2839 *
2840 * Returns 0 if this validates, a positive error code number otherwise
2841 * and -1 in case of internal or API error.
2842 */
2843int
2844xmlSchemaValPredefTypeNodeNoNorm(xmlSchemaTypePtr type, const xmlChar *value,
2845 xmlSchemaValPtr *val, xmlNodePtr node) {
2846 return(xmlSchemaValAtomicType(type, value, val, node, 1));
2847}
2848
2849/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002850 * xmlSchemaValidatePredefinedType:
2851 * @type: the predefined type
2852 * @value: the value to check
2853 * @val: the return computed value
2854 *
2855 * Check that a value conforms to the lexical space of the predefined type.
2856 * if true a value is computed and returned in @val.
2857 *
2858 * Returns 0 if this validates, a positive error code number otherwise
2859 * and -1 in case of internal or API error.
2860 */
2861int
2862xmlSchemaValidatePredefinedType(xmlSchemaTypePtr type, const xmlChar *value,
2863 xmlSchemaValPtr *val) {
2864 return(xmlSchemaValPredefTypeNode(type, value, val, NULL));
2865}
2866
2867/**
Daniel Veillard4255d502002-04-16 15:50:10 +00002868 * xmlSchemaCompareDecimals:
2869 * @x: a first decimal value
2870 * @y: a second decimal value
2871 *
2872 * Compare 2 decimals
2873 *
2874 * Returns -1 if x < y, 0 if x == y, 1 if x > y and -2 in case of error
2875 */
2876static int
2877xmlSchemaCompareDecimals(xmlSchemaValPtr x, xmlSchemaValPtr y)
2878{
2879 xmlSchemaValPtr swp;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002880 int order = 1, p;
Daniel Veillard4255d502002-04-16 15:50:10 +00002881 unsigned long tmp;
2882
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002883 if ((x->value.decimal.sign) &&
2884 ((x->value.decimal.lo != 0) ||
2885 (x->value.decimal.mi != 0) ||
2886 (x->value.decimal.hi != 0))) {
2887 if ((y->value.decimal.sign) &&
2888 ((y->value.decimal.lo != 0) ||
2889 (y->value.decimal.mi != 0) ||
2890 (y->value.decimal.hi != 0)))
Daniel Veillard80b19092003-03-28 13:29:53 +00002891 order = -1;
2892 else
2893 return (-1);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002894 } else if ((y->value.decimal.sign) &&
2895 ((y->value.decimal.lo != 0) ||
2896 (y->value.decimal.mi != 0) ||
2897 (y->value.decimal.hi != 0))) {
Daniel Veillard4255d502002-04-16 15:50:10 +00002898 return (1);
Daniel Veillard80b19092003-03-28 13:29:53 +00002899 }
Daniel Veillard4255d502002-04-16 15:50:10 +00002900 if (x->value.decimal.frac == y->value.decimal.frac) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002901 if (x->value.decimal.hi < y->value.decimal.hi)
2902 return (-order);
Daniel Veillard01fa6152004-06-29 17:04:39 +00002903 if (x->value.decimal.hi > y->value.decimal.hi)
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002904 return (order);
2905 if (x->value.decimal.mi < y->value.decimal.mi)
2906 return (-order);
Daniel Veillard01fa6152004-06-29 17:04:39 +00002907 if (x->value.decimal.mi > y->value.decimal.mi)
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002908 return (order);
2909 if (x->value.decimal.lo < y->value.decimal.lo)
Daniel Veillard80b19092003-03-28 13:29:53 +00002910 return (-order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002911 if (x->value.decimal.lo > y->value.decimal.lo)
Daniel Veillard80b19092003-03-28 13:29:53 +00002912 return(order);
2913 return(0);
Daniel Veillard4255d502002-04-16 15:50:10 +00002914 }
2915 if (y->value.decimal.frac > x->value.decimal.frac) {
2916 swp = y;
2917 y = x;
2918 x = swp;
2919 order = -order;
2920 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002921 p = powten[x->value.decimal.frac - y->value.decimal.frac];
2922 tmp = x->value.decimal.lo / p;
2923 if (tmp > y->value.decimal.lo)
Daniel Veillard4255d502002-04-16 15:50:10 +00002924 return (order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002925 if (tmp < y->value.decimal.lo)
Daniel Veillard4255d502002-04-16 15:50:10 +00002926 return (-order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002927 tmp = y->value.decimal.lo * p;
2928 if (x->value.decimal.lo < tmp)
Daniel Veillard4255d502002-04-16 15:50:10 +00002929 return (-order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002930 if (x->value.decimal.lo == tmp)
Daniel Veillard4255d502002-04-16 15:50:10 +00002931 return (0);
2932 return (order);
2933}
2934
2935/**
Daniel Veillard070803b2002-05-03 07:29:38 +00002936 * xmlSchemaCompareDurations:
2937 * @x: a first duration value
2938 * @y: a second duration value
2939 *
2940 * Compare 2 durations
2941 *
2942 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
2943 * case of error
2944 */
2945static int
2946xmlSchemaCompareDurations(xmlSchemaValPtr x, xmlSchemaValPtr y)
2947{
2948 long carry, mon, day;
2949 double sec;
Daniel Veillard80b19092003-03-28 13:29:53 +00002950 int invert = 1;
2951 long xmon, xday, myear, minday, maxday;
Daniel Veillard070803b2002-05-03 07:29:38 +00002952 static const long dayRange [2][12] = {
2953 { 0, 28, 59, 89, 120, 150, 181, 212, 242, 273, 303, 334, },
2954 { 0, 31, 62, 92, 123, 153, 184, 215, 245, 276, 306, 337} };
2955
2956 if ((x == NULL) || (y == NULL))
Daniel Veillard5a872412002-05-22 06:40:27 +00002957 return -2;
Daniel Veillard070803b2002-05-03 07:29:38 +00002958
2959 /* months */
2960 mon = x->value.dur.mon - y->value.dur.mon;
2961
2962 /* seconds */
2963 sec = x->value.dur.sec - y->value.dur.sec;
2964 carry = (long)sec / SECS_PER_DAY;
2965 sec -= (double)(carry * SECS_PER_DAY);
2966
2967 /* days */
2968 day = x->value.dur.day - y->value.dur.day + carry;
2969
2970 /* easy test */
2971 if (mon == 0) {
2972 if (day == 0)
2973 if (sec == 0.0)
2974 return 0;
2975 else if (sec < 0.0)
2976 return -1;
2977 else
2978 return 1;
2979 else if (day < 0)
2980 return -1;
2981 else
2982 return 1;
2983 }
2984
2985 if (mon > 0) {
2986 if ((day >= 0) && (sec >= 0.0))
2987 return 1;
2988 else {
2989 xmon = mon;
2990 xday = -day;
2991 }
2992 } else if ((day <= 0) && (sec <= 0.0)) {
2993 return -1;
2994 } else {
Daniel Veillard80b19092003-03-28 13:29:53 +00002995 invert = -1;
Daniel Veillard070803b2002-05-03 07:29:38 +00002996 xmon = -mon;
2997 xday = day;
2998 }
2999
3000 myear = xmon / 12;
Daniel Veillard80b19092003-03-28 13:29:53 +00003001 if (myear == 0) {
3002 minday = 0;
3003 maxday = 0;
3004 } else {
3005 maxday = 366 * ((myear + 3) / 4) +
3006 365 * ((myear - 1) % 4);
3007 minday = maxday - 1;
3008 }
3009
Daniel Veillard070803b2002-05-03 07:29:38 +00003010 xmon = xmon % 12;
3011 minday += dayRange[0][xmon];
3012 maxday += dayRange[1][xmon];
3013
Daniel Veillard80b19092003-03-28 13:29:53 +00003014 if ((maxday == minday) && (maxday == xday))
3015 return(0); /* can this really happen ? */
Daniel Veillard070803b2002-05-03 07:29:38 +00003016 if (maxday < xday)
Daniel Veillard80b19092003-03-28 13:29:53 +00003017 return(-invert);
3018 if (minday > xday)
3019 return(invert);
Daniel Veillard070803b2002-05-03 07:29:38 +00003020
3021 /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00003022 return 2;
3023}
3024
3025/*
3026 * macros for adding date/times and durations
3027 */
3028#define FQUOTIENT(a,b) (floor(((double)a/(double)b)))
3029#define MODULO(a,b) (a - FQUOTIENT(a,b) * b)
3030#define FQUOTIENT_RANGE(a,low,high) (FQUOTIENT((a-low),(high-low)))
3031#define MODULO_RANGE(a,low,high) ((MODULO((a-low),(high-low)))+low)
3032
3033/**
Daniel Veillard669adfc2004-05-29 20:12:46 +00003034 * xmlSchemaDupVal:
3035 * @v: the #xmlSchemaValPtr value to duplicate
3036 *
3037 * Makes a copy of @v. The calling program is responsible for freeing
3038 * the returned value.
3039 *
3040 * returns a pointer to a duplicated #xmlSchemaValPtr or NULL if error.
3041 */
3042static xmlSchemaValPtr
3043xmlSchemaDupVal (xmlSchemaValPtr v)
3044{
3045 xmlSchemaValPtr ret = xmlSchemaNewValue(v->type);
3046 if (ret == NULL)
3047 return NULL;
3048
3049 memcpy(ret, v, sizeof(xmlSchemaVal));
3050 return ret;
3051}
3052
3053/**
Kasimier T. Buchcik285ebab2005-03-04 18:04:59 +00003054 * xmlSchemaCopyValue:
3055 * @val: the precomputed value to be copied
3056 *
3057 * Copies the precomputed value. This duplicates any string within.
3058 *
3059 * Returns the copy or NULL if a copy for a data-type is not implemented.
3060 */
3061xmlSchemaValPtr
3062xmlSchemaCopyValue(xmlSchemaValPtr val)
3063{
3064 xmlSchemaValPtr ret;
3065
3066 if (val == NULL)
3067 return (NULL);
3068 /*
3069 * Copy the string values.
3070 */
3071 switch (val->type) {
3072 case XML_SCHEMAS_IDREFS:
3073 case XML_SCHEMAS_ENTITIES:
3074 case XML_SCHEMAS_NMTOKENS:
3075 case XML_SCHEMAS_ANYTYPE:
3076 case XML_SCHEMAS_ANYSIMPLETYPE:
3077 return (NULL);
3078 case XML_SCHEMAS_STRING:
3079 case XML_SCHEMAS_NORMSTRING:
3080 case XML_SCHEMAS_TOKEN:
3081 case XML_SCHEMAS_LANGUAGE:
3082 case XML_SCHEMAS_NAME:
3083 case XML_SCHEMAS_NCNAME:
3084 case XML_SCHEMAS_ID:
3085 case XML_SCHEMAS_IDREF:
3086 case XML_SCHEMAS_ENTITY:
3087 case XML_SCHEMAS_NMTOKEN:
3088 ret = xmlSchemaDupVal(val);
3089 if (val->value.str != NULL)
3090 ret->value.str = xmlStrdup(BAD_CAST val->value.str);
3091 return (ret);
3092 case XML_SCHEMAS_QNAME:
3093 case XML_SCHEMAS_ANYURI:
3094 case XML_SCHEMAS_NOTATION:
3095 ret = xmlSchemaDupVal(val);
3096 if (val->value.qname.name != NULL)
3097 ret->value.qname.name =
3098 xmlStrdup(BAD_CAST val->value.qname.name);
3099 if (val->value.qname.uri != NULL)
3100 ret->value.qname.uri =
3101 xmlStrdup(BAD_CAST val->value.qname.uri);
3102 return (ret);
3103 case XML_SCHEMAS_HEXBINARY:
3104 ret = xmlSchemaDupVal(val);
3105 if (val->value.hex.str != NULL)
3106 ret->value.hex.str = xmlStrdup(BAD_CAST val->value.hex.str);
3107 return (ret);
3108 case XML_SCHEMAS_BASE64BINARY:
3109 ret = xmlSchemaDupVal(val);
3110 if (val->value.base64.str != NULL)
3111 ret->value.base64.str =
3112 xmlStrdup(BAD_CAST val->value.base64.str);
3113 return (ret);
3114 default:
3115 return (xmlSchemaDupVal(val));
3116 }
3117 return (NULL);
3118}
3119
3120/**
Daniel Veillard5a872412002-05-22 06:40:27 +00003121 * _xmlSchemaDateAdd:
3122 * @dt: an #xmlSchemaValPtr
3123 * @dur: an #xmlSchemaValPtr of type #XS_DURATION
3124 *
3125 * Compute a new date/time from @dt and @dur. This function assumes @dt
3126 * is either #XML_SCHEMAS_DATETIME, #XML_SCHEMAS_DATE, #XML_SCHEMAS_GYEARMONTH,
Daniel Veillard669adfc2004-05-29 20:12:46 +00003127 * or #XML_SCHEMAS_GYEAR. The returned #xmlSchemaVal is the same type as
3128 * @dt. The calling program is responsible for freeing the returned value.
Daniel Veillard5a872412002-05-22 06:40:27 +00003129 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00003130 * Returns a pointer to a new #xmlSchemaVal or NULL if error.
Daniel Veillard5a872412002-05-22 06:40:27 +00003131 */
3132static xmlSchemaValPtr
3133_xmlSchemaDateAdd (xmlSchemaValPtr dt, xmlSchemaValPtr dur)
3134{
Daniel Veillard669adfc2004-05-29 20:12:46 +00003135 xmlSchemaValPtr ret, tmp;
Daniel Veillard5a872412002-05-22 06:40:27 +00003136 long carry, tempdays, temp;
3137 xmlSchemaValDatePtr r, d;
3138 xmlSchemaValDurationPtr u;
3139
3140 if ((dt == NULL) || (dur == NULL))
3141 return NULL;
3142
3143 ret = xmlSchemaNewValue(dt->type);
3144 if (ret == NULL)
3145 return NULL;
3146
Daniel Veillard669adfc2004-05-29 20:12:46 +00003147 /* make a copy so we don't alter the original value */
3148 tmp = xmlSchemaDupVal(dt);
3149 if (tmp == NULL) {
3150 xmlSchemaFreeValue(ret);
3151 return NULL;
3152 }
3153
Daniel Veillard5a872412002-05-22 06:40:27 +00003154 r = &(ret->value.date);
Daniel Veillard669adfc2004-05-29 20:12:46 +00003155 d = &(tmp->value.date);
Daniel Veillard5a872412002-05-22 06:40:27 +00003156 u = &(dur->value.dur);
3157
3158 /* normalization */
3159 if (d->mon == 0)
3160 d->mon = 1;
3161
3162 /* normalize for time zone offset */
3163 u->sec -= (d->tzo * 60);
3164 d->tzo = 0;
3165
3166 /* normalization */
3167 if (d->day == 0)
3168 d->day = 1;
3169
3170 /* month */
3171 carry = d->mon + u->mon;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003172 r->mon = (unsigned int) MODULO_RANGE(carry, 1, 13);
3173 carry = (long) FQUOTIENT_RANGE(carry, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00003174
3175 /* year (may be modified later) */
3176 r->year = d->year + carry;
3177 if (r->year == 0) {
3178 if (d->year > 0)
3179 r->year--;
3180 else
3181 r->year++;
3182 }
3183
3184 /* time zone */
3185 r->tzo = d->tzo;
3186 r->tz_flag = d->tz_flag;
3187
3188 /* seconds */
3189 r->sec = d->sec + u->sec;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003190 carry = (long) FQUOTIENT((long)r->sec, 60);
Daniel Veillard5a872412002-05-22 06:40:27 +00003191 if (r->sec != 0.0) {
3192 r->sec = MODULO(r->sec, 60.0);
3193 }
3194
3195 /* minute */
3196 carry += d->min;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003197 r->min = (unsigned int) MODULO(carry, 60);
3198 carry = (long) FQUOTIENT(carry, 60);
Daniel Veillard5a872412002-05-22 06:40:27 +00003199
3200 /* hours */
3201 carry += d->hour;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003202 r->hour = (unsigned int) MODULO(carry, 24);
3203 carry = (long)FQUOTIENT(carry, 24);
Daniel Veillard5a872412002-05-22 06:40:27 +00003204
3205 /*
3206 * days
3207 * Note we use tempdays because the temporary values may need more
3208 * than 5 bits
3209 */
3210 if ((VALID_YEAR(r->year)) && (VALID_MONTH(r->mon)) &&
3211 (d->day > MAX_DAYINMONTH(r->year, r->mon)))
3212 tempdays = MAX_DAYINMONTH(r->year, r->mon);
3213 else if (d->day < 1)
3214 tempdays = 1;
3215 else
3216 tempdays = d->day;
3217
3218 tempdays += u->day + carry;
3219
3220 while (1) {
3221 if (tempdays < 1) {
Daniel Veillardebe25d42004-03-25 09:35:49 +00003222 long tmon = (long) MODULO_RANGE(r->mon-1, 1, 13);
3223 long tyr = r->year + (long)FQUOTIENT_RANGE(r->mon-1, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00003224 if (tyr == 0)
3225 tyr--;
3226 tempdays += MAX_DAYINMONTH(tyr, tmon);
3227 carry = -1;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003228 } else if (tempdays > (long) MAX_DAYINMONTH(r->year, r->mon)) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003229 tempdays = tempdays - MAX_DAYINMONTH(r->year, r->mon);
3230 carry = 1;
3231 } else
3232 break;
3233
3234 temp = r->mon + carry;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003235 r->mon = (unsigned int) MODULO_RANGE(temp, 1, 13);
3236 r->year = r->year + (unsigned int) FQUOTIENT_RANGE(temp, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00003237 if (r->year == 0) {
3238 if (temp < 1)
3239 r->year--;
3240 else
3241 r->year++;
3242 }
3243 }
3244
3245 r->day = tempdays;
3246
3247 /*
3248 * adjust the date/time type to the date values
3249 */
3250 if (ret->type != XML_SCHEMAS_DATETIME) {
3251 if ((r->hour) || (r->min) || (r->sec))
3252 ret->type = XML_SCHEMAS_DATETIME;
3253 else if (ret->type != XML_SCHEMAS_DATE) {
3254 if ((r->mon != 1) && (r->day != 1))
3255 ret->type = XML_SCHEMAS_DATE;
3256 else if ((ret->type != XML_SCHEMAS_GYEARMONTH) && (r->mon != 1))
3257 ret->type = XML_SCHEMAS_GYEARMONTH;
3258 }
3259 }
3260
Daniel Veillard669adfc2004-05-29 20:12:46 +00003261 xmlSchemaFreeValue(tmp);
Daniel Veillard5a872412002-05-22 06:40:27 +00003262
Daniel Veillard5a872412002-05-22 06:40:27 +00003263 return ret;
3264}
3265
3266/**
3267 * xmlSchemaDateNormalize:
Daniel Veillard669adfc2004-05-29 20:12:46 +00003268 * @dt: an #xmlSchemaValPtr of a date/time type value.
3269 * @offset: number of seconds to adjust @dt by.
Daniel Veillard5a872412002-05-22 06:40:27 +00003270 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00003271 * Normalize @dt to GMT time. The @offset parameter is subtracted from
3272 * the return value is a time-zone offset is present on @dt.
Daniel Veillard5a872412002-05-22 06:40:27 +00003273 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00003274 * Returns a normalized copy of @dt or NULL if error.
Daniel Veillard5a872412002-05-22 06:40:27 +00003275 */
3276static xmlSchemaValPtr
3277xmlSchemaDateNormalize (xmlSchemaValPtr dt, double offset)
3278{
3279 xmlSchemaValPtr dur, ret;
3280
3281 if (dt == NULL)
3282 return NULL;
3283
3284 if (((dt->type != XML_SCHEMAS_TIME) &&
3285 (dt->type != XML_SCHEMAS_DATETIME)) || (dt->value.date.tzo == 0))
3286 return xmlSchemaDupVal(dt);
3287
3288 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
3289 if (dur == NULL)
3290 return NULL;
3291
3292 dur->value.date.sec -= offset;
3293
3294 ret = _xmlSchemaDateAdd(dt, dur);
3295 if (ret == NULL)
3296 return NULL;
3297
3298 xmlSchemaFreeValue(dur);
3299
3300 /* ret->value.date.tzo = 0; */
3301 return ret;
3302}
3303
3304/**
3305 * _xmlSchemaDateCastYMToDays:
3306 * @dt: an #xmlSchemaValPtr
3307 *
3308 * Convert mon and year of @dt to total number of days. Take the
3309 * number of years since (or before) 1 AD and add the number of leap
3310 * years. This is a function because negative
3311 * years must be handled a little differently and there is no zero year.
3312 *
3313 * Returns number of days.
3314 */
3315static long
3316_xmlSchemaDateCastYMToDays (const xmlSchemaValPtr dt)
3317{
3318 long ret;
Daniel Veillard49e89632004-09-23 16:24:36 +00003319 int mon;
Daniel Veillard5a872412002-05-22 06:40:27 +00003320
Daniel Veillard49e89632004-09-23 16:24:36 +00003321 mon = dt->value.date.mon;
3322 if (mon <= 0) mon = 1; /* normalization */
3323
3324 if (dt->value.date.year <= 0)
Daniel Veillard5a872412002-05-22 06:40:27 +00003325 ret = (dt->value.date.year * 365) +
3326 (((dt->value.date.year+1)/4)-((dt->value.date.year+1)/100)+
3327 ((dt->value.date.year+1)/400)) +
Daniel Veillard49e89632004-09-23 16:24:36 +00003328 DAY_IN_YEAR(0, mon, dt->value.date.year);
Daniel Veillard5a872412002-05-22 06:40:27 +00003329 else
3330 ret = ((dt->value.date.year-1) * 365) +
3331 (((dt->value.date.year-1)/4)-((dt->value.date.year-1)/100)+
3332 ((dt->value.date.year-1)/400)) +
Daniel Veillard49e89632004-09-23 16:24:36 +00003333 DAY_IN_YEAR(0, mon, dt->value.date.year);
Daniel Veillard5a872412002-05-22 06:40:27 +00003334
3335 return ret;
3336}
3337
3338/**
3339 * TIME_TO_NUMBER:
3340 * @dt: an #xmlSchemaValPtr
3341 *
3342 * Calculates the number of seconds in the time portion of @dt.
3343 *
3344 * Returns seconds.
3345 */
3346#define TIME_TO_NUMBER(dt) \
3347 ((double)((dt->value.date.hour * SECS_PER_HOUR) + \
Daniel Veillardb3721c22003-03-31 11:22:25 +00003348 (dt->value.date.min * SECS_PER_MIN) + \
3349 (dt->value.date.tzo * SECS_PER_MIN)) + \
3350 dt->value.date.sec)
Daniel Veillard5a872412002-05-22 06:40:27 +00003351
3352/**
3353 * xmlSchemaCompareDates:
3354 * @x: a first date/time value
3355 * @y: a second date/time value
3356 *
3357 * Compare 2 date/times
3358 *
3359 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3360 * case of error
3361 */
3362static int
3363xmlSchemaCompareDates (xmlSchemaValPtr x, xmlSchemaValPtr y)
3364{
3365 unsigned char xmask, ymask, xor_mask, and_mask;
3366 xmlSchemaValPtr p1, p2, q1, q2;
3367 long p1d, p2d, q1d, q2d;
3368
3369 if ((x == NULL) || (y == NULL))
3370 return -2;
3371
3372 if (x->value.date.tz_flag) {
3373
3374 if (!y->value.date.tz_flag) {
3375 p1 = xmlSchemaDateNormalize(x, 0);
3376 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3377 /* normalize y + 14:00 */
3378 q1 = xmlSchemaDateNormalize(y, (14 * SECS_PER_HOUR));
3379
3380 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003381 if (p1d < q1d) {
3382 xmlSchemaFreeValue(p1);
3383 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003384 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003385 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003386 double sec;
3387
3388 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00003389 if (sec < 0.0) {
3390 xmlSchemaFreeValue(p1);
3391 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003392 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003393 } else {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003394 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003395 /* normalize y - 14:00 */
3396 q2 = xmlSchemaDateNormalize(y, -(14 * SECS_PER_HOUR));
3397 q2d = _xmlSchemaDateCastYMToDays(q2) + q2->value.date.day;
3398 if (p1d > q2d)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003399 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003400 else if (p1d == q2d) {
3401 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q2);
3402 if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003403 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003404 else
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003405 ret = 2; /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00003406 }
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003407 xmlSchemaFreeValue(p1);
3408 xmlSchemaFreeValue(q1);
3409 xmlSchemaFreeValue(q2);
3410 if (ret != 0)
3411 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003412 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00003413 } else {
3414 xmlSchemaFreeValue(p1);
3415 xmlSchemaFreeValue(q1);
3416 }
Daniel Veillard5a872412002-05-22 06:40:27 +00003417 }
3418 } else if (y->value.date.tz_flag) {
3419 q1 = xmlSchemaDateNormalize(y, 0);
3420 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
3421
3422 /* normalize x - 14:00 */
3423 p1 = xmlSchemaDateNormalize(x, -(14 * SECS_PER_HOUR));
3424 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3425
Daniel Veillardfdc91562002-07-01 21:52:03 +00003426 if (p1d < q1d) {
3427 xmlSchemaFreeValue(p1);
3428 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003429 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003430 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003431 double sec;
3432
3433 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00003434 if (sec < 0.0) {
3435 xmlSchemaFreeValue(p1);
3436 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003437 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003438 } else {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003439 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003440 /* normalize x + 14:00 */
3441 p2 = xmlSchemaDateNormalize(x, (14 * SECS_PER_HOUR));
3442 p2d = _xmlSchemaDateCastYMToDays(p2) + p2->value.date.day;
3443
Daniel Veillard6560a422003-03-27 21:25:38 +00003444 if (p2d > q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003445 ret = 1;
Daniel Veillard6560a422003-03-27 21:25:38 +00003446 } else if (p2d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003447 sec = TIME_TO_NUMBER(p2) - TIME_TO_NUMBER(q1);
3448 if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003449 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003450 else
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003451 ret = 2; /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00003452 }
Daniel Veillard6560a422003-03-27 21:25:38 +00003453 xmlSchemaFreeValue(p1);
3454 xmlSchemaFreeValue(q1);
3455 xmlSchemaFreeValue(p2);
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003456 if (ret != 0)
3457 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003458 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00003459 } else {
3460 xmlSchemaFreeValue(p1);
3461 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003462 }
3463 }
3464
3465 /*
3466 * if the same type then calculate the difference
3467 */
3468 if (x->type == y->type) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003469 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003470 q1 = xmlSchemaDateNormalize(y, 0);
3471 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
3472
3473 p1 = xmlSchemaDateNormalize(x, 0);
3474 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3475
Daniel Veillardfdc91562002-07-01 21:52:03 +00003476 if (p1d < q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003477 ret = -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003478 } else if (p1d > q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003479 ret = 1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003480 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00003481 double sec;
3482
3483 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
3484 if (sec < 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003485 ret = -1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003486 else if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003487 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003488
3489 }
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003490 xmlSchemaFreeValue(p1);
3491 xmlSchemaFreeValue(q1);
3492 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003493 }
3494
3495 switch (x->type) {
3496 case XML_SCHEMAS_DATETIME:
3497 xmask = 0xf;
3498 break;
3499 case XML_SCHEMAS_DATE:
3500 xmask = 0x7;
3501 break;
3502 case XML_SCHEMAS_GYEAR:
3503 xmask = 0x1;
3504 break;
3505 case XML_SCHEMAS_GMONTH:
3506 xmask = 0x2;
3507 break;
3508 case XML_SCHEMAS_GDAY:
3509 xmask = 0x3;
3510 break;
3511 case XML_SCHEMAS_GYEARMONTH:
3512 xmask = 0x3;
3513 break;
3514 case XML_SCHEMAS_GMONTHDAY:
3515 xmask = 0x6;
3516 break;
3517 case XML_SCHEMAS_TIME:
3518 xmask = 0x8;
3519 break;
3520 default:
3521 xmask = 0;
3522 break;
3523 }
3524
3525 switch (y->type) {
3526 case XML_SCHEMAS_DATETIME:
3527 ymask = 0xf;
3528 break;
3529 case XML_SCHEMAS_DATE:
3530 ymask = 0x7;
3531 break;
3532 case XML_SCHEMAS_GYEAR:
3533 ymask = 0x1;
3534 break;
3535 case XML_SCHEMAS_GMONTH:
3536 ymask = 0x2;
3537 break;
3538 case XML_SCHEMAS_GDAY:
3539 ymask = 0x3;
3540 break;
3541 case XML_SCHEMAS_GYEARMONTH:
3542 ymask = 0x3;
3543 break;
3544 case XML_SCHEMAS_GMONTHDAY:
3545 ymask = 0x6;
3546 break;
3547 case XML_SCHEMAS_TIME:
3548 ymask = 0x8;
3549 break;
3550 default:
3551 ymask = 0;
3552 break;
3553 }
3554
3555 xor_mask = xmask ^ ymask; /* mark type differences */
3556 and_mask = xmask & ymask; /* mark field specification */
3557
3558 /* year */
3559 if (xor_mask & 1)
3560 return 2; /* indeterminate */
3561 else if (and_mask & 1) {
3562 if (x->value.date.year < y->value.date.year)
3563 return -1;
3564 else if (x->value.date.year > y->value.date.year)
3565 return 1;
3566 }
3567
3568 /* month */
3569 if (xor_mask & 2)
3570 return 2; /* indeterminate */
3571 else if (and_mask & 2) {
3572 if (x->value.date.mon < y->value.date.mon)
3573 return -1;
3574 else if (x->value.date.mon > y->value.date.mon)
3575 return 1;
3576 }
3577
3578 /* day */
3579 if (xor_mask & 4)
3580 return 2; /* indeterminate */
3581 else if (and_mask & 4) {
3582 if (x->value.date.day < y->value.date.day)
3583 return -1;
3584 else if (x->value.date.day > y->value.date.day)
3585 return 1;
3586 }
3587
3588 /* time */
3589 if (xor_mask & 8)
3590 return 2; /* indeterminate */
3591 else if (and_mask & 8) {
3592 if (x->value.date.hour < y->value.date.hour)
3593 return -1;
3594 else if (x->value.date.hour > y->value.date.hour)
3595 return 1;
3596 else if (x->value.date.min < y->value.date.min)
3597 return -1;
3598 else if (x->value.date.min > y->value.date.min)
3599 return 1;
3600 else if (x->value.date.sec < y->value.date.sec)
3601 return -1;
3602 else if (x->value.date.sec > y->value.date.sec)
3603 return 1;
3604 }
3605
Daniel Veillard070803b2002-05-03 07:29:38 +00003606 return 0;
3607}
3608
3609/**
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003610 * xmlSchemaComparePreserveReplaceStrings:
3611 * @x: a first string value
3612 * @y: a second string value
3613 * @invert: inverts the result if x < y or x > y.
3614 *
3615 * Compare 2 string for their normalized values.
3616 * @x is a string with whitespace of "preserve", @y is
3617 * a string with a whitespace of "replace". I.e. @x could
3618 * be an "xsd:string" and @y an "xsd:normalizedString".
3619 *
3620 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
3621 * case of error
3622 */
3623static int
3624xmlSchemaComparePreserveReplaceStrings(xmlSchemaValPtr x, xmlSchemaValPtr y,
3625 int invert)
3626{
3627 const xmlChar *utf1;
3628 const xmlChar *utf2;
3629 int tmp;
3630
3631 if ((x == NULL) || (y == NULL))
3632 return(-2);
3633 utf1 = x->value.str;
3634 utf2 = y->value.str;
3635
3636 while ((*utf1 != 0) && (*utf2 != 0)) {
3637 if (IS_WSP_REPLACE_CH(*utf2)) {
3638 if (! IS_WSP_SPACE_CH(*utf1)) {
3639 if ((*utf1 - 0x20) < 0) {
3640 if (invert)
3641 return(1);
3642 else
3643 return(-1);
3644 } else {
3645 if (invert)
3646 return(-1);
3647 else
3648 return(1);
3649 }
3650 }
3651 } else {
3652 tmp = *utf1 - *utf2;
3653 if (tmp < 0) {
3654 if (invert)
3655 return(1);
3656 else
3657 return(-1);
3658 }
3659 if (tmp > 0) {
3660 if (invert)
3661 return(-1);
3662 else
3663 return(1);
3664 }
3665 }
3666 utf1++;
3667 utf2++;
3668 }
3669 if (*utf1 != 0) {
3670 if (invert)
3671 return(-1);
3672 else
3673 return(1);
3674 }
3675 if (*utf2 != 0) {
3676 if (invert)
3677 return(1);
3678 else
3679 return(-1);
3680 }
3681 return(0);
3682}
3683
3684/**
3685 * xmlSchemaComparePreserveCollapseStrings:
3686 * @x: a first string value
3687 * @y: a second string value
3688 *
3689 * Compare 2 string for their normalized values.
3690 * @x is a string with whitespace of "preserve", @y is
3691 * a string with a whitespace of "collapse". I.e. @x could
3692 * be an "xsd:string" and @y an "xsd:normalizedString".
3693 *
3694 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
3695 * case of error
3696 */
3697static int
3698xmlSchemaComparePreserveCollapseStrings(xmlSchemaValPtr x, xmlSchemaValPtr y,
3699 int invert)
3700{
3701 const xmlChar *utf1;
3702 const xmlChar *utf2;
3703 int tmp;
3704
3705 if ((x == NULL) || (y == NULL))
3706 return(-2);
3707 utf1 = x->value.str;
3708 utf2 = y->value.str;
3709
3710 /*
3711 * Skip leading blank chars of the collapsed string.
3712 */
3713 while (IS_WSP_SPACE_CH(*utf2) || IS_WSP_REPLACE_CH(*utf2))
3714 utf2++;
3715
3716 while ((*utf1 != 0) && (*utf2 != 0)) {
3717 if (IS_WSP_SPACE_CH(*utf2) || IS_WSP_REPLACE_CH(*utf2)) {
3718 if (! IS_WSP_SPACE_CH(*utf1)) {
3719 /*
3720 * The utf2 character would have been replaced to 0x20.
3721 */
3722 if ((*utf1 - 0x20) < 0) {
3723 if (invert)
3724 return(1);
3725 else
3726 return(-1);
3727 } else {
3728 if (invert)
3729 return(-1);
3730 else
3731 return(1);
3732 }
3733 }
3734 utf1++;
3735 utf2++;
3736 /*
3737 * Skip contiguous blank chars of the collapsed string.
3738 */
3739 while (IS_WSP_SPACE_CH(*utf2) || IS_WSP_REPLACE_CH(*utf2))
3740 utf2++;
3741 } else {
3742 tmp = *utf1++ - *utf2++;
3743 if (tmp < 0) {
3744 if (invert)
3745 return(1);
3746 else
3747 return(-1);
3748 }
3749 if (tmp > 0) {
3750 if (invert)
3751 return(-1);
3752 else
3753 return(1);
3754 }
3755 }
3756 }
3757 if (*utf1 != 0) {
3758 if (invert)
3759 return(-1);
3760 else
3761 return(1);
3762 }
3763 if (*utf2 != 0) {
3764 /*
3765 * Skip trailing blank chars of the collapsed string.
3766 */
3767 while (IS_WSP_SPACE_CH(*utf2) || IS_WSP_REPLACE_CH(*utf2))
3768 utf2++;
3769 if (*utf2 != 0) {
3770 if (invert)
3771 return(1);
3772 else
3773 return(-1);
3774 }
3775 }
3776 return(0);
3777}
3778
3779/**
3780 * xmlSchemaComparePreserveCollapseStrings:
3781 * @x: a first string value
3782 * @y: a second string value
3783 *
3784 * Compare 2 string for their normalized values.
3785 * @x is a string with whitespace of "preserve", @y is
3786 * a string with a whitespace of "collapse". I.e. @x could
3787 * be an "xsd:string" and @y an "xsd:normalizedString".
3788 *
3789 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
3790 * case of error
3791 */
3792static int
3793xmlSchemaCompareReplaceCollapseStrings(xmlSchemaValPtr x, xmlSchemaValPtr y,
3794 int invert)
3795{
3796 const xmlChar *utf1;
3797 const xmlChar *utf2;
3798 int tmp;
3799
3800 if ((x == NULL) || (y == NULL))
3801 return(-2);
3802 utf1 = x->value.str;
3803 utf2 = y->value.str;
3804
3805 /*
3806 * Skip leading blank chars of the collapsed string.
3807 */
3808 while (IS_WSP_SPACE_CH(*utf2) || IS_WSP_REPLACE_CH(*utf2))
3809 utf2++;
3810
3811 while ((*utf1 != 0) && (*utf2 != 0)) {
3812 if (IS_WSP_SPACE_CH(*utf2) || IS_WSP_REPLACE_CH(*utf2)) {
3813 if (! (IS_WSP_SPACE_CH(*utf1) || IS_WSP_REPLACE_CH(*utf1))) {
3814 /*
3815 * The utf2 character would have been replaced to 0x20.
3816 */
3817 if ((*utf1 - 0x20) < 0) {
3818 if (invert)
3819 return(1);
3820 else
3821 return(-1);
3822 } else {
3823 if (invert)
3824 return(-1);
3825 else
3826 return(1);
3827 }
3828 }
3829 utf1++;
3830 utf2++;
3831 /*
3832 * Skip contiguous blank chars of the collapsed string.
3833 */
3834 while (IS_WSP_SPACE_CH(*utf2) || IS_WSP_REPLACE_CH(*utf2))
3835 utf2++;
3836 } else {
3837 if (IS_WSP_SPACE_CH(*utf1) || IS_WSP_REPLACE_CH(*utf1)) {
3838 /*
3839 * The utf1 character would have been replaced to 0x20.
3840 */
3841 if ((0x20 - *utf2) < 0) {
3842 if (invert)
3843 return(1);
3844 else
3845 return(-1);
3846 } else {
3847 if (invert)
3848 return(-1);
3849 else
3850 return(1);
3851 }
3852 }
3853 tmp = *utf1++ - *utf2++;
3854 if (tmp < 0)
3855 return(-1);
3856 if (tmp > 0)
3857 return(1);
3858 }
3859 }
3860 if (*utf1 != 0) {
3861 if (invert)
3862 return(-1);
3863 else
3864 return(1);
3865 }
3866 if (*utf2 != 0) {
3867 /*
3868 * Skip trailing blank chars of the collapsed string.
3869 */
3870 while (IS_WSP_SPACE_CH(*utf2) || IS_WSP_REPLACE_CH(*utf2))
3871 utf2++;
3872 if (*utf2 != 0) {
3873 if (invert)
3874 return(1);
3875 else
3876 return(-1);
3877 }
3878 }
3879 return(0);
3880}
3881
3882
3883/**
3884 * xmlSchemaCompareReplacedStrings:
3885 * @x: a first string value
3886 * @y: a second string value
3887 *
3888 * Compare 2 string for their normalized values.
3889 *
3890 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
3891 * case of error
3892 */
3893static int
3894xmlSchemaCompareReplacedStrings(xmlSchemaValPtr x, xmlSchemaValPtr y)
3895{
3896 const xmlChar *utf1;
3897 const xmlChar *utf2;
3898 int tmp;
3899
3900 if ((x == NULL) || (y == NULL))
3901 return(-2);
3902 utf1 = x->value.str;
3903 utf2 = y->value.str;
3904
3905 while ((*utf1 != 0) && (*utf2 != 0)) {
3906 if (IS_WSP_SPACE_CH(*utf2) || IS_WSP_REPLACE_CH(*utf2)) {
3907 if (! (IS_WSP_SPACE_CH(*utf1) || IS_WSP_REPLACE_CH(*utf1))) {
3908 if ((*utf1 - 0x20) < 0)
3909 return(-1);
3910 else
3911 return(1);
3912 }
3913 } else {
3914 if (IS_WSP_SPACE_CH(*utf1) || IS_WSP_REPLACE_CH(*utf1)) {
3915 if ((0x20 - *utf2) < 0)
3916 return(-1);
3917 else
3918 return(1);
3919 }
3920 tmp = *utf1 - *utf2;
3921 if (tmp < 0)
3922 return(-1);
3923 if (tmp > 0)
3924 return(1);
3925 }
3926 utf1++;
3927 utf2++;
3928 }
3929 if (*utf1 != 0)
3930 return(1);
3931 if (*utf2 != 0)
3932 return(-1);
3933 return(0);
3934}
3935
3936/**
Daniel Veillardc4c21552003-03-29 10:53:38 +00003937 * xmlSchemaCompareNormStrings:
3938 * @x: a first string value
3939 * @y: a second string value
3940 *
3941 * Compare 2 string for their normalized values.
3942 *
3943 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
3944 * case of error
3945 */
3946static int
3947xmlSchemaCompareNormStrings(xmlSchemaValPtr x, xmlSchemaValPtr y) {
3948 const xmlChar *utf1;
3949 const xmlChar *utf2;
3950 int tmp;
3951
3952 if ((x == NULL) || (y == NULL))
3953 return(-2);
3954 utf1 = x->value.str;
3955 utf2 = y->value.str;
3956
William M. Brack76e95df2003-10-18 16:20:14 +00003957 while (IS_BLANK_CH(*utf1)) utf1++;
3958 while (IS_BLANK_CH(*utf2)) utf2++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003959 while ((*utf1 != 0) && (*utf2 != 0)) {
William M. Brack76e95df2003-10-18 16:20:14 +00003960 if (IS_BLANK_CH(*utf1)) {
3961 if (!IS_BLANK_CH(*utf2)) {
Daniel Veillardc4c21552003-03-29 10:53:38 +00003962 tmp = *utf1 - *utf2;
3963 return(tmp);
3964 }
William M. Brack76e95df2003-10-18 16:20:14 +00003965 while (IS_BLANK_CH(*utf1)) utf1++;
3966 while (IS_BLANK_CH(*utf2)) utf2++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003967 } else {
3968 tmp = *utf1++ - *utf2++;
3969 if (tmp < 0)
3970 return(-1);
3971 if (tmp > 0)
3972 return(1);
3973 }
3974 }
3975 if (*utf1 != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00003976 while (IS_BLANK_CH(*utf1)) utf1++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003977 if (*utf1 != 0)
3978 return(1);
3979 }
3980 if (*utf2 != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00003981 while (IS_BLANK_CH(*utf2)) utf2++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003982 if (*utf2 != 0)
3983 return(-1);
3984 }
3985 return(0);
3986}
3987
3988/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003989 * xmlSchemaCompareFloats:
3990 * @x: a first float or double value
3991 * @y: a second float or double value
3992 *
3993 * Compare 2 values
3994 *
3995 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3996 * case of error
3997 */
3998static int
3999xmlSchemaCompareFloats(xmlSchemaValPtr x, xmlSchemaValPtr y) {
4000 double d1, d2;
4001
4002 if ((x == NULL) || (y == NULL))
4003 return(-2);
4004
4005 /*
4006 * Cast everything to doubles.
4007 */
4008 if (x->type == XML_SCHEMAS_DOUBLE)
4009 d1 = x->value.d;
4010 else if (x->type == XML_SCHEMAS_FLOAT)
4011 d1 = x->value.f;
4012 else
4013 return(-2);
4014
4015 if (y->type == XML_SCHEMAS_DOUBLE)
4016 d2 = y->value.d;
4017 else if (y->type == XML_SCHEMAS_FLOAT)
4018 d2 = y->value.f;
4019 else
4020 return(-2);
4021
4022 /*
4023 * Check for special cases.
4024 */
4025 if (xmlXPathIsNaN(d1)) {
4026 if (xmlXPathIsNaN(d2))
4027 return(0);
4028 return(1);
4029 }
4030 if (xmlXPathIsNaN(d2))
4031 return(-1);
4032 if (d1 == xmlXPathPINF) {
4033 if (d2 == xmlXPathPINF)
4034 return(0);
4035 return(1);
4036 }
4037 if (d2 == xmlXPathPINF)
4038 return(-1);
4039 if (d1 == xmlXPathNINF) {
4040 if (d2 == xmlXPathNINF)
4041 return(0);
4042 return(-1);
4043 }
4044 if (d2 == xmlXPathNINF)
4045 return(1);
4046
4047 /*
4048 * basic tests, the last one we should have equality, but
4049 * portability is more important than speed and handling
4050 * NaN or Inf in a portable way is always a challenge, so ...
4051 */
4052 if (d1 < d2)
4053 return(-1);
4054 if (d1 > d2)
4055 return(1);
4056 if (d1 == d2)
4057 return(0);
4058 return(2);
4059}
4060
4061/**
Daniel Veillard4255d502002-04-16 15:50:10 +00004062 * xmlSchemaCompareValues:
4063 * @x: a first value
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004064 * @xwtsp: the whitespace type
Daniel Veillard4255d502002-04-16 15:50:10 +00004065 * @y: a second value
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004066 * @ywtsp: the whitespace type
Daniel Veillard4255d502002-04-16 15:50:10 +00004067 *
4068 * Compare 2 values
4069 *
Daniel Veillard5a872412002-05-22 06:40:27 +00004070 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
4071 * case of error
Daniel Veillard4255d502002-04-16 15:50:10 +00004072 */
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004073static int
4074xmlSchemaCompareValuesInternal(xmlSchemaValPtr x,
4075 xmlSchemaWhitespaceValueType xws,
4076 xmlSchemaValPtr y,
4077 xmlSchemaWhitespaceValueType yws) {
Daniel Veillard4255d502002-04-16 15:50:10 +00004078 if ((x == NULL) || (y == NULL))
4079 return(-2);
4080
4081 switch (x->type) {
Daniel Veillard80b19092003-03-28 13:29:53 +00004082 case XML_SCHEMAS_UNKNOWN:
William M. Brack2f2a6632004-08-20 23:09:47 +00004083 case XML_SCHEMAS_ANYTYPE:
4084 case XML_SCHEMAS_ANYSIMPLETYPE:
Daniel Veillard80b19092003-03-28 13:29:53 +00004085 return(-2);
4086 case XML_SCHEMAS_INTEGER:
4087 case XML_SCHEMAS_NPINTEGER:
4088 case XML_SCHEMAS_NINTEGER:
4089 case XML_SCHEMAS_NNINTEGER:
4090 case XML_SCHEMAS_PINTEGER:
4091 case XML_SCHEMAS_INT:
4092 case XML_SCHEMAS_UINT:
4093 case XML_SCHEMAS_LONG:
4094 case XML_SCHEMAS_ULONG:
4095 case XML_SCHEMAS_SHORT:
4096 case XML_SCHEMAS_USHORT:
4097 case XML_SCHEMAS_BYTE:
4098 case XML_SCHEMAS_UBYTE:
Daniel Veillard4255d502002-04-16 15:50:10 +00004099 case XML_SCHEMAS_DECIMAL:
Daniel Veillard80b19092003-03-28 13:29:53 +00004100 if (y->type == x->type)
4101 return(xmlSchemaCompareDecimals(x, y));
4102 if ((y->type == XML_SCHEMAS_DECIMAL) ||
4103 (y->type == XML_SCHEMAS_INTEGER) ||
4104 (y->type == XML_SCHEMAS_NPINTEGER) ||
4105 (y->type == XML_SCHEMAS_NINTEGER) ||
4106 (y->type == XML_SCHEMAS_NNINTEGER) ||
4107 (y->type == XML_SCHEMAS_PINTEGER) ||
4108 (y->type == XML_SCHEMAS_INT) ||
4109 (y->type == XML_SCHEMAS_UINT) ||
4110 (y->type == XML_SCHEMAS_LONG) ||
4111 (y->type == XML_SCHEMAS_ULONG) ||
4112 (y->type == XML_SCHEMAS_SHORT) ||
4113 (y->type == XML_SCHEMAS_USHORT) ||
4114 (y->type == XML_SCHEMAS_BYTE) ||
4115 (y->type == XML_SCHEMAS_UBYTE))
Daniel Veillard4255d502002-04-16 15:50:10 +00004116 return(xmlSchemaCompareDecimals(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00004117 return(-2);
Daniel Veillard070803b2002-05-03 07:29:38 +00004118 case XML_SCHEMAS_DURATION:
4119 if (y->type == XML_SCHEMAS_DURATION)
4120 return(xmlSchemaCompareDurations(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00004121 return(-2);
4122 case XML_SCHEMAS_TIME:
4123 case XML_SCHEMAS_GDAY:
4124 case XML_SCHEMAS_GMONTH:
4125 case XML_SCHEMAS_GMONTHDAY:
4126 case XML_SCHEMAS_GYEAR:
4127 case XML_SCHEMAS_GYEARMONTH:
4128 case XML_SCHEMAS_DATE:
4129 case XML_SCHEMAS_DATETIME:
4130 if ((y->type == XML_SCHEMAS_DATETIME) ||
4131 (y->type == XML_SCHEMAS_TIME) ||
4132 (y->type == XML_SCHEMAS_GDAY) ||
4133 (y->type == XML_SCHEMAS_GMONTH) ||
4134 (y->type == XML_SCHEMAS_GMONTHDAY) ||
4135 (y->type == XML_SCHEMAS_GYEAR) ||
4136 (y->type == XML_SCHEMAS_DATE) ||
4137 (y->type == XML_SCHEMAS_GYEARMONTH))
4138 return (xmlSchemaCompareDates(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00004139 return (-2);
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004140 case XML_SCHEMAS_STRING:
4141 case XML_SCHEMAS_NORMSTRING:
Daniel Veillard80b19092003-03-28 13:29:53 +00004142 case XML_SCHEMAS_TOKEN:
4143 case XML_SCHEMAS_LANGUAGE:
4144 case XML_SCHEMAS_NMTOKEN:
Daniel Veillard80b19092003-03-28 13:29:53 +00004145 case XML_SCHEMAS_NAME:
Daniel Veillard80b19092003-03-28 13:29:53 +00004146 case XML_SCHEMAS_NCNAME:
4147 case XML_SCHEMAS_ID:
4148 case XML_SCHEMAS_IDREF:
Daniel Veillard80b19092003-03-28 13:29:53 +00004149 case XML_SCHEMAS_ENTITY:
Daniel Veillard80b19092003-03-28 13:29:53 +00004150 case XML_SCHEMAS_NOTATION:
4151 case XML_SCHEMAS_ANYURI:
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004152 /*
4153 * TODO: Compare those against QName.
4154 */
4155 if (y->type == XML_SCHEMAS_QNAME) {
4156 TODO
4157 return (-2);
4158 }
4159 if ((y->type == XML_SCHEMAS_STRING) ||
4160 (y->type == XML_SCHEMAS_NORMSTRING) ||
Daniel Veillardc4c21552003-03-29 10:53:38 +00004161 (y->type == XML_SCHEMAS_TOKEN) ||
4162 (y->type == XML_SCHEMAS_LANGUAGE) ||
4163 (y->type == XML_SCHEMAS_NMTOKEN) ||
4164 (y->type == XML_SCHEMAS_NAME) ||
Daniel Veillardc4c21552003-03-29 10:53:38 +00004165 (y->type == XML_SCHEMAS_NCNAME) ||
4166 (y->type == XML_SCHEMAS_ID) ||
4167 (y->type == XML_SCHEMAS_IDREF) ||
4168 (y->type == XML_SCHEMAS_ENTITY) ||
4169 (y->type == XML_SCHEMAS_NOTATION) ||
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004170 (y->type == XML_SCHEMAS_ANYURI)) {
4171
4172 if (xws == XML_SCHEMA_WHITESPACE_PRESERVE) {
4173
4174 if (yws == XML_SCHEMA_WHITESPACE_PRESERVE) {
4175 /* TODO: What about x < y or x > y. */
4176 if (xmlStrEqual(x->value.str, y->value.str))
4177 return (0);
4178 else
4179 return (2);
4180 } else if (yws == XML_SCHEMA_WHITESPACE_REPLACE)
4181 return (xmlSchemaComparePreserveReplaceStrings(x, y, 0));
4182 else if (yws == XML_SCHEMA_WHITESPACE_COLLAPSE)
4183 return (xmlSchemaComparePreserveCollapseStrings(x, y, 0));
4184
4185 } else if (xws == XML_SCHEMA_WHITESPACE_REPLACE) {
4186
4187 if (yws == XML_SCHEMA_WHITESPACE_PRESERVE)
4188 return (xmlSchemaComparePreserveReplaceStrings(y, x, 1));
4189 if (yws == XML_SCHEMA_WHITESPACE_REPLACE)
4190 return (xmlSchemaCompareReplacedStrings(x, y));
4191 if (yws == XML_SCHEMA_WHITESPACE_COLLAPSE)
4192 return (xmlSchemaCompareReplaceCollapseStrings(x, y, 0));
4193
4194 } else if (xws == XML_SCHEMA_WHITESPACE_COLLAPSE) {
4195
4196 if (yws == XML_SCHEMA_WHITESPACE_PRESERVE)
4197 return (xmlSchemaComparePreserveCollapseStrings(y, x, 1));
4198 if (yws == XML_SCHEMA_WHITESPACE_REPLACE)
4199 return (xmlSchemaCompareReplaceCollapseStrings(y, x, 1));
4200 if (yws == XML_SCHEMA_WHITESPACE_COLLAPSE)
4201 return (xmlSchemaCompareNormStrings(x, y));
4202 } else
4203 return (-2);
4204
4205 }
Daniel Veillardc4c21552003-03-29 10:53:38 +00004206 return (-2);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004207 case XML_SCHEMAS_QNAME:
4208 if (y->type == XML_SCHEMAS_QNAME) {
4209 if ((xmlStrEqual(x->value.qname.name, y->value.qname.name)) &&
4210 (xmlStrEqual(x->value.qname.uri, y->value.qname.uri)))
4211 return(0);
4212 return(2);
4213 }
4214 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00004215 case XML_SCHEMAS_FLOAT:
4216 case XML_SCHEMAS_DOUBLE:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00004217 if ((y->type == XML_SCHEMAS_FLOAT) ||
4218 (y->type == XML_SCHEMAS_DOUBLE))
4219 return (xmlSchemaCompareFloats(x, y));
4220 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00004221 case XML_SCHEMAS_BOOLEAN:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00004222 if (y->type == XML_SCHEMAS_BOOLEAN) {
4223 if (x->value.b == y->value.b)
4224 return(0);
4225 if (x->value.b == 0)
4226 return(-1);
4227 return(1);
4228 }
4229 return (-2);
Daniel Veillard560c2a42003-07-06 21:13:49 +00004230 case XML_SCHEMAS_HEXBINARY:
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004231 if (y->type == XML_SCHEMAS_HEXBINARY) {
4232 if (x->value.hex.total == y->value.hex.total) {
4233 int ret = xmlStrcmp(x->value.hex.str, y->value.hex.str);
4234 if (ret > 0)
4235 return(1);
4236 else if (ret == 0)
4237 return(0);
4238 }
4239 else if (x->value.hex.total > y->value.hex.total)
4240 return(1);
4241
4242 return(-1);
4243 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00004244 return (-2);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00004245 case XML_SCHEMAS_BASE64BINARY:
4246 if (y->type == XML_SCHEMAS_BASE64BINARY) {
4247 if (x->value.base64.total == y->value.base64.total) {
4248 int ret = xmlStrcmp(x->value.base64.str,
4249 y->value.base64.str);
4250 if (ret > 0)
4251 return(1);
4252 else if (ret == 0)
4253 return(0);
4254 }
4255 else if (x->value.base64.total > y->value.base64.total)
4256 return(1);
4257 else
4258 return(-1);
4259 }
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004260 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00004261 case XML_SCHEMAS_IDREFS:
4262 case XML_SCHEMAS_ENTITIES:
4263 case XML_SCHEMAS_NMTOKENS:
4264 TODO
4265 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00004266 }
Daniel Veillard5a872412002-05-22 06:40:27 +00004267 return -2;
Daniel Veillard4255d502002-04-16 15:50:10 +00004268}
4269
4270/**
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004271 * xmlSchemaCompareValues:
4272 * @x: a first value
4273 * @y: a second value
4274 *
4275 * Compare 2 values
4276 *
4277 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
4278 * case of error
4279 */
4280int
4281xmlSchemaCompareValues(xmlSchemaValPtr x, xmlSchemaValPtr y) {
4282 xmlSchemaWhitespaceValueType xws, yws;
4283
Daniel Veillard5e094142005-02-18 19:36:12 +00004284 if ((x == NULL) || (y == NULL))
4285 return(-2);
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004286 if (x->type == XML_SCHEMAS_STRING)
4287 xws = XML_SCHEMA_WHITESPACE_PRESERVE;
4288 else if (x->type == XML_SCHEMAS_NORMSTRING)
4289 xws = XML_SCHEMA_WHITESPACE_REPLACE;
4290 else
4291 xws = XML_SCHEMA_WHITESPACE_COLLAPSE;
4292
4293 if (y->type == XML_SCHEMAS_STRING)
4294 yws = XML_SCHEMA_WHITESPACE_PRESERVE;
4295 else if (x->type == XML_SCHEMAS_NORMSTRING)
4296 yws = XML_SCHEMA_WHITESPACE_REPLACE;
4297 else
4298 yws = XML_SCHEMA_WHITESPACE_COLLAPSE;
4299
4300 return(xmlSchemaCompareValuesInternal(x, xws, y, yws));
4301}
4302
4303/**
4304 * xmlSchemaCompareValuesWhtsp:
4305 * @x: a first value
4306 * @xws: the whitespace value of x
4307 * @y: a second value
4308 * @yws: the whitespace value of y
4309 *
4310 * Compare 2 values
4311 *
4312 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
4313 * case of error
4314 */
4315int
4316xmlSchemaCompareValuesWhtsp(xmlSchemaValPtr x,
4317 xmlSchemaWhitespaceValueType xws,
4318 xmlSchemaValPtr y,
4319 xmlSchemaWhitespaceValueType yws) {
4320 return(xmlSchemaCompareValuesInternal(x, xws, y, yws));
4321}
4322
4323/**
Daniel Veillardc4c21552003-03-29 10:53:38 +00004324 * xmlSchemaNormLen:
4325 * @value: a string
4326 *
4327 * Computes the UTF8 length of the normalized value of the string
4328 *
4329 * Returns the length or -1 in case of error.
4330 */
4331static int
4332xmlSchemaNormLen(const xmlChar *value) {
4333 const xmlChar *utf;
4334 int ret = 0;
4335
4336 if (value == NULL)
4337 return(-1);
4338 utf = value;
William M. Brack76e95df2003-10-18 16:20:14 +00004339 while (IS_BLANK_CH(*utf)) utf++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00004340 while (*utf != 0) {
4341 if (utf[0] & 0x80) {
4342 if ((utf[1] & 0xc0) != 0x80)
4343 return(-1);
4344 if ((utf[0] & 0xe0) == 0xe0) {
4345 if ((utf[2] & 0xc0) != 0x80)
4346 return(-1);
4347 if ((utf[0] & 0xf0) == 0xf0) {
4348 if ((utf[0] & 0xf8) != 0xf0 || (utf[3] & 0xc0) != 0x80)
4349 return(-1);
4350 utf += 4;
4351 } else {
4352 utf += 3;
4353 }
4354 } else {
4355 utf += 2;
4356 }
William M. Brack76e95df2003-10-18 16:20:14 +00004357 } else if (IS_BLANK_CH(*utf)) {
4358 while (IS_BLANK_CH(*utf)) utf++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00004359 if (*utf == 0)
4360 break;
4361 } else {
4362 utf++;
4363 }
4364 ret++;
4365 }
4366 return(ret);
4367}
4368
Daniel Veillard6927b102004-10-27 17:29:04 +00004369/**
4370 * xmlSchemaGetFacetValueAsULong:
4371 * @facet: an schemas type facet
4372 *
4373 * Extract the value of a facet
4374 *
4375 * Returns the value as a long
4376 */
Daniel Veillardc0826a72004-08-10 14:17:33 +00004377unsigned long
4378xmlSchemaGetFacetValueAsULong(xmlSchemaFacetPtr facet)
4379{
4380 /*
4381 * TODO: Check if this is a decimal.
4382 */
William M. Brack094dd862004-11-14 14:28:34 +00004383 if (facet == NULL)
4384 return 0;
Daniel Veillardc0826a72004-08-10 14:17:33 +00004385 return ((unsigned long) facet->val->value.decimal.lo);
4386}
4387
Daniel Veillardc4c21552003-03-29 10:53:38 +00004388/**
Daniel Veillard01fa6152004-06-29 17:04:39 +00004389 * xmlSchemaValidateListSimpleTypeFacet:
4390 * @facet: the facet to check
4391 * @value: the lexical repr of the value to validate
4392 * @actualLen: the number of list items
4393 * @expectedLen: the resulting expected number of list items
4394 *
4395 * Checks the value of a list simple type against a facet.
4396 *
4397 * Returns 0 if the value is valid, a positive error code
4398 * number otherwise and -1 in case of an internal error.
4399 */
4400int
4401xmlSchemaValidateListSimpleTypeFacet(xmlSchemaFacetPtr facet,
4402 const xmlChar *value,
4403 unsigned long actualLen,
4404 unsigned long *expectedLen)
4405{
Daniel Veillardce682bc2004-11-05 17:22:25 +00004406 if (facet == NULL)
4407 return(-1);
Daniel Veillard01fa6152004-06-29 17:04:39 +00004408 /*
4409 * TODO: Check if this will work with large numbers.
4410 * (compare value.decimal.mi and value.decimal.hi as well?).
4411 */
4412 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
4413 if (actualLen != facet->val->value.decimal.lo) {
Daniel Veillardc0826a72004-08-10 14:17:33 +00004414 if (expectedLen != 0)
4415 *expectedLen = facet->val->value.decimal.lo;
Daniel Veillard01fa6152004-06-29 17:04:39 +00004416 return (XML_SCHEMAV_CVC_LENGTH_VALID);
4417 }
4418 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
4419 if (actualLen < facet->val->value.decimal.lo) {
Daniel Veillardc0826a72004-08-10 14:17:33 +00004420 if (expectedLen != 0)
4421 *expectedLen = facet->val->value.decimal.lo;
Daniel Veillard01fa6152004-06-29 17:04:39 +00004422 return (XML_SCHEMAV_CVC_MINLENGTH_VALID);
4423 }
4424 } else if (facet->type == XML_SCHEMA_FACET_MAXLENGTH) {
4425 if (actualLen > facet->val->value.decimal.lo) {
Daniel Veillardc0826a72004-08-10 14:17:33 +00004426 if (expectedLen != 0)
4427 *expectedLen = facet->val->value.decimal.lo;
Daniel Veillard01fa6152004-06-29 17:04:39 +00004428 return (XML_SCHEMAV_CVC_MAXLENGTH_VALID);
4429 }
4430 } else
4431 /*
4432 * NOTE: That we can pass NULL as xmlSchemaValPtr to
4433 * xmlSchemaValidateFacet, since the remaining facet types
4434 * are: XML_SCHEMA_FACET_PATTERN, XML_SCHEMA_FACET_ENUMERATION.
4435 */
4436 return(xmlSchemaValidateFacet(NULL, facet, value, NULL));
4437 return (0);
4438}
4439
4440/**
Daniel Veillard6927b102004-10-27 17:29:04 +00004441 * xmlSchemaValidateLengthFacet:
Daniel Veillardc0826a72004-08-10 14:17:33 +00004442 * @type: the built-in type
4443 * @facet: the facet to check
4444 * @value: the lexical repr. of the value to be validated
4445 * @val: the precomputed value
4446 * @length: the actual length of the value
4447 *
4448 * Checka a value against a "length", "minLength" and "maxLength"
4449 * facet; sets @length to the computed length of @value.
4450 *
4451 * Returns 0 if the value is valid, a positive error code
4452 * otherwise and -1 in case of an internal or API error.
4453 */
4454int
4455xmlSchemaValidateLengthFacet(xmlSchemaTypePtr type,
4456 xmlSchemaFacetPtr facet,
4457 const xmlChar *value,
4458 xmlSchemaValPtr val,
4459 unsigned long *length)
4460{
4461 unsigned int len = 0;
4462
Daniel Veillardce682bc2004-11-05 17:22:25 +00004463 if ((length == NULL) || (facet == NULL) || (type == NULL))
4464 return (-1);
Daniel Veillardc0826a72004-08-10 14:17:33 +00004465 *length = 0;
4466 if ((facet->type != XML_SCHEMA_FACET_LENGTH) &&
4467 (facet->type != XML_SCHEMA_FACET_MAXLENGTH) &&
4468 (facet->type != XML_SCHEMA_FACET_MINLENGTH))
4469 return (-1);
4470
4471 if ((facet->val == NULL) ||
4472 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
4473 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
4474 (facet->val->value.decimal.frac != 0)) {
4475 return(-1);
4476 }
4477 if ((val != NULL) && (val->type == XML_SCHEMAS_HEXBINARY))
4478 len = val->value.hex.total;
4479 else if ((val != NULL) && (val->type == XML_SCHEMAS_BASE64BINARY))
4480 len = val->value.base64.total;
4481 else {
4482 switch (type->builtInType) {
4483 case XML_SCHEMAS_IDREF:
4484 case XML_SCHEMAS_NORMSTRING:
4485 case XML_SCHEMAS_TOKEN:
4486 case XML_SCHEMAS_LANGUAGE:
4487 case XML_SCHEMAS_NMTOKEN:
4488 case XML_SCHEMAS_NAME:
4489 case XML_SCHEMAS_NCNAME:
4490 case XML_SCHEMAS_ID:
4491 len = xmlSchemaNormLen(value);
4492 break;
4493 case XML_SCHEMAS_STRING:
4494 /*
4495 * FIXME: What exactly to do with anyURI?
4496 */
4497 case XML_SCHEMAS_ANYURI:
4498 if (value != NULL)
4499 len = xmlUTF8Strlen(value);
4500 break;
4501 default:
4502 TODO
4503 }
4504 }
4505 *length = (unsigned long) len;
4506 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
4507 if (len != facet->val->value.decimal.lo)
4508 return(XML_SCHEMAV_CVC_LENGTH_VALID);
4509 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
4510 if (len < facet->val->value.decimal.lo)
4511 return(XML_SCHEMAV_CVC_MINLENGTH_VALID);
4512 } else {
4513 if (len > facet->val->value.decimal.lo)
4514 return(XML_SCHEMAV_CVC_MAXLENGTH_VALID);
4515 }
4516
4517 return (0);
4518}
4519
4520/**
4521 * xmlSchemaValidateFacet:
Daniel Veillard01c13b52002-12-10 15:19:08 +00004522 * @base: the base type
Daniel Veillard4255d502002-04-16 15:50:10 +00004523 * @facet: the facet to check
4524 * @value: the lexical repr of the value to validate
4525 * @val: the precomputed value
4526 *
4527 * Check a value against a facet condition
4528 *
4529 * Returns 0 if the element is schemas valid, a positive error code
4530 * number otherwise and -1 in case of internal or API error.
4531 */
4532int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00004533xmlSchemaValidateFacet(xmlSchemaTypePtr base ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +00004534 xmlSchemaFacetPtr facet,
Daniel Veillard4255d502002-04-16 15:50:10 +00004535 const xmlChar *value, xmlSchemaValPtr val)
4536{
4537 int ret;
4538
Daniel Veillardce682bc2004-11-05 17:22:25 +00004539 if ((facet == NULL) || (value == NULL))
4540 return(-1);
Daniel Veillard4255d502002-04-16 15:50:10 +00004541 switch (facet->type) {
4542 case XML_SCHEMA_FACET_PATTERN:
4543 ret = xmlRegexpExec(facet->regexp, value);
4544 if (ret == 1)
4545 return(0);
4546 if (ret == 0) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00004547 return(XML_SCHEMAV_CVC_PATTERN_VALID);
Daniel Veillard4255d502002-04-16 15:50:10 +00004548 }
4549 return(ret);
4550 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
4551 ret = xmlSchemaCompareValues(val, facet->val);
4552 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004553 /* TODO error code */
Daniel Veillard4255d502002-04-16 15:50:10 +00004554 return(-1);
4555 }
4556 if (ret == -1)
4557 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00004558 /* error code */
Daniel Veillard01fa6152004-06-29 17:04:39 +00004559 return(XML_SCHEMAV_CVC_MAXEXCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00004560 case XML_SCHEMA_FACET_MAXINCLUSIVE:
4561 ret = xmlSchemaCompareValues(val, facet->val);
4562 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004563 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00004564 return(-1);
4565 }
4566 if ((ret == -1) || (ret == 0))
4567 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00004568 /* error code */
Daniel Veillard01fa6152004-06-29 17:04:39 +00004569 return(XML_SCHEMAV_CVC_MAXINCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00004570 case XML_SCHEMA_FACET_MINEXCLUSIVE:
4571 ret = xmlSchemaCompareValues(val, facet->val);
4572 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004573 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00004574 return(-1);
4575 }
4576 if (ret == 1)
4577 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00004578 /* error code */
Daniel Veillard01fa6152004-06-29 17:04:39 +00004579 return(XML_SCHEMAV_CVC_MINEXCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00004580 case XML_SCHEMA_FACET_MININCLUSIVE:
4581 ret = xmlSchemaCompareValues(val, facet->val);
4582 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004583 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00004584 return(-1);
4585 }
4586 if ((ret == 1) || (ret == 0))
4587 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00004588 /* error code */
Daniel Veillard01fa6152004-06-29 17:04:39 +00004589 return(XML_SCHEMAV_CVC_MININCLUSIVE_VALID);
Daniel Veillard8651f532002-04-17 09:06:27 +00004590 case XML_SCHEMA_FACET_WHITESPACE:
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004591 /* TODO whitespaces */
Daniel Veillard01fa6152004-06-29 17:04:39 +00004592 /*
4593 * NOTE: Whitespace should be handled to normalize
4594 * the value to be validated against a the facets;
4595 * not to normalize the value in-between.
4596 */
Daniel Veillard8651f532002-04-17 09:06:27 +00004597 return(0);
Daniel Veillard88c58912002-04-23 07:12:20 +00004598 case XML_SCHEMA_FACET_ENUMERATION:
4599 if ((facet->value != NULL) &&
4600 (xmlStrEqual(facet->value, value)))
4601 return(0);
Daniel Veillard01fa6152004-06-29 17:04:39 +00004602 return(XML_SCHEMAV_CVC_ENUMERATION_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004603 case XML_SCHEMA_FACET_LENGTH:
4604 case XML_SCHEMA_FACET_MAXLENGTH:
4605 case XML_SCHEMA_FACET_MINLENGTH: {
4606 unsigned int len = 0;
4607
4608 if ((facet->val == NULL) ||
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004609 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
4610 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004611 (facet->val->value.decimal.frac != 0)) {
4612 return(-1);
4613 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00004614 if ((val != NULL) && (val->type == XML_SCHEMAS_HEXBINARY))
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004615 len = val->value.hex.total;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00004616 else if ((val != NULL) && (val->type == XML_SCHEMAS_BASE64BINARY))
4617 len = val->value.base64.total;
4618 else {
Daniel Veillard01fa6152004-06-29 17:04:39 +00004619 switch (base->builtInType) {
Daniel Veillard560c2a42003-07-06 21:13:49 +00004620 case XML_SCHEMAS_IDREF:
4621 case XML_SCHEMAS_NORMSTRING:
4622 case XML_SCHEMAS_TOKEN:
4623 case XML_SCHEMAS_LANGUAGE:
4624 case XML_SCHEMAS_NMTOKEN:
4625 case XML_SCHEMAS_NAME:
4626 case XML_SCHEMAS_NCNAME:
4627 case XML_SCHEMAS_ID:
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004628 len = xmlSchemaNormLen(value);
4629 break;
Daniel Veillard560c2a42003-07-06 21:13:49 +00004630 case XML_SCHEMAS_STRING:
Daniel Veillard01fa6152004-06-29 17:04:39 +00004631 /*
4632 * FIXME: What exactly to do with anyURI?
4633 */
4634 case XML_SCHEMAS_ANYURI:
William M. Brackfbf2c5e2004-02-03 17:55:56 +00004635 if (value != NULL)
4636 len = xmlUTF8Strlen(value);
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004637 break;
Daniel Veillard560c2a42003-07-06 21:13:49 +00004638 default:
4639 TODO
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004640 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004641 }
4642 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004643 if (len != facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004644 return(XML_SCHEMAV_CVC_LENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004645 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004646 if (len < facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004647 return(XML_SCHEMAV_CVC_MINLENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004648 } else {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004649 if (len > facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004650 return(XML_SCHEMAV_CVC_MAXLENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004651 }
4652 break;
4653 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00004654 case XML_SCHEMA_FACET_TOTALDIGITS:
4655 case XML_SCHEMA_FACET_FRACTIONDIGITS:
4656
4657 if ((facet->val == NULL) ||
4658 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
4659 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
4660 (facet->val->value.decimal.frac != 0)) {
4661 return(-1);
4662 }
4663 if ((val == NULL) ||
4664 ((val->type != XML_SCHEMAS_DECIMAL) &&
4665 (val->type != XML_SCHEMAS_INTEGER) &&
4666 (val->type != XML_SCHEMAS_NPINTEGER) &&
4667 (val->type != XML_SCHEMAS_NINTEGER) &&
4668 (val->type != XML_SCHEMAS_NNINTEGER) &&
4669 (val->type != XML_SCHEMAS_PINTEGER) &&
4670 (val->type != XML_SCHEMAS_INT) &&
4671 (val->type != XML_SCHEMAS_UINT) &&
4672 (val->type != XML_SCHEMAS_LONG) &&
4673 (val->type != XML_SCHEMAS_ULONG) &&
4674 (val->type != XML_SCHEMAS_SHORT) &&
4675 (val->type != XML_SCHEMAS_USHORT) &&
4676 (val->type != XML_SCHEMAS_BYTE) &&
4677 (val->type != XML_SCHEMAS_UBYTE))) {
4678 return(-1);
4679 }
4680 if (facet->type == XML_SCHEMA_FACET_TOTALDIGITS) {
4681 if (val->value.decimal.total > facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004682 return(XML_SCHEMAV_CVC_TOTALDIGITS_VALID);
Daniel Veillard560c2a42003-07-06 21:13:49 +00004683
4684 } else if (facet->type == XML_SCHEMA_FACET_FRACTIONDIGITS) {
4685 if (val->value.decimal.frac > facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004686 return(XML_SCHEMAV_CVC_FRACTIONDIGITS_VALID);
Daniel Veillard560c2a42003-07-06 21:13:49 +00004687 }
4688 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00004689 default:
4690 TODO
4691 }
4692 return(0);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00004693
Daniel Veillard4255d502002-04-16 15:50:10 +00004694}
4695
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004696/**
4697 * xmlSchemaGetCanonValue:
4698 * @val: the precomputed value
4699 * @retValue: the returned value
4700 *
Daniel Veillardb5839c32005-02-19 18:27:14 +00004701 * Get a the cononical representation of the value.
4702 * The caller has to free the returned retValue.
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004703 *
4704 * Returns 0 if the value could be built and -1 in case of
4705 * API errors or if the value type is not supported yet.
4706 */
4707int
Daniel Veillardb5839c32005-02-19 18:27:14 +00004708xmlSchemaGetCanonValue(xmlSchemaValPtr val, const xmlChar **retValue)
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004709{
Daniel Veillardb5839c32005-02-19 18:27:14 +00004710 if ((retValue == NULL) || (val == NULL))
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004711 return (-1);
4712 *retValue = NULL;
4713 switch (val->type) {
4714 case XML_SCHEMAS_STRING:
4715 case XML_SCHEMAS_NORMSTRING:
4716 /*
4717 case XML_SCHEMAS_TOKEN:
4718 case XML_SCHEMAS_LANGUAGE:
4719 case XML_SCHEMAS_NMTOKEN:
4720 case XML_SCHEMAS_NAME:
4721 case XML_SCHEMAS_QNAME:
4722 case XML_SCHEMAS_NCNAME:
4723 case XML_SCHEMAS_ID:
4724 case XML_SCHEMAS_IDREF:
4725 case XML_SCHEMAS_ENTITY:
4726 case XML_SCHEMAS_NOTATION:
4727 case XML_SCHEMAS_ANYURI:
4728 */
4729 if (val->value.str == NULL)
4730 *retValue = NULL;
4731 else
4732 /* TODO: This is not yet correct for non-normalized values. */
4733 *retValue =
4734 BAD_CAST xmlStrdup((const xmlChar *) val->value.str);
4735 return (0);
4736 default:
4737 return (-1);
4738 }
4739 return (-1);
4740}
4741
Daniel Veillard4255d502002-04-16 15:50:10 +00004742#endif /* LIBXML_SCHEMAS_ENABLED */