blob: c03faaa5d0ebba7711f12706aaf28831a997e4b9 [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
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +000031#ifdef HAVE_FLOAT_H
32#include <float.h>
33#endif
Daniel Veillard070803b2002-05-03 07:29:38 +000034
Daniel Veillard4255d502002-04-16 15:50:10 +000035#define DEBUG
36
Daniel Veillardd0cf7f62004-11-09 16:17:02 +000037#ifndef LIBXML_XPATH_ENABLED
38extern double xmlXPathNAN;
39extern double xmlXPathPINF;
40extern double xmlXPathNINF;
41#endif
42
Daniel Veillard4255d502002-04-16 15:50:10 +000043#define TODO \
44 xmlGenericError(xmlGenericErrorContext, \
45 "Unimplemented block at %s:%d\n", \
46 __FILE__, __LINE__);
47
48#define XML_SCHEMAS_NAMESPACE_NAME \
49 (const xmlChar *)"http://www.w3.org/2001/XMLSchema"
50
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +000051#define IS_WSP_REPLACE_CH(c) ((((c) == 0x9) || ((c) == 0xa)) || \
52 ((c) == 0xd))
53
54#define IS_WSP_SPACE_CH(c) ((c) == 0x20)
55
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +000056#define IS_WSP_BLANK_CH(c) IS_BLANK_CH(c)
57
Daniel Veillard070803b2002-05-03 07:29:38 +000058/* Date value */
59typedef struct _xmlSchemaValDate xmlSchemaValDate;
60typedef xmlSchemaValDate *xmlSchemaValDatePtr;
61struct _xmlSchemaValDate {
62 long year;
63 unsigned int mon :4; /* 1 <= mon <= 12 */
64 unsigned int day :5; /* 1 <= day <= 31 */
65 unsigned int hour :5; /* 0 <= hour <= 23 */
66 unsigned int min :6; /* 0 <= min <= 59 */
67 double sec;
Daniel Veillarda77cf712003-05-09 23:09:55 +000068 unsigned int tz_flag :1; /* is tzo explicitely set? */
Kasimier T. Buchcik285b3672005-05-12 13:10:22 +000069 signed int tzo :12; /* -1440 <= tzo <= 1440;
70 currently only -840 to +840 are needed */
Daniel Veillard070803b2002-05-03 07:29:38 +000071};
72
73/* Duration value */
74typedef struct _xmlSchemaValDuration xmlSchemaValDuration;
75typedef xmlSchemaValDuration *xmlSchemaValDurationPtr;
76struct _xmlSchemaValDuration {
77 long mon; /* mon stores years also */
78 long day;
79 double sec; /* sec stores min and hour also */
80};
81
Daniel Veillard4255d502002-04-16 15:50:10 +000082typedef struct _xmlSchemaValDecimal xmlSchemaValDecimal;
83typedef xmlSchemaValDecimal *xmlSchemaValDecimalPtr;
84struct _xmlSchemaValDecimal {
85 /* would use long long but not portable */
Daniel Veillarde637c4a2003-03-30 21:10:09 +000086 unsigned long lo;
87 unsigned long mi;
88 unsigned long hi;
Daniel Veillard4255d502002-04-16 15:50:10 +000089 unsigned int extra;
Daniel Veillard5a872412002-05-22 06:40:27 +000090 unsigned int sign:1;
William M. Brackc1939562003-08-05 15:52:22 +000091 unsigned int frac:7;
92 unsigned int total:8;
Daniel Veillard4255d502002-04-16 15:50:10 +000093};
94
Daniel Veillarde637c4a2003-03-30 21:10:09 +000095typedef struct _xmlSchemaValQName xmlSchemaValQName;
96typedef xmlSchemaValQName *xmlSchemaValQNamePtr;
97struct _xmlSchemaValQName {
98 xmlChar *name;
99 xmlChar *uri;
100};
101
Daniel Veillard70bcb0e2003-08-08 14:00:28 +0000102typedef struct _xmlSchemaValHex xmlSchemaValHex;
103typedef xmlSchemaValHex *xmlSchemaValHexPtr;
104struct _xmlSchemaValHex {
105 xmlChar *str;
106 unsigned int total;
107};
108
Daniel Veillard1ac24d32003-08-27 14:15:15 +0000109typedef struct _xmlSchemaValBase64 xmlSchemaValBase64;
110typedef xmlSchemaValBase64 *xmlSchemaValBase64Ptr;
111struct _xmlSchemaValBase64 {
112 xmlChar *str;
113 unsigned int total;
114};
115
Daniel Veillard4255d502002-04-16 15:50:10 +0000116struct _xmlSchemaVal {
117 xmlSchemaValType type;
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +0000118 struct _xmlSchemaVal *next;
Daniel Veillard4255d502002-04-16 15:50:10 +0000119 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 ************************************************************************/
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +0000212
213/**
214 * xmlSchemaNewValue:
215 * @type: the value type
216 *
217 * Allocate a new simple type value
218 *
219 * Returns a pointer to the new value or NULL in case of error
220 */
221static xmlSchemaValPtr
222xmlSchemaNewValue(xmlSchemaValType type) {
223 xmlSchemaValPtr value;
224
225 value = (xmlSchemaValPtr) xmlMalloc(sizeof(xmlSchemaVal));
226 if (value == NULL) {
227 return(NULL);
228 }
229 memset(value, 0, sizeof(xmlSchemaVal));
230 value->type = type;
231 return(value);
232}
233
234static xmlSchemaFacetPtr
235xmlSchemaNewMinLengthFacet(int value)
236{
237 xmlSchemaFacetPtr ret;
238
239 ret = xmlSchemaNewFacet();
240 ret->type = XML_SCHEMA_FACET_MINLENGTH;
241 ret->val = xmlSchemaNewValue(XML_SCHEMAS_NNINTEGER);
242 ret->val->value.decimal.lo = value;
243 return (ret);
244}
245
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000246/*
Daniel Veillard4255d502002-04-16 15:50:10 +0000247 * xmlSchemaInitBasicType:
248 * @name: the type name
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000249 * @type: the value type associated
Daniel Veillard4255d502002-04-16 15:50:10 +0000250 *
Daniel Veillard01fa6152004-06-29 17:04:39 +0000251 * Initialize one primitive built-in type
Daniel Veillard4255d502002-04-16 15:50:10 +0000252 */
253static xmlSchemaTypePtr
Daniel Veillard01fa6152004-06-29 17:04:39 +0000254xmlSchemaInitBasicType(const char *name, xmlSchemaValType type,
255 xmlSchemaTypePtr baseType) {
Daniel Veillard4255d502002-04-16 15:50:10 +0000256 xmlSchemaTypePtr ret;
257
258 ret = (xmlSchemaTypePtr) xmlMalloc(sizeof(xmlSchemaType));
259 if (ret == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000260 xmlSchemaTypeErrMemory(NULL, "could not initialize basic types");
Daniel Veillard4255d502002-04-16 15:50:10 +0000261 return(NULL);
262 }
263 memset(ret, 0, sizeof(xmlSchemaType));
Daniel Veillardbe9c6322003-11-22 20:37:51 +0000264 ret->name = (const xmlChar *)name;
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +0000265 ret->targetNamespace = XML_SCHEMAS_NAMESPACE_NAME;
Daniel Veillard4255d502002-04-16 15:50:10 +0000266 ret->type = XML_SCHEMA_TYPE_BASIC;
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +0000267 ret->baseType = baseType;
Daniel Veillard4255d502002-04-16 15:50:10 +0000268 ret->contentType = XML_SCHEMA_CONTENT_BASIC;
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +0000269 /*
270 * Primitive types.
271 */
272 switch (type) {
Daniel Veillard01fa6152004-06-29 17:04:39 +0000273 case XML_SCHEMAS_STRING:
274 case XML_SCHEMAS_DECIMAL:
275 case XML_SCHEMAS_DATE:
276 case XML_SCHEMAS_DATETIME:
277 case XML_SCHEMAS_TIME:
278 case XML_SCHEMAS_GYEAR:
279 case XML_SCHEMAS_GYEARMONTH:
280 case XML_SCHEMAS_GMONTH:
281 case XML_SCHEMAS_GMONTHDAY:
282 case XML_SCHEMAS_GDAY:
283 case XML_SCHEMAS_DURATION:
284 case XML_SCHEMAS_FLOAT:
285 case XML_SCHEMAS_DOUBLE:
286 case XML_SCHEMAS_BOOLEAN:
287 case XML_SCHEMAS_ANYURI:
288 case XML_SCHEMAS_HEXBINARY:
289 case XML_SCHEMAS_BASE64BINARY:
290 case XML_SCHEMAS_QNAME:
291 case XML_SCHEMAS_NOTATION:
292 ret->flags |= XML_SCHEMAS_TYPE_BUILTIN_PRIMITIVE;
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +0000293 break;
William M. Brack96d2eff2004-06-30 11:48:47 +0000294 default:
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +0000295 break;
Daniel Veillard01fa6152004-06-29 17:04:39 +0000296 }
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +0000297 /*
298 * Set variety.
299 */
300 switch (type) {
301 case XML_SCHEMAS_ANYTYPE:
302 case XML_SCHEMAS_ANYSIMPLETYPE:
303 break;
304 case XML_SCHEMAS_IDREFS:
305 case XML_SCHEMAS_NMTOKENS:
306 case XML_SCHEMAS_ENTITIES:
307 ret->flags |= XML_SCHEMAS_TYPE_VARIETY_LIST;
308 ret->facets = xmlSchemaNewMinLengthFacet(1);
309 ret->flags |= XML_SCHEMAS_TYPE_HAS_FACETS;
310 break;
311 default:
312 ret->flags |= XML_SCHEMAS_TYPE_VARIETY_ATOMIC;
313 break;
314 }
Daniel Veillard4255d502002-04-16 15:50:10 +0000315 xmlHashAddEntry2(xmlSchemaTypesBank, ret->name,
316 XML_SCHEMAS_NAMESPACE_NAME, ret);
Daniel Veillard01fa6152004-06-29 17:04:39 +0000317 ret->builtInType = type;
Daniel Veillard4255d502002-04-16 15:50:10 +0000318 return(ret);
319}
320
321/*
322 * xmlSchemaInitTypes:
323 *
324 * Initialize the default XML Schemas type library
325 */
326void
Daniel Veillard6560a422003-03-27 21:25:38 +0000327xmlSchemaInitTypes(void)
328{
Daniel Veillard4255d502002-04-16 15:50:10 +0000329 if (xmlSchemaTypesInitialized != 0)
Daniel Veillard6560a422003-03-27 21:25:38 +0000330 return;
Daniel Veillard4255d502002-04-16 15:50:10 +0000331 xmlSchemaTypesBank = xmlHashCreate(40);
Daniel Veillard6560a422003-03-27 21:25:38 +0000332
Daniel Veillard01fa6152004-06-29 17:04:39 +0000333
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000334 /*
Daniel Veillard01fa6152004-06-29 17:04:39 +0000335 * 3.4.7 Built-in Complex Type Definition
336 */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000337 xmlSchemaTypeAnyTypeDef = xmlSchemaInitBasicType("anyType",
William M. Brack2f2a6632004-08-20 23:09:47 +0000338 XML_SCHEMAS_ANYTYPE,
Daniel Veillard01fa6152004-06-29 17:04:39 +0000339 NULL);
340 xmlSchemaTypeAnyTypeDef->baseType = xmlSchemaTypeAnyTypeDef;
341 xmlSchemaTypeAnyTypeDef->contentType = XML_SCHEMA_CONTENT_MIXED;
342 {
343 xmlSchemaWildcardPtr wild;
344
345 wild = (xmlSchemaWildcardPtr) xmlMalloc(sizeof(xmlSchemaWildcard));
346 if (wild == NULL) {
William M. Brack2f2a6632004-08-20 23:09:47 +0000347 xmlSchemaTypeErrMemory(NULL, "could not create an attribute wildcard on anyType");
Daniel Veillard01fa6152004-06-29 17:04:39 +0000348 return;
349 }
350 memset(wild, 0, sizeof(xmlSchemaWildcard));
351 wild->any = 1;
352 wild->processContents = XML_SCHEMAS_ANY_LAX;
353 wild->minOccurs = 1;
354 wild->maxOccurs = 1;
355 xmlSchemaTypeAnyTypeDef->attributeWildcard = wild;
356 }
357 xmlSchemaTypeAnySimpleTypeDef = xmlSchemaInitBasicType("anySimpleType",
William M. Brack2f2a6632004-08-20 23:09:47 +0000358 XML_SCHEMAS_ANYSIMPLETYPE,
Daniel Veillard01fa6152004-06-29 17:04:39 +0000359 xmlSchemaTypeAnyTypeDef);
360 /*
361 * primitive datatypes
362 */
363 xmlSchemaTypeStringDef = xmlSchemaInitBasicType("string",
364 XML_SCHEMAS_STRING,
365 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000366 xmlSchemaTypeDecimalDef = xmlSchemaInitBasicType("decimal",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000367 XML_SCHEMAS_DECIMAL,
368 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000369 xmlSchemaTypeDateDef = xmlSchemaInitBasicType("date",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000370 XML_SCHEMAS_DATE,
371 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000372 xmlSchemaTypeDatetimeDef = xmlSchemaInitBasicType("dateTime",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000373 XML_SCHEMAS_DATETIME,
374 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000375 xmlSchemaTypeTimeDef = xmlSchemaInitBasicType("time",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000376 XML_SCHEMAS_TIME,
377 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000378 xmlSchemaTypeGYearDef = xmlSchemaInitBasicType("gYear",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000379 XML_SCHEMAS_GYEAR,
380 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000381 xmlSchemaTypeGYearMonthDef = xmlSchemaInitBasicType("gYearMonth",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000382 XML_SCHEMAS_GYEARMONTH,
383 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000384 xmlSchemaTypeGMonthDef = xmlSchemaInitBasicType("gMonth",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000385 XML_SCHEMAS_GMONTH,
386 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000387 xmlSchemaTypeGMonthDayDef = xmlSchemaInitBasicType("gMonthDay",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000388 XML_SCHEMAS_GMONTHDAY,
389 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000390 xmlSchemaTypeGDayDef = xmlSchemaInitBasicType("gDay",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000391 XML_SCHEMAS_GDAY,
392 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000393 xmlSchemaTypeDurationDef = xmlSchemaInitBasicType("duration",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000394 XML_SCHEMAS_DURATION,
395 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000396 xmlSchemaTypeFloatDef = xmlSchemaInitBasicType("float",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000397 XML_SCHEMAS_FLOAT,
398 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000399 xmlSchemaTypeDoubleDef = xmlSchemaInitBasicType("double",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000400 XML_SCHEMAS_DOUBLE,
401 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000402 xmlSchemaTypeBooleanDef = xmlSchemaInitBasicType("boolean",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000403 XML_SCHEMAS_BOOLEAN,
404 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000405 xmlSchemaTypeAnyURIDef = xmlSchemaInitBasicType("anyURI",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000406 XML_SCHEMAS_ANYURI,
407 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard560c2a42003-07-06 21:13:49 +0000408 xmlSchemaTypeHexBinaryDef = xmlSchemaInitBasicType("hexBinary",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000409 XML_SCHEMAS_HEXBINARY,
410 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard1ac24d32003-08-27 14:15:15 +0000411 xmlSchemaTypeBase64BinaryDef
Daniel Veillard01fa6152004-06-29 17:04:39 +0000412 = xmlSchemaInitBasicType("base64Binary", XML_SCHEMAS_BASE64BINARY,
413 xmlSchemaTypeAnySimpleTypeDef);
414 xmlSchemaTypeNotationDef = xmlSchemaInitBasicType("NOTATION",
415 XML_SCHEMAS_NOTATION,
416 xmlSchemaTypeAnySimpleTypeDef);
417 xmlSchemaTypeQNameDef = xmlSchemaInitBasicType("QName",
418 XML_SCHEMAS_QNAME,
419 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard4255d502002-04-16 15:50:10 +0000420
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000421 /*
422 * derived datatypes
423 */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000424 xmlSchemaTypeIntegerDef = xmlSchemaInitBasicType("integer",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000425 XML_SCHEMAS_INTEGER,
426 xmlSchemaTypeDecimalDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000427 xmlSchemaTypeNonPositiveIntegerDef =
428 xmlSchemaInitBasicType("nonPositiveInteger",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000429 XML_SCHEMAS_NPINTEGER,
430 xmlSchemaTypeIntegerDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000431 xmlSchemaTypeNegativeIntegerDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000432 xmlSchemaInitBasicType("negativeInteger", XML_SCHEMAS_NINTEGER,
433 xmlSchemaTypeNonPositiveIntegerDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000434 xmlSchemaTypeLongDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000435 xmlSchemaInitBasicType("long", XML_SCHEMAS_LONG,
436 xmlSchemaTypeIntegerDef);
437 xmlSchemaTypeIntDef = xmlSchemaInitBasicType("int", XML_SCHEMAS_INT,
438 xmlSchemaTypeLongDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000439 xmlSchemaTypeShortDef = xmlSchemaInitBasicType("short",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000440 XML_SCHEMAS_SHORT,
441 xmlSchemaTypeIntDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000442 xmlSchemaTypeByteDef = xmlSchemaInitBasicType("byte",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000443 XML_SCHEMAS_BYTE,
444 xmlSchemaTypeShortDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000445 xmlSchemaTypeNonNegativeIntegerDef =
446 xmlSchemaInitBasicType("nonNegativeInteger",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000447 XML_SCHEMAS_NNINTEGER,
448 xmlSchemaTypeIntegerDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000449 xmlSchemaTypeUnsignedLongDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000450 xmlSchemaInitBasicType("unsignedLong", XML_SCHEMAS_ULONG,
451 xmlSchemaTypeNonNegativeIntegerDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000452 xmlSchemaTypeUnsignedIntDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000453 xmlSchemaInitBasicType("unsignedInt", XML_SCHEMAS_UINT,
454 xmlSchemaTypeUnsignedLongDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000455 xmlSchemaTypeUnsignedShortDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000456 xmlSchemaInitBasicType("unsignedShort", XML_SCHEMAS_USHORT,
457 xmlSchemaTypeUnsignedIntDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000458 xmlSchemaTypeUnsignedByteDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000459 xmlSchemaInitBasicType("unsignedByte", XML_SCHEMAS_UBYTE,
460 xmlSchemaTypeUnsignedShortDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000461 xmlSchemaTypePositiveIntegerDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000462 xmlSchemaInitBasicType("positiveInteger", XML_SCHEMAS_PINTEGER,
463 xmlSchemaTypeNonNegativeIntegerDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000464 xmlSchemaTypeNormStringDef = xmlSchemaInitBasicType("normalizedString",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000465 XML_SCHEMAS_NORMSTRING,
466 xmlSchemaTypeStringDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000467 xmlSchemaTypeTokenDef = xmlSchemaInitBasicType("token",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000468 XML_SCHEMAS_TOKEN,
469 xmlSchemaTypeNormStringDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000470 xmlSchemaTypeLanguageDef = xmlSchemaInitBasicType("language",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000471 XML_SCHEMAS_LANGUAGE,
472 xmlSchemaTypeTokenDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000473 xmlSchemaTypeNameDef = xmlSchemaInitBasicType("Name",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000474 XML_SCHEMAS_NAME,
475 xmlSchemaTypeTokenDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000476 xmlSchemaTypeNmtokenDef = xmlSchemaInitBasicType("NMTOKEN",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000477 XML_SCHEMAS_NMTOKEN,
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +0000478 xmlSchemaTypeTokenDef);
Daniel Veillard01fa6152004-06-29 17:04:39 +0000479 xmlSchemaTypeNCNameDef = xmlSchemaInitBasicType("NCName",
480 XML_SCHEMAS_NCNAME,
481 xmlSchemaTypeNameDef);
482 xmlSchemaTypeIdDef = xmlSchemaInitBasicType("ID", XML_SCHEMAS_ID,
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +0000483 xmlSchemaTypeNCNameDef);
Daniel Veillard01fa6152004-06-29 17:04:39 +0000484 xmlSchemaTypeIdrefDef = xmlSchemaInitBasicType("IDREF",
485 XML_SCHEMAS_IDREF,
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +0000486 xmlSchemaTypeNCNameDef);
Daniel Veillard01fa6152004-06-29 17:04:39 +0000487 xmlSchemaTypeEntityDef = xmlSchemaInitBasicType("ENTITY",
488 XML_SCHEMAS_ENTITY,
489 xmlSchemaTypeNCNameDef);
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +0000490 /*
491 * Derived list types.
492 */
493 /* ENTITIES */
Daniel Veillard01fa6152004-06-29 17:04:39 +0000494 xmlSchemaTypeEntitiesDef = xmlSchemaInitBasicType("ENTITIES",
495 XML_SCHEMAS_ENTITIES,
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +0000496 xmlSchemaTypeAnySimpleTypeDef);
497 xmlSchemaTypeEntitiesDef->subtypes = xmlSchemaTypeEntityDef;
498 /* IDREFS */
499 xmlSchemaTypeIdrefsDef = xmlSchemaInitBasicType("IDREFS",
500 XML_SCHEMAS_IDREFS,
501 xmlSchemaTypeAnySimpleTypeDef);
502 xmlSchemaTypeIdrefsDef->subtypes = xmlSchemaTypeIdrefDef;
503
504 /* NMTOKENS */
505 xmlSchemaTypeNmtokensDef = xmlSchemaInitBasicType("NMTOKENS",
506 XML_SCHEMAS_NMTOKENS,
507 xmlSchemaTypeAnySimpleTypeDef);
508 xmlSchemaTypeNmtokensDef->subtypes = xmlSchemaTypeNmtokenDef;
509
Daniel Veillard4255d502002-04-16 15:50:10 +0000510 xmlSchemaTypesInitialized = 1;
511}
512
513/**
514 * xmlSchemaCleanupTypes:
515 *
516 * Cleanup the default XML Schemas type library
517 */
518void
519xmlSchemaCleanupTypes(void) {
520 if (xmlSchemaTypesInitialized == 0)
521 return;
Daniel Veillard01fa6152004-06-29 17:04:39 +0000522 xmlSchemaFreeWildcard(xmlSchemaTypeAnyTypeDef->attributeWildcard);
Daniel Veillard4255d502002-04-16 15:50:10 +0000523 xmlHashFree(xmlSchemaTypesBank, (xmlHashDeallocator) xmlSchemaFreeType);
524 xmlSchemaTypesInitialized = 0;
525}
526
527/**
Daniel Veillard6927b102004-10-27 17:29:04 +0000528 * xmlSchemaIsBuiltInTypeFacet:
Daniel Veillard01fa6152004-06-29 17:04:39 +0000529 * @type: the built-in type
530 * @facetType: the facet type
531 *
532 * Evaluates if a specific facet can be
533 * used in conjunction with a type.
534 *
535 * Returns 1 if the facet can be used with the given built-in type,
536 * 0 otherwise and -1 in case the type is not a built-in type.
537 */
538int
539xmlSchemaIsBuiltInTypeFacet(xmlSchemaTypePtr type, int facetType)
540{
Daniel Veillardce682bc2004-11-05 17:22:25 +0000541 if (type == NULL)
542 return (-1);
Daniel Veillard01fa6152004-06-29 17:04:39 +0000543 if (type->type != XML_SCHEMA_TYPE_BASIC)
544 return (-1);
545 switch (type->builtInType) {
546 case XML_SCHEMAS_BOOLEAN:
547 if ((facetType == XML_SCHEMA_FACET_PATTERN) ||
548 (facetType == XML_SCHEMA_FACET_WHITESPACE))
549 return (1);
550 else
551 return (0);
552 case XML_SCHEMAS_STRING:
553 case XML_SCHEMAS_NOTATION:
554 case XML_SCHEMAS_QNAME:
555 case XML_SCHEMAS_ANYURI:
556 case XML_SCHEMAS_BASE64BINARY:
557 case XML_SCHEMAS_HEXBINARY:
558 if ((facetType == XML_SCHEMA_FACET_LENGTH) ||
559 (facetType == XML_SCHEMA_FACET_MINLENGTH) ||
560 (facetType == XML_SCHEMA_FACET_MAXLENGTH) ||
561 (facetType == XML_SCHEMA_FACET_PATTERN) ||
562 (facetType == XML_SCHEMA_FACET_ENUMERATION) ||
563 (facetType == XML_SCHEMA_FACET_WHITESPACE))
564 return (1);
565 else
566 return (0);
567 case XML_SCHEMAS_DECIMAL:
568 if ((facetType == XML_SCHEMA_FACET_TOTALDIGITS) ||
569 (facetType == XML_SCHEMA_FACET_FRACTIONDIGITS) ||
570 (facetType == XML_SCHEMA_FACET_PATTERN) ||
571 (facetType == XML_SCHEMA_FACET_WHITESPACE) ||
572 (facetType == XML_SCHEMA_FACET_ENUMERATION) ||
573 (facetType == XML_SCHEMA_FACET_MAXINCLUSIVE) ||
574 (facetType == XML_SCHEMA_FACET_MAXEXCLUSIVE) ||
575 (facetType == XML_SCHEMA_FACET_MININCLUSIVE) ||
576 (facetType == XML_SCHEMA_FACET_MINEXCLUSIVE))
577 return (1);
578 else
579 return (0);
580 case XML_SCHEMAS_TIME:
581 case XML_SCHEMAS_GDAY:
582 case XML_SCHEMAS_GMONTH:
583 case XML_SCHEMAS_GMONTHDAY:
584 case XML_SCHEMAS_GYEAR:
585 case XML_SCHEMAS_GYEARMONTH:
586 case XML_SCHEMAS_DATE:
587 case XML_SCHEMAS_DATETIME:
588 case XML_SCHEMAS_DURATION:
589 case XML_SCHEMAS_FLOAT:
590 case XML_SCHEMAS_DOUBLE:
591 if ((facetType == XML_SCHEMA_FACET_PATTERN) ||
592 (facetType == XML_SCHEMA_FACET_ENUMERATION) ||
593 (facetType == XML_SCHEMA_FACET_WHITESPACE) ||
594 (facetType == XML_SCHEMA_FACET_MAXINCLUSIVE) ||
595 (facetType == XML_SCHEMA_FACET_MAXEXCLUSIVE) ||
596 (facetType == XML_SCHEMA_FACET_MININCLUSIVE) ||
597 (facetType == XML_SCHEMA_FACET_MINEXCLUSIVE))
598 return (1);
599 else
600 return (0);
601 default:
Daniel Veillardc7e3cc42004-09-28 12:33:52 +0000602 break;
Daniel Veillard01fa6152004-06-29 17:04:39 +0000603 }
604 return (0);
605}
606
607/**
608 * xmlSchemaGetBuiltInType:
609 * @type: the type of the built in type
610 *
611 * Gives you the type struct for a built-in
612 * type by its type id.
613 *
614 * Returns the type if found, NULL otherwise.
615 */
616xmlSchemaTypePtr
617xmlSchemaGetBuiltInType(xmlSchemaValType type)
618{
619 if (xmlSchemaTypesInitialized == 0)
620 xmlSchemaInitTypes();
621 switch (type) {
622
623 case XML_SCHEMAS_ANYSIMPLETYPE:
624 return (xmlSchemaTypeAnySimpleTypeDef);
625 case XML_SCHEMAS_STRING:
626 return (xmlSchemaTypeStringDef);
627 case XML_SCHEMAS_NORMSTRING:
628 return (xmlSchemaTypeNormStringDef);
629 case XML_SCHEMAS_DECIMAL:
630 return (xmlSchemaTypeDecimalDef);
631 case XML_SCHEMAS_TIME:
632 return (xmlSchemaTypeTimeDef);
633 case XML_SCHEMAS_GDAY:
634 return (xmlSchemaTypeGDayDef);
635 case XML_SCHEMAS_GMONTH:
636 return (xmlSchemaTypeGMonthDef);
637 case XML_SCHEMAS_GMONTHDAY:
638 return (xmlSchemaTypeGMonthDayDef);
639 case XML_SCHEMAS_GYEAR:
640 return (xmlSchemaTypeGYearDef);
641 case XML_SCHEMAS_GYEARMONTH:
642 return (xmlSchemaTypeGYearMonthDef);
643 case XML_SCHEMAS_DATE:
644 return (xmlSchemaTypeDateDef);
645 case XML_SCHEMAS_DATETIME:
646 return (xmlSchemaTypeDatetimeDef);
647 case XML_SCHEMAS_DURATION:
648 return (xmlSchemaTypeDurationDef);
649 case XML_SCHEMAS_FLOAT:
650 return (xmlSchemaTypeFloatDef);
651 case XML_SCHEMAS_DOUBLE:
652 return (xmlSchemaTypeDoubleDef);
653 case XML_SCHEMAS_BOOLEAN:
654 return (xmlSchemaTypeBooleanDef);
655 case XML_SCHEMAS_TOKEN:
656 return (xmlSchemaTypeTokenDef);
657 case XML_SCHEMAS_LANGUAGE:
658 return (xmlSchemaTypeLanguageDef);
659 case XML_SCHEMAS_NMTOKEN:
660 return (xmlSchemaTypeNmtokenDef);
661 case XML_SCHEMAS_NMTOKENS:
662 return (xmlSchemaTypeNmtokensDef);
663 case XML_SCHEMAS_NAME:
664 return (xmlSchemaTypeNameDef);
665 case XML_SCHEMAS_QNAME:
666 return (xmlSchemaTypeQNameDef);
667 case XML_SCHEMAS_NCNAME:
668 return (xmlSchemaTypeNCNameDef);
669 case XML_SCHEMAS_ID:
670 return (xmlSchemaTypeIdDef);
671 case XML_SCHEMAS_IDREF:
672 return (xmlSchemaTypeIdrefDef);
673 case XML_SCHEMAS_IDREFS:
674 return (xmlSchemaTypeIdrefsDef);
675 case XML_SCHEMAS_ENTITY:
676 return (xmlSchemaTypeEntityDef);
677 case XML_SCHEMAS_ENTITIES:
678 return (xmlSchemaTypeEntitiesDef);
679 case XML_SCHEMAS_NOTATION:
680 return (xmlSchemaTypeNotationDef);
681 case XML_SCHEMAS_ANYURI:
682 return (xmlSchemaTypeAnyURIDef);
683 case XML_SCHEMAS_INTEGER:
684 return (xmlSchemaTypeIntegerDef);
685 case XML_SCHEMAS_NPINTEGER:
686 return (xmlSchemaTypeNonPositiveIntegerDef);
687 case XML_SCHEMAS_NINTEGER:
688 return (xmlSchemaTypeNegativeIntegerDef);
689 case XML_SCHEMAS_NNINTEGER:
690 return (xmlSchemaTypeNonNegativeIntegerDef);
691 case XML_SCHEMAS_PINTEGER:
692 return (xmlSchemaTypePositiveIntegerDef);
693 case XML_SCHEMAS_INT:
694 return (xmlSchemaTypeIntDef);
695 case XML_SCHEMAS_UINT:
696 return (xmlSchemaTypeUnsignedIntDef);
697 case XML_SCHEMAS_LONG:
698 return (xmlSchemaTypeLongDef);
699 case XML_SCHEMAS_ULONG:
700 return (xmlSchemaTypeUnsignedLongDef);
701 case XML_SCHEMAS_SHORT:
702 return (xmlSchemaTypeShortDef);
703 case XML_SCHEMAS_USHORT:
704 return (xmlSchemaTypeUnsignedShortDef);
705 case XML_SCHEMAS_BYTE:
706 return (xmlSchemaTypeByteDef);
707 case XML_SCHEMAS_UBYTE:
708 return (xmlSchemaTypeUnsignedByteDef);
709 case XML_SCHEMAS_HEXBINARY:
710 return (xmlSchemaTypeHexBinaryDef);
711 case XML_SCHEMAS_BASE64BINARY:
712 return (xmlSchemaTypeBase64BinaryDef);
713 case XML_SCHEMAS_ANYTYPE:
714 return (xmlSchemaTypeAnyTypeDef);
715 default:
716 return (NULL);
717 }
718}
719
Kasimier T. Buchcik7f6e0242005-06-15 13:36:10 +0000720/**
721 * xmlSchemaValueAppend:
722 * @prev: the value
723 * @cur: the value to be appended
724 *
725 * Appends a next sibling to a list of computed values.
726 *
727 * Returns 0 if succeeded and -1 on API errors.
728 */
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +0000729int
730xmlSchemaValueAppend(xmlSchemaValPtr prev, xmlSchemaValPtr cur) {
Daniel Veillard4255d502002-04-16 15:50:10 +0000731
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +0000732 if ((prev == NULL) || (cur == NULL))
733 return (-1);
734 prev->next = cur;
735 return (0);
736}
737
Kasimier T. Buchcik7f6e0242005-06-15 13:36:10 +0000738/**
739 * xmlSchemaValueGetNext:
740 * @cur: the value
741 *
742 * Accessor for the next sibling of a list of computed values.
743 *
744 * Returns the next value or NULL if there was none, or on
745 * API errors.
746 */
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +0000747xmlSchemaValPtr
748xmlSchemaValueGetNext(xmlSchemaValPtr cur) {
749
750 if (cur == NULL)
751 return (NULL);
752 return (cur->next);
753}
754
Kasimier T. Buchcik7f6e0242005-06-15 13:36:10 +0000755/**
756 * xmlSchemaValueGetAsString:
757 * @val: the value
758 *
759 * Accessor for the string value of a computed value.
760 *
761 * Returns the string value or NULL if there was none, or on
762 * API errors.
763 */
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +0000764const xmlChar *
765xmlSchemaValueGetAsString(xmlSchemaValPtr val)
766{
767 if (val == NULL)
768 return (NULL);
769 switch (val->type) {
770 case XML_SCHEMAS_STRING:
771 case XML_SCHEMAS_NORMSTRING:
772 case XML_SCHEMAS_ANYSIMPLETYPE:
773 case XML_SCHEMAS_TOKEN:
774 case XML_SCHEMAS_LANGUAGE:
775 case XML_SCHEMAS_NMTOKEN:
776 case XML_SCHEMAS_NAME:
777 case XML_SCHEMAS_NCNAME:
778 case XML_SCHEMAS_ID:
779 case XML_SCHEMAS_IDREF:
780 case XML_SCHEMAS_ENTITY:
781 case XML_SCHEMAS_ANYURI:
782 return (BAD_CAST val->value.str);
783 default:
784 break;
Daniel Veillard4255d502002-04-16 15:50:10 +0000785 }
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +0000786 return (NULL);
787}
788
Kasimier T. Buchcik7f6e0242005-06-15 13:36:10 +0000789/**
790 * xmlSchemaValueGetAsBoolean:
791 * @val: the value
792 *
793 * Accessor for the boolean value of a computed value.
794 *
795 * Returns 1 if true and 0 if false, or in case of an error. Hmm.
796 */
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +0000797int
798xmlSchemaValueGetAsBoolean(xmlSchemaValPtr val)
799{
800 if ((val == NULL) || (val->type != XML_SCHEMAS_BOOLEAN))
801 return (0);
802 return (val->value.b);
Daniel Veillard4255d502002-04-16 15:50:10 +0000803}
804
805/**
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +0000806 * xmlSchemaNewStringValue:
807 * @type: the value type
Daniel Veillardb5839c32005-02-19 18:27:14 +0000808 * @value: the value
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +0000809 *
810 * Allocate a new simple type value. The type can be
Kasimier T. Buchcik2ee855d2005-03-07 11:14:14 +0000811 * of XML_SCHEMAS_STRING.
812 * WARNING: This one is intended to be expanded for other
813 * string based types. We need this for anySimpleType as well.
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +0000814 * The given value is consumed and freed with the struct.
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +0000815 *
816 * Returns a pointer to the new value or NULL in case of error
817 */
818xmlSchemaValPtr
819xmlSchemaNewStringValue(xmlSchemaValType type,
820 const xmlChar *value)
821{
822 xmlSchemaValPtr val;
823
824 if (type != XML_SCHEMAS_STRING)
825 return(NULL);
826 val = (xmlSchemaValPtr) xmlMalloc(sizeof(xmlSchemaVal));
827 if (val == NULL) {
828 return(NULL);
829 }
830 memset(val, 0, sizeof(xmlSchemaVal));
831 val->type = type;
832 val->value.str = (xmlChar *) value;
833 return(val);
834}
835
Kasimier T. Buchcikb06b4de2005-02-17 19:00:23 +0000836/**
837 * xmlSchemaNewNOTATIONValue:
Daniel Veillardb5839c32005-02-19 18:27:14 +0000838 * @name: the notation name
839 * @ns: the notation namespace name or NULL
Kasimier T. Buchcikb06b4de2005-02-17 19:00:23 +0000840 *
841 * Allocate a new NOTATION value.
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +0000842 * The given values are consumed and freed with the struct.
Kasimier T. Buchcikb06b4de2005-02-17 19:00:23 +0000843 *
844 * Returns a pointer to the new value or NULL in case of error
845 */
846xmlSchemaValPtr
847xmlSchemaNewNOTATIONValue(const xmlChar *name,
848 const xmlChar *ns)
849{
850 xmlSchemaValPtr val;
851
852 val = xmlSchemaNewValue(XML_SCHEMAS_NOTATION);
853 if (val == NULL)
854 return (NULL);
855
William M. Brack12d37ab2005-02-21 13:54:07 +0000856 val->value.qname.name = (xmlChar *)name;
Kasimier T. Buchcikb06b4de2005-02-17 19:00:23 +0000857 if (ns != NULL)
William M. Brack12d37ab2005-02-21 13:54:07 +0000858 val->value.qname.uri = (xmlChar *)ns;
Kasimier T. Buchcikb06b4de2005-02-17 19:00:23 +0000859 return(val);
860}
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +0000861
862/**
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +0000863 * xmlSchemaNewQNameValue:
864 * @namespaceName: the namespace name
865 * @localName: the local name
866 *
867 * Allocate a new QName value.
868 * The given values are consumed and freed with the struct.
869 *
870 * Returns a pointer to the new value or NULL in case of an error.
871 */
872xmlSchemaValPtr
873xmlSchemaNewQNameValue(const xmlChar *namespaceName,
874 const xmlChar *localName)
875{
876 xmlSchemaValPtr val;
877
878 val = xmlSchemaNewValue(XML_SCHEMAS_QNAME);
879 if (val == NULL)
880 return (NULL);
881
882 val->value.qname.name = (xmlChar *) localName;
883 val->value.qname.uri = (xmlChar *) namespaceName;
884 return(val);
885}
886
887/**
Daniel Veillard4255d502002-04-16 15:50:10 +0000888 * xmlSchemaFreeValue:
889 * @value: the value to free
890 *
891 * Cleanup the default XML Schemas type library
892 */
893void
894xmlSchemaFreeValue(xmlSchemaValPtr value) {
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +0000895 xmlSchemaValPtr prev;
896
897 while (value != NULL) {
898 switch (value->type) {
899 case XML_SCHEMAS_STRING:
900 case XML_SCHEMAS_NORMSTRING:
901 case XML_SCHEMAS_TOKEN:
902 case XML_SCHEMAS_LANGUAGE:
903 case XML_SCHEMAS_NMTOKEN:
904 case XML_SCHEMAS_NMTOKENS:
905 case XML_SCHEMAS_NAME:
906 case XML_SCHEMAS_NCNAME:
907 case XML_SCHEMAS_ID:
908 case XML_SCHEMAS_IDREF:
909 case XML_SCHEMAS_IDREFS:
910 case XML_SCHEMAS_ENTITY:
911 case XML_SCHEMAS_ENTITIES:
912 case XML_SCHEMAS_ANYURI:
913 case XML_SCHEMAS_ANYSIMPLETYPE:
914 if (value->value.str != NULL)
915 xmlFree(value->value.str);
916 break;
917 case XML_SCHEMAS_NOTATION:
918 case XML_SCHEMAS_QNAME:
919 if (value->value.qname.uri != NULL)
920 xmlFree(value->value.qname.uri);
921 if (value->value.qname.name != NULL)
922 xmlFree(value->value.qname.name);
923 break;
924 case XML_SCHEMAS_HEXBINARY:
925 if (value->value.hex.str != NULL)
926 xmlFree(value->value.hex.str);
927 break;
928 case XML_SCHEMAS_BASE64BINARY:
929 if (value->value.base64.str != NULL)
930 xmlFree(value->value.base64.str);
931 break;
932 default:
933 break;
934 }
935 prev = value;
936 value = value->next;
937 xmlFree(prev);
938 }
Daniel Veillard4255d502002-04-16 15:50:10 +0000939}
940
941/**
942 * xmlSchemaGetPredefinedType:
943 * @name: the type name
944 * @ns: the URI of the namespace usually "http://www.w3.org/2001/XMLSchema"
945 *
946 * Lookup a type in the default XML Schemas type library
947 *
948 * Returns the type if found, NULL otherwise
949 */
950xmlSchemaTypePtr
951xmlSchemaGetPredefinedType(const xmlChar *name, const xmlChar *ns) {
952 if (xmlSchemaTypesInitialized == 0)
953 xmlSchemaInitTypes();
954 if (name == NULL)
955 return(NULL);
956 return((xmlSchemaTypePtr) xmlHashLookup2(xmlSchemaTypesBank, name, ns));
957}
Daniel Veillard070803b2002-05-03 07:29:38 +0000958
Daniel Veillard01fa6152004-06-29 17:04:39 +0000959/**
960 * xmlSchemaGetBuiltInListSimpleTypeItemType:
961 * @type: the built-in simple type.
962 *
Daniel Veillard6927b102004-10-27 17:29:04 +0000963 * Lookup function
964 *
Daniel Veillardc0826a72004-08-10 14:17:33 +0000965 * Returns the item type of @type as defined by the built-in datatype
966 * hierarchy of XML Schema Part 2: Datatypes, or NULL in case of an error.
Daniel Veillard01fa6152004-06-29 17:04:39 +0000967 */
968xmlSchemaTypePtr
969xmlSchemaGetBuiltInListSimpleTypeItemType(xmlSchemaTypePtr type)
970{
Daniel Veillard42595322004-11-08 10:52:06 +0000971 if ((type == NULL) || (type->type != XML_SCHEMA_TYPE_BASIC))
Daniel Veillard01fa6152004-06-29 17:04:39 +0000972 return (NULL);
973 switch (type->builtInType) {
974 case XML_SCHEMAS_NMTOKENS:
975 return (xmlSchemaTypeNmtokenDef );
976 case XML_SCHEMAS_IDREFS:
977 return (xmlSchemaTypeIdrefDef);
978 case XML_SCHEMAS_ENTITIES:
979 return (xmlSchemaTypeEntityDef);
980 default:
981 return (NULL);
982 }
983}
984
Daniel Veillard070803b2002-05-03 07:29:38 +0000985/****************************************************************
986 * *
987 * Convenience macros and functions *
988 * *
989 ****************************************************************/
990
991#define IS_TZO_CHAR(c) \
992 ((c == 0) || (c == 'Z') || (c == '+') || (c == '-'))
993
994#define VALID_YEAR(yr) (yr != 0)
995#define VALID_MONTH(mon) ((mon >= 1) && (mon <= 12))
996/* VALID_DAY should only be used when month is unknown */
997#define VALID_DAY(day) ((day >= 1) && (day <= 31))
998#define VALID_HOUR(hr) ((hr >= 0) && (hr <= 23))
999#define VALID_MIN(min) ((min >= 0) && (min <= 59))
1000#define VALID_SEC(sec) ((sec >= 0) && (sec < 60))
Kasimier T. Buchcik690a6802005-05-12 13:16:01 +00001001#define VALID_TZO(tzo) ((tzo > -840) && (tzo < 840))
Daniel Veillard070803b2002-05-03 07:29:38 +00001002#define IS_LEAP(y) \
1003 (((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0))
1004
Daniel Veillardebe25d42004-03-25 09:35:49 +00001005static const unsigned int daysInMonth[12] =
Daniel Veillard070803b2002-05-03 07:29:38 +00001006 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
Daniel Veillardebe25d42004-03-25 09:35:49 +00001007static const unsigned int daysInMonthLeap[12] =
Daniel Veillard070803b2002-05-03 07:29:38 +00001008 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
1009
Daniel Veillard5a872412002-05-22 06:40:27 +00001010#define MAX_DAYINMONTH(yr,mon) \
1011 (IS_LEAP(yr) ? daysInMonthLeap[mon - 1] : daysInMonth[mon - 1])
1012
Daniel Veillard070803b2002-05-03 07:29:38 +00001013#define VALID_MDAY(dt) \
1014 (IS_LEAP(dt->year) ? \
1015 (dt->day <= daysInMonthLeap[dt->mon - 1]) : \
1016 (dt->day <= daysInMonth[dt->mon - 1]))
1017
1018#define VALID_DATE(dt) \
1019 (VALID_YEAR(dt->year) && VALID_MONTH(dt->mon) && VALID_MDAY(dt))
1020
1021#define VALID_TIME(dt) \
1022 (VALID_HOUR(dt->hour) && VALID_MIN(dt->min) && \
1023 VALID_SEC(dt->sec) && VALID_TZO(dt->tzo))
1024
1025#define VALID_DATETIME(dt) \
1026 (VALID_DATE(dt) && VALID_TIME(dt))
1027
1028#define SECS_PER_MIN (60)
1029#define SECS_PER_HOUR (60 * SECS_PER_MIN)
1030#define SECS_PER_DAY (24 * SECS_PER_HOUR)
1031
Daniel Veillard5a872412002-05-22 06:40:27 +00001032static const long dayInYearByMonth[12] =
1033 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
1034static const long dayInLeapYearByMonth[12] =
1035 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 };
1036
1037#define DAY_IN_YEAR(day, month, year) \
1038 ((IS_LEAP(year) ? \
1039 dayInLeapYearByMonth[month - 1] : \
1040 dayInYearByMonth[month - 1]) + day)
1041
1042#ifdef DEBUG
1043#define DEBUG_DATE(dt) \
1044 xmlGenericError(xmlGenericErrorContext, \
1045 "type=%o %04ld-%02u-%02uT%02u:%02u:%03f", \
1046 dt->type,dt->value.date.year,dt->value.date.mon, \
1047 dt->value.date.day,dt->value.date.hour,dt->value.date.min, \
1048 dt->value.date.sec); \
1049 if (dt->value.date.tz_flag) \
1050 if (dt->value.date.tzo != 0) \
1051 xmlGenericError(xmlGenericErrorContext, \
1052 "%+05d\n",dt->value.date.tzo); \
1053 else \
1054 xmlGenericError(xmlGenericErrorContext, "Z\n"); \
1055 else \
1056 xmlGenericError(xmlGenericErrorContext,"\n")
1057#else
1058#define DEBUG_DATE(dt)
1059#endif
1060
Daniel Veillard070803b2002-05-03 07:29:38 +00001061/**
1062 * _xmlSchemaParseGYear:
1063 * @dt: pointer to a date structure
1064 * @str: pointer to the string to analyze
1065 *
1066 * Parses a xs:gYear without time zone and fills in the appropriate
1067 * field of the @dt structure. @str is updated to point just after the
1068 * xs:gYear. It is supposed that @dt->year is big enough to contain
1069 * the year.
1070 *
1071 * Returns 0 or the error code
1072 */
1073static int
1074_xmlSchemaParseGYear (xmlSchemaValDatePtr dt, const xmlChar **str) {
1075 const xmlChar *cur = *str, *firstChar;
1076 int isneg = 0, digcnt = 0;
1077
1078 if (((*cur < '0') || (*cur > '9')) &&
1079 (*cur != '-') && (*cur != '+'))
1080 return -1;
1081
1082 if (*cur == '-') {
1083 isneg = 1;
1084 cur++;
1085 }
1086
1087 firstChar = cur;
1088
1089 while ((*cur >= '0') && (*cur <= '9')) {
1090 dt->year = dt->year * 10 + (*cur - '0');
1091 cur++;
1092 digcnt++;
1093 }
1094
1095 /* year must be at least 4 digits (CCYY); over 4
1096 * digits cannot have a leading zero. */
1097 if ((digcnt < 4) || ((digcnt > 4) && (*firstChar == '0')))
1098 return 1;
1099
1100 if (isneg)
1101 dt->year = - dt->year;
1102
1103 if (!VALID_YEAR(dt->year))
1104 return 2;
1105
1106 *str = cur;
1107 return 0;
1108}
1109
1110/**
1111 * PARSE_2_DIGITS:
1112 * @num: the integer to fill in
1113 * @cur: an #xmlChar *
1114 * @invalid: an integer
1115 *
1116 * Parses a 2-digits integer and updates @num with the value. @cur is
1117 * updated to point just after the integer.
1118 * In case of error, @invalid is set to %TRUE, values of @num and
1119 * @cur are undefined.
1120 */
1121#define PARSE_2_DIGITS(num, cur, invalid) \
1122 if ((cur[0] < '0') || (cur[0] > '9') || \
1123 (cur[1] < '0') || (cur[1] > '9')) \
1124 invalid = 1; \
1125 else \
1126 num = (cur[0] - '0') * 10 + (cur[1] - '0'); \
1127 cur += 2;
1128
1129/**
1130 * PARSE_FLOAT:
1131 * @num: the double to fill in
1132 * @cur: an #xmlChar *
1133 * @invalid: an integer
1134 *
1135 * Parses a float and updates @num with the value. @cur is
1136 * updated to point just after the float. The float must have a
1137 * 2-digits integer part and may or may not have a decimal part.
1138 * In case of error, @invalid is set to %TRUE, values of @num and
1139 * @cur are undefined.
1140 */
1141#define PARSE_FLOAT(num, cur, invalid) \
1142 PARSE_2_DIGITS(num, cur, invalid); \
1143 if (!invalid && (*cur == '.')) { \
1144 double mult = 1; \
1145 cur++; \
1146 if ((*cur < '0') || (*cur > '9')) \
1147 invalid = 1; \
1148 while ((*cur >= '0') && (*cur <= '9')) { \
1149 mult /= 10; \
1150 num += (*cur - '0') * mult; \
1151 cur++; \
1152 } \
1153 }
1154
1155/**
1156 * _xmlSchemaParseGMonth:
1157 * @dt: pointer to a date structure
1158 * @str: pointer to the string to analyze
1159 *
1160 * Parses a xs:gMonth without time zone and fills in the appropriate
1161 * field of the @dt structure. @str is updated to point just after the
1162 * xs:gMonth.
1163 *
1164 * Returns 0 or the error code
1165 */
1166static int
1167_xmlSchemaParseGMonth (xmlSchemaValDatePtr dt, const xmlChar **str) {
1168 const xmlChar *cur = *str;
1169 int ret = 0;
Kasimier T. Buchcik64dc4d22005-04-19 15:58:31 +00001170 unsigned int value = 0;
Daniel Veillard070803b2002-05-03 07:29:38 +00001171
Kasimier T. Buchcik64dc4d22005-04-19 15:58:31 +00001172 PARSE_2_DIGITS(value, cur, ret);
Daniel Veillard070803b2002-05-03 07:29:38 +00001173 if (ret != 0)
1174 return ret;
1175
Kasimier T. Buchcik64dc4d22005-04-19 15:58:31 +00001176 if (!VALID_MONTH(value))
Daniel Veillard070803b2002-05-03 07:29:38 +00001177 return 2;
1178
Kasimier T. Buchcik64dc4d22005-04-19 15:58:31 +00001179 dt->mon = value;
1180
Daniel Veillard070803b2002-05-03 07:29:38 +00001181 *str = cur;
1182 return 0;
1183}
1184
1185/**
1186 * _xmlSchemaParseGDay:
1187 * @dt: pointer to a date structure
1188 * @str: pointer to the string to analyze
1189 *
1190 * Parses a xs:gDay without time zone and fills in the appropriate
1191 * field of the @dt structure. @str is updated to point just after the
1192 * xs:gDay.
1193 *
1194 * Returns 0 or the error code
1195 */
1196static int
1197_xmlSchemaParseGDay (xmlSchemaValDatePtr dt, const xmlChar **str) {
1198 const xmlChar *cur = *str;
1199 int ret = 0;
Kasimier T. Buchcik64dc4d22005-04-19 15:58:31 +00001200 unsigned int value = 0;
Daniel Veillard070803b2002-05-03 07:29:38 +00001201
Kasimier T. Buchcik64dc4d22005-04-19 15:58:31 +00001202 PARSE_2_DIGITS(value, cur, ret);
Daniel Veillard070803b2002-05-03 07:29:38 +00001203 if (ret != 0)
1204 return ret;
1205
Kasimier T. Buchcik64dc4d22005-04-19 15:58:31 +00001206 if (!VALID_DAY(value))
Daniel Veillard070803b2002-05-03 07:29:38 +00001207 return 2;
1208
Kasimier T. Buchcik64dc4d22005-04-19 15:58:31 +00001209 dt->day = value;
Daniel Veillard070803b2002-05-03 07:29:38 +00001210 *str = cur;
1211 return 0;
1212}
1213
1214/**
1215 * _xmlSchemaParseTime:
1216 * @dt: pointer to a date structure
1217 * @str: pointer to the string to analyze
1218 *
1219 * Parses a xs:time without time zone and fills in the appropriate
1220 * fields of the @dt structure. @str is updated to point just after the
1221 * xs:time.
1222 * In case of error, values of @dt fields are undefined.
1223 *
1224 * Returns 0 or the error code
1225 */
1226static int
1227_xmlSchemaParseTime (xmlSchemaValDatePtr dt, const xmlChar **str) {
Kasimier T. Buchcik285b3672005-05-12 13:10:22 +00001228 const xmlChar *cur = *str;
Daniel Veillard070803b2002-05-03 07:29:38 +00001229 int ret = 0;
Kasimier T. Buchcik285b3672005-05-12 13:10:22 +00001230 int value = 0;
Daniel Veillard070803b2002-05-03 07:29:38 +00001231
Kasimier T. Buchcik64dc4d22005-04-19 15:58:31 +00001232 PARSE_2_DIGITS(value, cur, ret);
Daniel Veillard070803b2002-05-03 07:29:38 +00001233 if (ret != 0)
Kasimier T. Buchcik64dc4d22005-04-19 15:58:31 +00001234 return ret;
Daniel Veillard070803b2002-05-03 07:29:38 +00001235 if (*cur != ':')
1236 return 1;
Kasimier T. Buchcik64dc4d22005-04-19 15:58:31 +00001237 if (!VALID_HOUR(value))
1238 return 2;
Daniel Veillard070803b2002-05-03 07:29:38 +00001239 cur++;
1240
1241 /* the ':' insures this string is xs:time */
Kasimier T. Buchcik64dc4d22005-04-19 15:58:31 +00001242 dt->hour = value;
Daniel Veillard070803b2002-05-03 07:29:38 +00001243
Kasimier T. Buchcik64dc4d22005-04-19 15:58:31 +00001244 PARSE_2_DIGITS(value, cur, ret);
Daniel Veillard070803b2002-05-03 07:29:38 +00001245 if (ret != 0)
1246 return ret;
Kasimier T. Buchcik64dc4d22005-04-19 15:58:31 +00001247 if (!VALID_MIN(value))
1248 return 2;
1249 dt->min = value;
Daniel Veillard070803b2002-05-03 07:29:38 +00001250
1251 if (*cur != ':')
1252 return 1;
1253 cur++;
1254
1255 PARSE_FLOAT(dt->sec, cur, ret);
1256 if (ret != 0)
1257 return ret;
1258
Kasimier T. Buchcik64dc4d22005-04-19 15:58:31 +00001259 if ((!VALID_SEC(dt->sec)) || (!VALID_TZO(dt->tzo)))
Daniel Veillard070803b2002-05-03 07:29:38 +00001260 return 2;
1261
1262 *str = cur;
1263 return 0;
1264}
1265
1266/**
1267 * _xmlSchemaParseTimeZone:
1268 * @dt: pointer to a date structure
1269 * @str: pointer to the string to analyze
1270 *
1271 * Parses a time zone without time zone and fills in the appropriate
1272 * field of the @dt structure. @str is updated to point just after the
1273 * time zone.
1274 *
1275 * Returns 0 or the error code
1276 */
1277static int
1278_xmlSchemaParseTimeZone (xmlSchemaValDatePtr dt, const xmlChar **str) {
1279 const xmlChar *cur = *str;
1280 int ret = 0;
1281
1282 if (str == NULL)
1283 return -1;
1284
1285 switch (*cur) {
1286 case 0:
1287 dt->tz_flag = 0;
1288 dt->tzo = 0;
1289 break;
1290
1291 case 'Z':
1292 dt->tz_flag = 1;
1293 dt->tzo = 0;
1294 cur++;
1295 break;
1296
1297 case '+':
1298 case '-': {
1299 int isneg = 0, tmp = 0;
1300 isneg = (*cur == '-');
1301
1302 cur++;
1303
1304 PARSE_2_DIGITS(tmp, cur, ret);
1305 if (ret != 0)
1306 return ret;
1307 if (!VALID_HOUR(tmp))
1308 return 2;
1309
1310 if (*cur != ':')
1311 return 1;
1312 cur++;
1313
1314 dt->tzo = tmp * 60;
1315
1316 PARSE_2_DIGITS(tmp, cur, ret);
1317 if (ret != 0)
1318 return ret;
1319 if (!VALID_MIN(tmp))
1320 return 2;
1321
1322 dt->tzo += tmp;
1323 if (isneg)
1324 dt->tzo = - dt->tzo;
1325
1326 if (!VALID_TZO(dt->tzo))
1327 return 2;
1328
Daniel Veillard5a872412002-05-22 06:40:27 +00001329 dt->tz_flag = 1;
Daniel Veillard070803b2002-05-03 07:29:38 +00001330 break;
1331 }
1332 default:
1333 return 1;
1334 }
1335
1336 *str = cur;
1337 return 0;
1338}
1339
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001340/**
1341 * _xmlSchemaBase64Decode:
1342 * @ch: a character
1343 *
1344 * Converts a base64 encoded character to its base 64 value.
1345 *
1346 * Returns 0-63 (value), 64 (pad), or -1 (not recognized)
1347 */
1348static int
1349_xmlSchemaBase64Decode (const xmlChar ch) {
1350 if (('A' <= ch) && (ch <= 'Z')) return ch - 'A';
1351 if (('a' <= ch) && (ch <= 'z')) return ch - 'a' + 26;
1352 if (('0' <= ch) && (ch <= '9')) return ch - '0' + 52;
1353 if ('+' == ch) return 62;
1354 if ('/' == ch) return 63;
1355 if ('=' == ch) return 64;
1356 return -1;
1357}
1358
Daniel Veillard070803b2002-05-03 07:29:38 +00001359/****************************************************************
1360 * *
1361 * XML Schema Dates/Times Datatypes Handling *
1362 * *
1363 ****************************************************************/
1364
1365/**
1366 * PARSE_DIGITS:
1367 * @num: the integer to fill in
1368 * @cur: an #xmlChar *
1369 * @num_type: an integer flag
1370 *
1371 * Parses a digits integer and updates @num with the value. @cur is
1372 * updated to point just after the integer.
1373 * In case of error, @num_type is set to -1, values of @num and
1374 * @cur are undefined.
1375 */
1376#define PARSE_DIGITS(num, cur, num_type) \
1377 if ((*cur < '0') || (*cur > '9')) \
1378 num_type = -1; \
1379 else \
1380 while ((*cur >= '0') && (*cur <= '9')) { \
1381 num = num * 10 + (*cur - '0'); \
1382 cur++; \
1383 }
1384
1385/**
1386 * PARSE_NUM:
1387 * @num: the double to fill in
1388 * @cur: an #xmlChar *
1389 * @num_type: an integer flag
1390 *
1391 * Parses a float or integer and updates @num with the value. @cur is
1392 * updated to point just after the number. If the number is a float,
1393 * then it must have an integer part and a decimal part; @num_type will
1394 * be set to 1. If there is no decimal part, @num_type is set to zero.
1395 * In case of error, @num_type is set to -1, values of @num and
1396 * @cur are undefined.
1397 */
1398#define PARSE_NUM(num, cur, num_type) \
1399 num = 0; \
1400 PARSE_DIGITS(num, cur, num_type); \
1401 if (!num_type && (*cur == '.')) { \
1402 double mult = 1; \
1403 cur++; \
1404 if ((*cur < '0') || (*cur > '9')) \
1405 num_type = -1; \
1406 else \
1407 num_type = 1; \
1408 while ((*cur >= '0') && (*cur <= '9')) { \
1409 mult /= 10; \
1410 num += (*cur - '0') * mult; \
1411 cur++; \
1412 } \
1413 }
1414
1415/**
Daniel Veillard5a872412002-05-22 06:40:27 +00001416 * xmlSchemaValidateDates:
Daniel Veillard455cc072003-03-31 10:13:23 +00001417 * @type: the expected type or XML_SCHEMAS_UNKNOWN
Daniel Veillard070803b2002-05-03 07:29:38 +00001418 * @dateTime: string to analyze
1419 * @val: the return computed value
1420 *
1421 * Check that @dateTime conforms to the lexical space of one of the date types.
1422 * if true a value is computed and returned in @val.
1423 *
1424 * Returns 0 if this validates, a positive error code number otherwise
1425 * and -1 in case of internal or API error.
1426 */
1427static int
Daniel Veillard455cc072003-03-31 10:13:23 +00001428xmlSchemaValidateDates (xmlSchemaValType type,
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00001429 const xmlChar *dateTime, xmlSchemaValPtr *val,
1430 int collapse) {
Daniel Veillard070803b2002-05-03 07:29:38 +00001431 xmlSchemaValPtr dt;
1432 int ret;
1433 const xmlChar *cur = dateTime;
1434
1435#define RETURN_TYPE_IF_VALID(t) \
1436 if (IS_TZO_CHAR(*cur)) { \
1437 ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur); \
1438 if (ret == 0) { \
1439 if (*cur != 0) \
1440 goto error; \
1441 dt->type = t; \
Daniel Veillard455cc072003-03-31 10:13:23 +00001442 goto done; \
Daniel Veillard070803b2002-05-03 07:29:38 +00001443 } \
1444 }
1445
1446 if (dateTime == NULL)
1447 return -1;
1448
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00001449 if (collapse)
1450 while IS_WSP_BLANK_CH(*cur) cur++;
1451
Daniel Veillard070803b2002-05-03 07:29:38 +00001452 if ((*cur != '-') && (*cur < '0') && (*cur > '9'))
1453 return 1;
1454
1455 dt = xmlSchemaNewValue(XML_SCHEMAS_UNKNOWN);
1456 if (dt == NULL)
1457 return -1;
1458
1459 if ((cur[0] == '-') && (cur[1] == '-')) {
1460 /*
1461 * It's an incomplete date (xs:gMonthDay, xs:gMonth or
1462 * xs:gDay)
1463 */
1464 cur += 2;
1465
1466 /* is it an xs:gDay? */
1467 if (*cur == '-') {
Daniel Veillard455cc072003-03-31 10:13:23 +00001468 if (type == XML_SCHEMAS_GMONTH)
1469 goto error;
Daniel Veillard070803b2002-05-03 07:29:38 +00001470 ++cur;
1471 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
1472 if (ret != 0)
1473 goto error;
1474
1475 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GDAY);
1476
1477 goto error;
1478 }
1479
1480 /*
1481 * it should be an xs:gMonthDay or xs:gMonth
1482 */
1483 ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
1484 if (ret != 0)
1485 goto error;
1486
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001487 /*
1488 * a '-' char could indicate this type is xs:gMonthDay or
1489 * a negative time zone offset. Check for xs:gMonthDay first.
1490 * Also the first three char's of a negative tzo (-MM:SS) can
1491 * appear to be a valid day; so even if the day portion
1492 * of the xs:gMonthDay verifies, we must insure it was not
1493 * a tzo.
1494 */
1495 if (*cur == '-') {
1496 const xmlChar *rewnd = cur;
1497 cur++;
Daniel Veillard070803b2002-05-03 07:29:38 +00001498
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001499 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
1500 if ((ret == 0) && ((*cur == 0) || (*cur != ':'))) {
1501
1502 /*
1503 * we can use the VALID_MDAY macro to validate the month
1504 * and day because the leap year test will flag year zero
1505 * as a leap year (even though zero is an invalid year).
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00001506 * FUTURE TODO: Zero will become valid in XML Schema 1.1
1507 * probably.
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001508 */
1509 if (VALID_MDAY((&(dt->value.date)))) {
1510
1511 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTHDAY);
1512
1513 goto error;
1514 }
1515 }
1516
1517 /*
1518 * not xs:gMonthDay so rewind and check if just xs:gMonth
1519 * with an optional time zone.
1520 */
1521 cur = rewnd;
1522 }
1523
1524 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTH);
Daniel Veillard070803b2002-05-03 07:29:38 +00001525
1526 goto error;
1527 }
1528
1529 /*
1530 * It's a right-truncated date or an xs:time.
1531 * Try to parse an xs:time then fallback on right-truncated dates.
1532 */
1533 if ((*cur >= '0') && (*cur <= '9')) {
1534 ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
1535 if (ret == 0) {
1536 /* it's an xs:time */
1537 RETURN_TYPE_IF_VALID(XML_SCHEMAS_TIME);
1538 }
1539 }
1540
1541 /* fallback on date parsing */
1542 cur = dateTime;
1543
1544 ret = _xmlSchemaParseGYear(&(dt->value.date), &cur);
1545 if (ret != 0)
1546 goto error;
1547
1548 /* is it an xs:gYear? */
1549 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEAR);
1550
1551 if (*cur != '-')
1552 goto error;
1553 cur++;
1554
1555 ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
1556 if (ret != 0)
1557 goto error;
1558
1559 /* is it an xs:gYearMonth? */
1560 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEARMONTH);
1561
1562 if (*cur != '-')
1563 goto error;
1564 cur++;
1565
1566 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
1567 if ((ret != 0) || !VALID_DATE((&(dt->value.date))))
1568 goto error;
1569
1570 /* is it an xs:date? */
1571 RETURN_TYPE_IF_VALID(XML_SCHEMAS_DATE);
1572
1573 if (*cur != 'T')
1574 goto error;
1575 cur++;
1576
1577 /* it should be an xs:dateTime */
1578 ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
1579 if (ret != 0)
1580 goto error;
1581
1582 ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur);
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00001583 if (collapse)
1584 while IS_WSP_BLANK_CH(*cur) cur++;
Daniel Veillard070803b2002-05-03 07:29:38 +00001585 if ((ret != 0) || (*cur != 0) || !VALID_DATETIME((&(dt->value.date))))
1586 goto error;
1587
Daniel Veillard455cc072003-03-31 10:13:23 +00001588
Daniel Veillard070803b2002-05-03 07:29:38 +00001589 dt->type = XML_SCHEMAS_DATETIME;
1590
Daniel Veillard455cc072003-03-31 10:13:23 +00001591done:
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001592#if 1
1593 if ((type != XML_SCHEMAS_UNKNOWN) && (type != dt->type))
1594 goto error;
1595#else
1596 /*
1597 * insure the parsed type is equal to or less significant (right
1598 * truncated) than the desired type.
1599 */
1600 if ((type != XML_SCHEMAS_UNKNOWN) && (type != dt->type)) {
1601
1602 /* time only matches time */
1603 if ((type == XML_SCHEMAS_TIME) && (dt->type == XML_SCHEMAS_TIME))
1604 goto error;
1605
1606 if ((type == XML_SCHEMAS_DATETIME) &&
1607 ((dt->type != XML_SCHEMAS_DATE) ||
1608 (dt->type != XML_SCHEMAS_GYEARMONTH) ||
1609 (dt->type != XML_SCHEMAS_GYEAR)))
1610 goto error;
1611
1612 if ((type == XML_SCHEMAS_DATE) &&
1613 ((dt->type != XML_SCHEMAS_GYEAR) ||
1614 (dt->type != XML_SCHEMAS_GYEARMONTH)))
1615 goto error;
1616
1617 if ((type == XML_SCHEMAS_GYEARMONTH) && (dt->type != XML_SCHEMAS_GYEAR))
1618 goto error;
1619
1620 if ((type == XML_SCHEMAS_GMONTHDAY) && (dt->type != XML_SCHEMAS_GMONTH))
1621 goto error;
1622 }
Daniel Veillard455cc072003-03-31 10:13:23 +00001623#endif
1624
Daniel Veillard070803b2002-05-03 07:29:38 +00001625 if (val != NULL)
1626 *val = dt;
Daniel Veillard80b19092003-03-28 13:29:53 +00001627 else
1628 xmlSchemaFreeValue(dt);
Daniel Veillard070803b2002-05-03 07:29:38 +00001629
1630 return 0;
1631
1632error:
1633 if (dt != NULL)
1634 xmlSchemaFreeValue(dt);
1635 return 1;
1636}
1637
1638/**
Daniel Veillard5a872412002-05-22 06:40:27 +00001639 * xmlSchemaValidateDuration:
Daniel Veillard070803b2002-05-03 07:29:38 +00001640 * @type: the predefined type
1641 * @duration: string to analyze
1642 * @val: the return computed value
1643 *
1644 * Check that @duration conforms to the lexical space of the duration type.
1645 * if true a value is computed and returned in @val.
1646 *
1647 * Returns 0 if this validates, a positive error code number otherwise
1648 * and -1 in case of internal or API error.
1649 */
1650static int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00001651xmlSchemaValidateDuration (xmlSchemaTypePtr type ATTRIBUTE_UNUSED,
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00001652 const xmlChar *duration, xmlSchemaValPtr *val,
1653 int collapse) {
Daniel Veillard070803b2002-05-03 07:29:38 +00001654 const xmlChar *cur = duration;
1655 xmlSchemaValPtr dur;
1656 int isneg = 0;
1657 unsigned int seq = 0;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001658 double num;
1659 int num_type = 0; /* -1 = invalid, 0 = int, 1 = floating */
1660 const xmlChar desig[] = {'Y', 'M', 'D', 'H', 'M', 'S'};
1661 const double multi[] = { 0.0, 0.0, 86400.0, 3600.0, 60.0, 1.0, 0.0};
Daniel Veillard070803b2002-05-03 07:29:38 +00001662
1663 if (duration == NULL)
1664 return -1;
1665
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00001666 if (collapse)
1667 while IS_WSP_BLANK_CH(*cur) cur++;
1668
Daniel Veillard070803b2002-05-03 07:29:38 +00001669 if (*cur == '-') {
1670 isneg = 1;
1671 cur++;
1672 }
1673
1674 /* duration must start with 'P' (after sign) */
1675 if (*cur++ != 'P')
1676 return 1;
1677
Daniel Veillard80b19092003-03-28 13:29:53 +00001678 if (*cur == 0)
1679 return 1;
1680
Daniel Veillard070803b2002-05-03 07:29:38 +00001681 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
1682 if (dur == NULL)
1683 return -1;
1684
1685 while (*cur != 0) {
Daniel Veillard070803b2002-05-03 07:29:38 +00001686
1687 /* input string should be empty or invalid date/time item */
1688 if (seq >= sizeof(desig))
1689 goto error;
1690
1691 /* T designator must be present for time items */
1692 if (*cur == 'T') {
1693 if (seq <= 3) {
1694 seq = 3;
1695 cur++;
1696 } else
1697 return 1;
1698 } else if (seq == 3)
1699 goto error;
1700
1701 /* parse the number portion of the item */
1702 PARSE_NUM(num, cur, num_type);
1703
1704 if ((num_type == -1) || (*cur == 0))
1705 goto error;
1706
1707 /* update duration based on item type */
1708 while (seq < sizeof(desig)) {
1709 if (*cur == desig[seq]) {
1710
1711 /* verify numeric type; only seconds can be float */
1712 if ((num_type != 0) && (seq < (sizeof(desig)-1)))
1713 goto error;
1714
1715 switch (seq) {
1716 case 0:
1717 dur->value.dur.mon = (long)num * 12;
1718 break;
1719 case 1:
1720 dur->value.dur.mon += (long)num;
1721 break;
1722 default:
1723 /* convert to seconds using multiplier */
1724 dur->value.dur.sec += num * multi[seq];
1725 seq++;
1726 break;
1727 }
1728
1729 break; /* exit loop */
1730 }
1731 /* no date designators found? */
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00001732 if ((++seq == 3) || (seq == 6))
Daniel Veillard070803b2002-05-03 07:29:38 +00001733 goto error;
1734 }
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00001735 cur++;
1736 if (collapse)
1737 while IS_WSP_BLANK_CH(*cur) cur++;
Daniel Veillard070803b2002-05-03 07:29:38 +00001738 }
1739
1740 if (isneg) {
1741 dur->value.dur.mon = -dur->value.dur.mon;
1742 dur->value.dur.day = -dur->value.dur.day;
1743 dur->value.dur.sec = -dur->value.dur.sec;
1744 }
1745
1746 if (val != NULL)
1747 *val = dur;
Daniel Veillard80b19092003-03-28 13:29:53 +00001748 else
1749 xmlSchemaFreeValue(dur);
Daniel Veillard070803b2002-05-03 07:29:38 +00001750
1751 return 0;
1752
1753error:
1754 if (dur != NULL)
1755 xmlSchemaFreeValue(dur);
1756 return 1;
1757}
1758
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001759/**
1760 * xmlSchemaStrip:
1761 * @value: a value
1762 *
1763 * Removes the leading and ending spaces of a string
1764 *
1765 * Returns the new string or NULL if no change was required.
1766 */
1767static xmlChar *
1768xmlSchemaStrip(const xmlChar *value) {
1769 const xmlChar *start = value, *end, *f;
1770
1771 if (value == NULL) return(NULL);
William M. Brack76e95df2003-10-18 16:20:14 +00001772 while ((*start != 0) && (IS_BLANK_CH(*start))) start++;
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001773 end = start;
1774 while (*end != 0) end++;
1775 f = end;
1776 end--;
William M. Brack76e95df2003-10-18 16:20:14 +00001777 while ((end > start) && (IS_BLANK_CH(*end))) end--;
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001778 end++;
1779 if ((start == value) && (f == end)) return(NULL);
1780 return(xmlStrndup(start, end - start));
1781}
Daniel Veillard96a4b252003-02-06 08:22:32 +00001782
1783/**
Kasimier T. Buchcik91feaf82004-11-12 14:04:58 +00001784 * xmlSchemaWhiteSpaceReplace:
1785 * @value: a value
1786 *
1787 * Replaces 0xd, 0x9 and 0xa with a space.
1788 *
1789 * Returns the new string or NULL if no change was required.
1790 */
1791xmlChar *
1792xmlSchemaWhiteSpaceReplace(const xmlChar *value) {
1793 const xmlChar *cur = value;
1794 xmlChar *ret = NULL, *mcur;
1795
1796 if (value == NULL)
1797 return(NULL);
1798
1799 while ((*cur != 0) &&
1800 (((*cur) != 0xd) && ((*cur) != 0x9) && ((*cur) != 0xa))) {
1801 cur++;
1802 }
1803 if (*cur == 0)
1804 return (NULL);
1805 ret = xmlStrdup(value);
1806 /* TODO FIXME: I guess gcc will bark at this. */
1807 mcur = (xmlChar *) (ret + (cur - value));
1808 do {
1809 if ( ((*mcur) == 0xd) || ((*mcur) == 0x9) || ((*mcur) == 0xa) )
1810 *mcur = ' ';
1811 mcur++;
1812 } while (*mcur != 0);
1813 return(ret);
1814}
1815
1816/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001817 * xmlSchemaCollapseString:
1818 * @value: a value
1819 *
1820 * Removes and normalize white spaces in the string
1821 *
1822 * Returns the new string or NULL if no change was required.
1823 */
Daniel Veillard01fa6152004-06-29 17:04:39 +00001824xmlChar *
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001825xmlSchemaCollapseString(const xmlChar *value) {
1826 const xmlChar *start = value, *end, *f;
1827 xmlChar *g;
1828 int col = 0;
1829
1830 if (value == NULL) return(NULL);
William M. Brack76e95df2003-10-18 16:20:14 +00001831 while ((*start != 0) && (IS_BLANK_CH(*start))) start++;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001832 end = start;
1833 while (*end != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00001834 if ((*end == ' ') && (IS_BLANK_CH(end[1]))) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001835 col = end - start;
1836 break;
1837 } else if ((*end == 0xa) || (*end == 0x9) || (*end == 0xd)) {
1838 col = end - start;
1839 break;
1840 }
1841 end++;
1842 }
1843 if (col == 0) {
1844 f = end;
1845 end--;
William M. Brack76e95df2003-10-18 16:20:14 +00001846 while ((end > start) && (IS_BLANK_CH(*end))) end--;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001847 end++;
1848 if ((start == value) && (f == end)) return(NULL);
1849 return(xmlStrndup(start, end - start));
1850 }
1851 start = xmlStrdup(start);
1852 if (start == NULL) return(NULL);
1853 g = (xmlChar *) (start + col);
1854 end = g;
1855 while (*end != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00001856 if (IS_BLANK_CH(*end)) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001857 end++;
William M. Brack76e95df2003-10-18 16:20:14 +00001858 while (IS_BLANK_CH(*end)) end++;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001859 if (*end != 0)
1860 *g++ = ' ';
1861 } else
1862 *g++ = *end++;
1863 }
1864 *g = 0;
1865 return((xmlChar *) start);
1866}
1867
1868/**
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001869 * xmlSchemaValAtomicListNode:
1870 * @type: the predefined atomic type for a token in the list
1871 * @value: the list value to check
1872 * @ret: the return computed value
1873 * @node: the node containing the value
1874 *
1875 * Check that a value conforms to the lexical space of the predefined
1876 * list type. if true a value is computed and returned in @ret.
1877 *
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001878 * Returns the number of items if this validates, a negative error code
1879 * number otherwise
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001880 */
1881static int
1882xmlSchemaValAtomicListNode(xmlSchemaTypePtr type, const xmlChar *value,
1883 xmlSchemaValPtr *ret, xmlNodePtr node) {
1884 xmlChar *val, *cur, *endval;
1885 int nb_values = 0;
Daniel Veillard580ced82003-03-21 21:22:48 +00001886 int tmp = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001887
1888 if (value == NULL) {
1889 return(-1);
1890 }
1891 val = xmlStrdup(value);
1892 if (val == NULL) {
1893 return(-1);
1894 }
Daniel Veillard6fc5db02005-01-16 00:05:58 +00001895 if (ret != NULL) {
1896 *ret = NULL;
1897 }
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001898 cur = val;
1899 /*
1900 * Split the list
1901 */
William M. Brack76e95df2003-10-18 16:20:14 +00001902 while (IS_BLANK_CH(*cur)) *cur++ = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001903 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00001904 if (IS_BLANK_CH(*cur)) {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001905 *cur = 0;
1906 cur++;
William M. Brack76e95df2003-10-18 16:20:14 +00001907 while (IS_BLANK_CH(*cur)) *cur++ = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001908 } else {
1909 nb_values++;
1910 cur++;
William M. Brack76e95df2003-10-18 16:20:14 +00001911 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001912 }
1913 }
1914 if (nb_values == 0) {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001915 xmlFree(val);
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001916 return(nb_values);
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001917 }
1918 endval = cur;
1919 cur = val;
1920 while ((*cur == 0) && (cur != endval)) cur++;
1921 while (cur != endval) {
1922 tmp = xmlSchemaValPredefTypeNode(type, cur, NULL, node);
1923 if (tmp != 0)
1924 break;
1925 while (*cur != 0) cur++;
1926 while ((*cur == 0) && (cur != endval)) cur++;
1927 }
Daniel Veillard6fc5db02005-01-16 00:05:58 +00001928 /* TODO what return value ? c.f. bug #158628
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001929 if (ret != NULL) {
1930 TODO
Daniel Veillard6fc5db02005-01-16 00:05:58 +00001931 } */
1932 xmlFree(val);
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001933 if (tmp == 0)
1934 return(nb_values);
1935 return(-1);
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001936}
1937
1938/**
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001939 * xmlSchemaParseUInt:
1940 * @str: pointer to the string R/W
1941 * @llo: pointer to the low result
1942 * @lmi: pointer to the mid result
1943 * @lhi: pointer to the high result
1944 *
1945 * Parse an unsigned long into 3 fields.
1946 *
William M. Brackec3b4b72005-03-15 15:50:17 +00001947 * Returns the number of significant digits in the number or
1948 * -1 if overflow of the capacity
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001949 */
1950static int
1951xmlSchemaParseUInt(const xmlChar **str, unsigned long *llo,
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00001952 unsigned long *lmi, unsigned long *lhi) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001953 unsigned long lo = 0, mi = 0, hi = 0;
1954 const xmlChar *tmp, *cur = *str;
1955 int ret = 0, i = 0;
1956
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00001957 while (*cur == '0') { /* ignore leading zeroes */
1958 cur++;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001959 }
1960 tmp = cur;
1961 while ((*tmp != 0) && (*tmp >= '0') && (*tmp <= '9')) {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00001962 i++;tmp++;ret++;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001963 }
1964 if (i > 24) {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00001965 *str = tmp;
1966 return(-1);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001967 }
1968 while (i > 16) {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00001969 hi = hi * 10 + (*cur++ - '0');
1970 i--;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001971 }
1972 while (i > 8) {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00001973 mi = mi * 10 + (*cur++ - '0');
1974 i--;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001975 }
1976 while (i > 0) {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00001977 lo = lo * 10 + (*cur++ - '0');
1978 i--;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001979 }
1980
1981 *str = cur;
1982 *llo = lo;
1983 *lmi = mi;
1984 *lhi = hi;
1985 return(ret);
1986}
1987
1988/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001989 * xmlSchemaValAtomicType:
1990 * @type: the predefined type
1991 * @value: the value to check
1992 * @val: the return computed value
1993 * @node: the node containing the value
1994 * flags: flags to control the vlidation
1995 *
1996 * Check that a value conforms to the lexical space of the atomic type.
1997 * if true a value is computed and returned in @val.
Daniel Veillard01fa6152004-06-29 17:04:39 +00001998 * This checks the value space for list types as well (IDREFS, NMTOKENS).
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001999 *
2000 * Returns 0 if this validates, a positive error code number otherwise
2001 * and -1 in case of internal or API error.
2002 */
2003static int
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002004xmlSchemaValAtomicType(xmlSchemaTypePtr type, const xmlChar * value,
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00002005 xmlSchemaValPtr * val, xmlNodePtr node, int flags,
2006 xmlSchemaWhitespaceValueType ws,
2007 int normOnTheFly, int applyNorm, int createStringValue)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002008{
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002009 xmlSchemaValPtr v;
2010 xmlChar *norm = NULL;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00002011 int ret = 0;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002012
2013 if (xmlSchemaTypesInitialized == 0)
Daniel Veillard01fa6152004-06-29 17:04:39 +00002014 xmlSchemaInitTypes();
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002015 if (type == NULL)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002016 return (-1);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002017
Daniel Veillardeebd6332004-08-26 10:30:44 +00002018 /*
2019 * validating a non existant text node is similar to validating
2020 * an empty one.
2021 */
2022 if (value == NULL)
2023 value = BAD_CAST "";
2024
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002025 if (val != NULL)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002026 *val = NULL;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002027 if ((flags == 0) && (value != NULL)) {
Kasimier T. Buchcik91feaf82004-11-12 14:04:58 +00002028
Daniel Veillard01fa6152004-06-29 17:04:39 +00002029 if ((type->builtInType != XML_SCHEMAS_STRING) &&
Kasimier T. Buchcik91feaf82004-11-12 14:04:58 +00002030 (type->builtInType != XML_SCHEMAS_ANYTYPE) &&
2031 (type->builtInType != XML_SCHEMAS_ANYSIMPLETYPE)) {
2032 if (type->builtInType == XML_SCHEMAS_NORMSTRING)
2033 norm = xmlSchemaWhiteSpaceReplace(value);
2034 else
2035 norm = xmlSchemaCollapseString(value);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002036 if (norm != NULL)
2037 value = norm;
2038 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002039 }
2040
Daniel Veillard01fa6152004-06-29 17:04:39 +00002041 switch (type->builtInType) {
William M. Brack2f2a6632004-08-20 23:09:47 +00002042 case XML_SCHEMAS_UNKNOWN:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002043 goto error;
William M. Brack2f2a6632004-08-20 23:09:47 +00002044 case XML_SCHEMAS_ANYTYPE:
2045 case XML_SCHEMAS_ANYSIMPLETYPE:
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00002046 if ((createStringValue) && (val != NULL)) {
2047 v = xmlSchemaNewValue(XML_SCHEMAS_ANYSIMPLETYPE);
2048 if (v != NULL) {
2049 v->value.str = xmlStrdup(value);
2050 *val = v;
2051 } else {
2052 goto error;
2053 }
2054 }
William M. Brack2f2a6632004-08-20 23:09:47 +00002055 goto return0;
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00002056 case XML_SCHEMAS_STRING:
2057 if (! normOnTheFly) {
2058 const xmlChar *cur = value;
2059
2060 if (ws == XML_SCHEMA_WHITESPACE_REPLACE) {
2061 while (*cur != 0) {
2062 if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) {
2063 goto return1;
2064 } else {
2065 cur++;
2066 }
2067 }
2068 } else if (ws == XML_SCHEMA_WHITESPACE_COLLAPSE) {
2069 while (*cur != 0) {
2070 if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) {
2071 goto return1;
2072 } else if IS_WSP_SPACE_CH(*cur) {
2073 cur++;
2074 if IS_WSP_SPACE_CH(*cur)
2075 goto return1;
2076 } else {
2077 cur++;
2078 }
2079 }
2080 }
2081 }
2082 if (createStringValue && (val != NULL)) {
2083 if (applyNorm) {
2084 if (ws == XML_SCHEMA_WHITESPACE_COLLAPSE)
2085 norm = xmlSchemaCollapseString(value);
2086 else if (ws == XML_SCHEMA_WHITESPACE_REPLACE)
2087 norm = xmlSchemaWhiteSpaceReplace(value);
2088 if (norm != NULL)
2089 value = norm;
2090 }
2091 v = xmlSchemaNewValue(XML_SCHEMAS_STRING);
2092 if (v != NULL) {
2093 v->value.str = xmlStrdup(value);
2094 *val = v;
2095 } else {
2096 goto error;
2097 }
2098 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002099 goto return0;
Daniel Veillard1516d5b2004-01-22 07:27:45 +00002100 case XML_SCHEMAS_NORMSTRING:{
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00002101 if (normOnTheFly) {
2102 if (applyNorm) {
2103 if (ws == XML_SCHEMA_WHITESPACE_COLLAPSE)
2104 norm = xmlSchemaCollapseString(value);
2105 else
2106 norm = xmlSchemaWhiteSpaceReplace(value);
2107 if (norm != NULL)
2108 value = norm;
2109 }
2110 } else {
2111 const xmlChar *cur = value;
2112 while (*cur != 0) {
2113 if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) {
2114 goto return1;
2115 } else {
2116 cur++;
2117 }
2118 }
2119 }
Daniel Veillard1516d5b2004-01-22 07:27:45 +00002120 if (val != NULL) {
2121 v = xmlSchemaNewValue(XML_SCHEMAS_NORMSTRING);
2122 if (v != NULL) {
2123 v->value.str = xmlStrdup(value);
2124 *val = v;
2125 } else {
2126 goto error;
2127 }
2128 }
2129 goto return0;
2130 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002131 case XML_SCHEMAS_DECIMAL:{
William M. Brack273670f2005-03-11 15:55:14 +00002132 const xmlChar *cur = value;
2133 unsigned int len, neg = 0;
2134 xmlChar cval[25];
2135 xmlChar *cptr = cval;
2136 int dec = -1;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002137
2138 if (cur == NULL)
2139 goto return1;
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00002140
2141 if (normOnTheFly)
2142 while IS_WSP_BLANK_CH(*cur) cur++;
2143
William M. Brack273670f2005-03-11 15:55:14 +00002144 /* First we handle an optional sign */
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002145 if (*cur == '+')
2146 cur++;
2147 else if (*cur == '-') {
2148 neg = 1;
2149 cur++;
2150 }
William M. Brack273670f2005-03-11 15:55:14 +00002151 /*
2152 * Next we "pre-parse" the number, in preparation for calling
2153 * the common routine xmlSchemaParseUInt. We get rid of any
2154 * leading zeroes (because we have reserved only 25 chars),
2155 * and note the position of any decimal point.
2156 */
2157 len = 0;
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00002158 /*
2159 * Skip leading zeroes.
2160 */
2161 while (*cur == '0')
William M. Brack273670f2005-03-11 15:55:14 +00002162 cur++;
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00002163 if (*cur != 0) {
2164 while (len < 24) {
2165 if ((*cur >= '0') && (*cur <= '9')) {
2166 *cptr++ = *cur++;
2167 len++;
2168 } else if (*cur == '.') {
2169 if (dec != -1)
2170 goto return1; /* multiple decimal points */
2171 cur++;
2172 if ((*cur == 0) && (cur -1 == value))
2173 goto return1;
2174
2175 dec = len;
2176 while ((len < 24) && (*cur >= '0') &&
2177 (*cur <= '9')) {
2178 *cptr++ = *cur++;
2179 len++;
2180 }
2181 break;
2182 } else
2183 break;
2184 }
William M. Brack273670f2005-03-11 15:55:14 +00002185 }
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00002186 if (normOnTheFly)
2187 while IS_WSP_BLANK_CH(*cur) cur++;
William M. Brack273670f2005-03-11 15:55:14 +00002188 if (*cur != 0)
2189 goto return1; /* error if any extraneous chars */
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002190 if (val != NULL) {
2191 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
2192 if (v != NULL) {
William M. Brack273670f2005-03-11 15:55:14 +00002193 /*
2194 * If a mixed decimal, get rid of trailing zeroes
2195 */
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00002196 if (dec != -1) {
Kasimier T. Buchcik6d30ff22005-07-06 11:44:51 +00002197 while ((len > dec) && (cptr > cval) &&
2198 (*(cptr-1) == '0')) {
William M. Brack273670f2005-03-11 15:55:14 +00002199 cptr--;
2200 len--;
2201 }
2202 }
2203 *cptr = 0; /* Terminate our (preparsed) string */
2204 cptr = cval;
2205 /*
2206 * Now evaluate the significant digits of the number
2207 */
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00002208 if (*cptr != 0)
2209 xmlSchemaParseUInt((const xmlChar **)&cptr,
William M. Brack273670f2005-03-11 15:55:14 +00002210 &v->value.decimal.lo,
2211 &v->value.decimal.mi,
2212 &v->value.decimal.hi);
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00002213 /*
2214 * Set the total digits to 1 if a zero value.
2215 */
2216 if (len == 0)
2217 len++;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002218 v->value.decimal.sign = neg;
William M. Brack273670f2005-03-11 15:55:14 +00002219 if (dec == -1) {
2220 v->value.decimal.frac = 0;
2221 v->value.decimal.total = len;
2222 } else {
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00002223 v->value.decimal.frac = len - dec;
2224 v->value.decimal.total = len;
William M. Brack273670f2005-03-11 15:55:14 +00002225 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002226 *val = v;
2227 }
2228 }
2229 goto return0;
2230 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002231 case XML_SCHEMAS_TIME:
2232 case XML_SCHEMAS_GDAY:
2233 case XML_SCHEMAS_GMONTH:
2234 case XML_SCHEMAS_GMONTHDAY:
2235 case XML_SCHEMAS_GYEAR:
2236 case XML_SCHEMAS_GYEARMONTH:
2237 case XML_SCHEMAS_DATE:
2238 case XML_SCHEMAS_DATETIME:
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00002239 ret = xmlSchemaValidateDates(type->builtInType, value, val,
2240 normOnTheFly);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002241 break;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002242 case XML_SCHEMAS_DURATION:
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00002243 ret = xmlSchemaValidateDuration(type, value, val,
2244 normOnTheFly);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002245 break;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002246 case XML_SCHEMAS_FLOAT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002247 case XML_SCHEMAS_DOUBLE:{
2248 const xmlChar *cur = value;
2249 int neg = 0;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002250
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002251 if (cur == NULL)
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00002252 goto return1;
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00002253
2254 if (normOnTheFly)
2255 while IS_WSP_BLANK_CH(*cur) cur++;
2256
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002257 if ((cur[0] == 'N') && (cur[1] == 'a') && (cur[2] == 'N')) {
2258 cur += 3;
2259 if (*cur != 0)
2260 goto return1;
2261 if (val != NULL) {
2262 if (type == xmlSchemaTypeFloatDef) {
2263 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
2264 if (v != NULL) {
2265 v->value.f = (float) xmlXPathNAN;
2266 } else {
2267 xmlSchemaFreeValue(v);
2268 goto error;
2269 }
2270 } else {
2271 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
2272 if (v != NULL) {
2273 v->value.d = xmlXPathNAN;
2274 } else {
2275 xmlSchemaFreeValue(v);
2276 goto error;
2277 }
2278 }
2279 *val = v;
2280 }
2281 goto return0;
2282 }
2283 if (*cur == '-') {
2284 neg = 1;
2285 cur++;
2286 }
2287 if ((cur[0] == 'I') && (cur[1] == 'N') && (cur[2] == 'F')) {
2288 cur += 3;
2289 if (*cur != 0)
2290 goto return1;
2291 if (val != NULL) {
2292 if (type == xmlSchemaTypeFloatDef) {
2293 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
2294 if (v != NULL) {
2295 if (neg)
2296 v->value.f = (float) xmlXPathNINF;
2297 else
2298 v->value.f = (float) xmlXPathPINF;
2299 } else {
2300 xmlSchemaFreeValue(v);
2301 goto error;
2302 }
2303 } else {
2304 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
2305 if (v != NULL) {
2306 if (neg)
2307 v->value.d = xmlXPathNINF;
2308 else
2309 v->value.d = xmlXPathPINF;
2310 } else {
2311 xmlSchemaFreeValue(v);
2312 goto error;
2313 }
2314 }
2315 *val = v;
2316 }
2317 goto return0;
2318 }
2319 if ((neg == 0) && (*cur == '+'))
2320 cur++;
2321 if ((cur[0] == 0) || (cur[0] == '+') || (cur[0] == '-'))
2322 goto return1;
2323 while ((*cur >= '0') && (*cur <= '9')) {
2324 cur++;
2325 }
2326 if (*cur == '.') {
2327 cur++;
2328 while ((*cur >= '0') && (*cur <= '9'))
2329 cur++;
2330 }
2331 if ((*cur == 'e') || (*cur == 'E')) {
2332 cur++;
2333 if ((*cur == '-') || (*cur == '+'))
2334 cur++;
2335 while ((*cur >= '0') && (*cur <= '9'))
2336 cur++;
2337 }
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00002338 if (normOnTheFly)
2339 while IS_WSP_BLANK_CH(*cur) cur++;
2340
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002341 if (*cur != 0)
2342 goto return1;
2343 if (val != NULL) {
2344 if (type == xmlSchemaTypeFloatDef) {
2345 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
2346 if (v != NULL) {
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00002347 /*
2348 * TODO: sscanf seems not to give the correct
2349 * value for extremely high/low values.
2350 * E.g. "1E-149" results in zero.
2351 */
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002352 if (sscanf((const char *) value, "%f",
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002353 &(v->value.f)) == 1) {
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00002354 *val = v;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002355 } else {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002356 xmlSchemaFreeValue(v);
2357 goto return1;
2358 }
2359 } else {
2360 goto error;
2361 }
2362 } else {
2363 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
2364 if (v != NULL) {
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00002365 /*
2366 * TODO: sscanf seems not to give the correct
2367 * value for extremely high/low values.
2368 */
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002369 if (sscanf((const char *) value, "%lf",
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002370 &(v->value.d)) == 1) {
2371 *val = v;
2372 } else {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002373 xmlSchemaFreeValue(v);
2374 goto return1;
2375 }
2376 } else {
2377 goto error;
2378 }
2379 }
2380 }
2381 goto return0;
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00002382 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002383 case XML_SCHEMAS_BOOLEAN:{
2384 const xmlChar *cur = value;
2385
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00002386 if (normOnTheFly) {
2387 while IS_WSP_BLANK_CH(*cur) cur++;
2388 if (*cur == '0') {
2389 ret = 0;
2390 cur++;
2391 } else if (*cur == '1') {
2392 ret = 1;
2393 cur++;
2394 } else if (*cur == 't') {
2395 cur++;
2396 if ((*cur++ == 'r') && (*cur++ == 'u') &&
2397 (*cur++ == 'e')) {
2398 ret = 1;
2399 } else
2400 goto return1;
2401 } else if (*cur == 'f') {
2402 cur++;
2403 if ((*cur++ == 'a') && (*cur++ == 'l') &&
2404 (*cur++ == 's') && (*cur++ == 'e')) {
2405 ret = 0;
2406 } else
2407 goto return1;
2408 }
2409 if (*cur != 0) {
2410 while IS_WSP_BLANK_CH(*cur) cur++;
2411 if (*cur != 0)
2412 goto return1;
2413 }
2414 } else {
2415 if ((cur[0] == '0') && (cur[1] == 0))
2416 ret = 0;
2417 else if ((cur[0] == '1') && (cur[1] == 0))
2418 ret = 1;
2419 else if ((cur[0] == 't') && (cur[1] == 'r')
2420 && (cur[2] == 'u') && (cur[3] == 'e')
2421 && (cur[4] == 0))
2422 ret = 1;
2423 else if ((cur[0] == 'f') && (cur[1] == 'a')
2424 && (cur[2] == 'l') && (cur[3] == 's')
2425 && (cur[4] == 'e') && (cur[5] == 0))
2426 ret = 0;
2427 else
2428 goto return1;
2429 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002430 if (val != NULL) {
2431 v = xmlSchemaNewValue(XML_SCHEMAS_BOOLEAN);
2432 if (v != NULL) {
2433 v->value.b = ret;
2434 *val = v;
2435 } else {
2436 goto error;
2437 }
2438 }
2439 goto return0;
2440 }
2441 case XML_SCHEMAS_TOKEN:{
2442 const xmlChar *cur = value;
2443
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00002444 if (! normOnTheFly) {
2445 while (*cur != 0) {
2446 if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) {
2447 goto return1;
2448 } else if (*cur == ' ') {
2449 cur++;
2450 if (*cur == 0)
2451 goto return1;
2452 if (*cur == ' ')
2453 goto return1;
2454 } else {
2455 cur++;
2456 }
2457 }
2458 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002459 if (val != NULL) {
2460 v = xmlSchemaNewValue(XML_SCHEMAS_TOKEN);
2461 if (v != NULL) {
2462 v->value.str = xmlStrdup(value);
2463 *val = v;
2464 } else {
2465 goto error;
2466 }
2467 }
2468 goto return0;
2469 }
2470 case XML_SCHEMAS_LANGUAGE:
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00002471 if (normOnTheFly) {
2472 norm = xmlSchemaCollapseString(value);
2473 if (norm != NULL)
2474 value = norm;
2475 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002476 if (xmlCheckLanguageID(value) == 1) {
2477 if (val != NULL) {
2478 v = xmlSchemaNewValue(XML_SCHEMAS_LANGUAGE);
2479 if (v != NULL) {
2480 v->value.str = xmlStrdup(value);
2481 *val = v;
2482 } else {
2483 goto error;
2484 }
2485 }
2486 goto return0;
2487 }
2488 goto return1;
2489 case XML_SCHEMAS_NMTOKEN:
2490 if (xmlValidateNMToken(value, 1) == 0) {
2491 if (val != NULL) {
2492 v = xmlSchemaNewValue(XML_SCHEMAS_NMTOKEN);
2493 if (v != NULL) {
2494 v->value.str = xmlStrdup(value);
2495 *val = v;
2496 } else {
2497 goto error;
2498 }
2499 }
2500 goto return0;
2501 }
2502 goto return1;
2503 case XML_SCHEMAS_NMTOKENS:
2504 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeNmtokenDef,
2505 value, val, node);
2506 if (ret > 0)
2507 ret = 0;
2508 else
2509 ret = 1;
2510 goto done;
2511 case XML_SCHEMAS_NAME:
2512 ret = xmlValidateName(value, 1);
Daniel Veillarddf292f72005-01-16 19:00:15 +00002513 if ((ret == 0) && (val != NULL) && (value != NULL)) {
2514 v = xmlSchemaNewValue(XML_SCHEMAS_NAME);
2515 if (v != NULL) {
2516 const xmlChar *start = value, *end;
2517 while (IS_BLANK_CH(*start)) start++;
2518 end = start;
2519 while ((*end != 0) && (!IS_BLANK_CH(*end))) end++;
2520 v->value.str = xmlStrndup(start, end - start);
2521 *val = v;
2522 } else {
2523 goto error;
2524 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002525 }
2526 goto done;
2527 case XML_SCHEMAS_QNAME:{
Kasimier T. Buchcik1c720df2005-06-09 14:54:59 +00002528 const xmlChar *uri = NULL;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002529 xmlChar *local = NULL;
2530
2531 ret = xmlValidateQName(value, 1);
Kasimier T. Buchcik1c720df2005-06-09 14:54:59 +00002532 if (ret != 0)
2533 goto done;
2534 if (node != NULL) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002535 xmlChar *prefix;
Kasimier T. Buchcik1c720df2005-06-09 14:54:59 +00002536 xmlNsPtr ns;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002537
2538 local = xmlSplitQName2(value, &prefix);
Kasimier T. Buchcik1c720df2005-06-09 14:54:59 +00002539 ns = xmlSearchNs(node->doc, node, prefix);
2540 if ((ns == NULL) && (prefix != NULL)) {
2541 xmlFree(prefix);
2542 if (local != NULL)
2543 xmlFree(local);
2544 goto return1;
2545 }
2546 if (ns != NULL)
2547 uri = ns->href;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002548 if (prefix != NULL)
2549 xmlFree(prefix);
2550 }
Kasimier T. Buchcik1c720df2005-06-09 14:54:59 +00002551 if (val != NULL) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002552 v = xmlSchemaNewValue(XML_SCHEMAS_QNAME);
Kasimier T. Buchcik1c720df2005-06-09 14:54:59 +00002553 if (v == NULL) {
2554 if (local != NULL)
2555 xmlFree(local);
2556 goto error;
2557 }
2558 if (local != NULL)
2559 v->value.qname.name = local;
2560 else
2561 v->value.qname.name = xmlStrdup(value);
2562 if (uri != NULL)
2563 v->value.qname.uri = xmlStrdup(uri);
2564 *val = v;
2565 } else
2566 if (local != NULL)
2567 xmlFree(local);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002568 goto done;
2569 }
2570 case XML_SCHEMAS_NCNAME:
2571 ret = xmlValidateNCName(value, 1);
2572 if ((ret == 0) && (val != NULL)) {
2573 v = xmlSchemaNewValue(XML_SCHEMAS_NCNAME);
2574 if (v != NULL) {
2575 v->value.str = xmlStrdup(value);
2576 *val = v;
2577 } else {
2578 goto error;
2579 }
2580 }
2581 goto done;
2582 case XML_SCHEMAS_ID:
2583 ret = xmlValidateNCName(value, 1);
2584 if ((ret == 0) && (val != NULL)) {
2585 v = xmlSchemaNewValue(XML_SCHEMAS_ID);
2586 if (v != NULL) {
2587 v->value.str = xmlStrdup(value);
2588 *val = v;
2589 } else {
2590 goto error;
2591 }
2592 }
2593 if ((ret == 0) && (node != NULL) &&
2594 (node->type == XML_ATTRIBUTE_NODE)) {
2595 xmlAttrPtr attr = (xmlAttrPtr) node;
2596
2597 /*
2598 * NOTE: the IDness might have already be declared in the DTD
2599 */
2600 if (attr->atype != XML_ATTRIBUTE_ID) {
2601 xmlIDPtr res;
2602 xmlChar *strip;
2603
2604 strip = xmlSchemaStrip(value);
2605 if (strip != NULL) {
2606 res = xmlAddID(NULL, node->doc, strip, attr);
2607 xmlFree(strip);
2608 } else
2609 res = xmlAddID(NULL, node->doc, value, attr);
2610 if (res == NULL) {
2611 ret = 2;
2612 } else {
2613 attr->atype = XML_ATTRIBUTE_ID;
2614 }
2615 }
2616 }
2617 goto done;
2618 case XML_SCHEMAS_IDREF:
2619 ret = xmlValidateNCName(value, 1);
2620 if ((ret == 0) && (val != NULL)) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00002621 v = xmlSchemaNewValue(XML_SCHEMAS_IDREF);
2622 if (v == NULL)
2623 goto error;
2624 v->value.str = xmlStrdup(value);
2625 *val = v;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002626 }
2627 if ((ret == 0) && (node != NULL) &&
2628 (node->type == XML_ATTRIBUTE_NODE)) {
2629 xmlAttrPtr attr = (xmlAttrPtr) node;
2630 xmlChar *strip;
2631
2632 strip = xmlSchemaStrip(value);
2633 if (strip != NULL) {
2634 xmlAddRef(NULL, node->doc, strip, attr);
2635 xmlFree(strip);
2636 } else
2637 xmlAddRef(NULL, node->doc, value, attr);
2638 attr->atype = XML_ATTRIBUTE_IDREF;
2639 }
2640 goto done;
2641 case XML_SCHEMAS_IDREFS:
2642 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeIdrefDef,
2643 value, val, node);
2644 if (ret < 0)
2645 ret = 2;
2646 else
2647 ret = 0;
2648 if ((ret == 0) && (node != NULL) &&
2649 (node->type == XML_ATTRIBUTE_NODE)) {
2650 xmlAttrPtr attr = (xmlAttrPtr) node;
2651
2652 attr->atype = XML_ATTRIBUTE_IDREFS;
2653 }
2654 goto done;
2655 case XML_SCHEMAS_ENTITY:{
2656 xmlChar *strip;
2657
2658 ret = xmlValidateNCName(value, 1);
2659 if ((node == NULL) || (node->doc == NULL))
2660 ret = 3;
2661 if (ret == 0) {
2662 xmlEntityPtr ent;
2663
2664 strip = xmlSchemaStrip(value);
2665 if (strip != NULL) {
2666 ent = xmlGetDocEntity(node->doc, strip);
2667 xmlFree(strip);
2668 } else {
2669 ent = xmlGetDocEntity(node->doc, value);
2670 }
2671 if ((ent == NULL) ||
2672 (ent->etype !=
2673 XML_EXTERNAL_GENERAL_UNPARSED_ENTITY))
2674 ret = 4;
2675 }
2676 if ((ret == 0) && (val != NULL)) {
2677 TODO;
2678 }
2679 if ((ret == 0) && (node != NULL) &&
2680 (node->type == XML_ATTRIBUTE_NODE)) {
2681 xmlAttrPtr attr = (xmlAttrPtr) node;
2682
2683 attr->atype = XML_ATTRIBUTE_ENTITY;
2684 }
2685 goto done;
2686 }
2687 case XML_SCHEMAS_ENTITIES:
2688 if ((node == NULL) || (node->doc == NULL))
2689 goto return3;
2690 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeEntityDef,
2691 value, val, node);
2692 if (ret <= 0)
2693 ret = 1;
2694 else
2695 ret = 0;
2696 if ((ret == 0) && (node != NULL) &&
2697 (node->type == XML_ATTRIBUTE_NODE)) {
2698 xmlAttrPtr attr = (xmlAttrPtr) node;
2699
2700 attr->atype = XML_ATTRIBUTE_ENTITIES;
2701 }
2702 goto done;
2703 case XML_SCHEMAS_NOTATION:{
2704 xmlChar *uri = NULL;
2705 xmlChar *local = NULL;
2706
2707 ret = xmlValidateQName(value, 1);
2708 if ((ret == 0) && (node != NULL)) {
2709 xmlChar *prefix;
2710
2711 local = xmlSplitQName2(value, &prefix);
2712 if (prefix != NULL) {
2713 xmlNsPtr ns;
2714
2715 ns = xmlSearchNs(node->doc, node, prefix);
2716 if (ns == NULL)
2717 ret = 1;
2718 else if (val != NULL)
2719 uri = xmlStrdup(ns->href);
2720 }
2721 if ((local != NULL) && ((val == NULL) || (ret != 0)))
2722 xmlFree(local);
2723 if (prefix != NULL)
2724 xmlFree(prefix);
2725 }
2726 if ((node == NULL) || (node->doc == NULL))
2727 ret = 3;
2728 if (ret == 0) {
2729 ret = xmlValidateNotationUse(NULL, node->doc, value);
2730 if (ret == 1)
2731 ret = 0;
2732 else
2733 ret = 1;
2734 }
2735 if ((ret == 0) && (val != NULL)) {
2736 v = xmlSchemaNewValue(XML_SCHEMAS_NOTATION);
2737 if (v != NULL) {
2738 if (local != NULL)
2739 v->value.qname.name = local;
2740 else
2741 v->value.qname.name = xmlStrdup(value);
2742 if (uri != NULL)
2743 v->value.qname.uri = uri;
2744
2745 *val = v;
2746 } else {
2747 if (local != NULL)
2748 xmlFree(local);
2749 if (uri != NULL)
2750 xmlFree(uri);
2751 goto error;
2752 }
2753 }
2754 goto done;
2755 }
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00002756 case XML_SCHEMAS_ANYURI:{
Daniel Veillard11c466a2004-03-14 12:20:15 +00002757 if (*value != 0) {
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00002758 xmlURIPtr uri;
2759 if (normOnTheFly) {
2760 norm = xmlSchemaCollapseString(value);
2761 if (norm != NULL)
2762 value = norm;
2763 }
2764 uri = xmlParseURI((const char *) value);
Daniel Veillard11c466a2004-03-14 12:20:15 +00002765 if (uri == NULL)
2766 goto return1;
2767 xmlFreeURI(uri);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002768 }
Daniel Veillard11c466a2004-03-14 12:20:15 +00002769
2770 if (val != NULL) {
2771 v = xmlSchemaNewValue(XML_SCHEMAS_ANYURI);
2772 if (v == NULL)
2773 goto error;
2774 v->value.str = xmlStrdup(value);
2775 *val = v;
2776 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002777 goto return0;
2778 }
2779 case XML_SCHEMAS_HEXBINARY:{
Kasimier T. Buchcik8dd1e1b2005-06-09 13:14:38 +00002780 const xmlChar *cur = value, *start;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002781 xmlChar *base;
2782 int total, i = 0;
2783
Daniel Veillardf34a20e2004-08-31 08:42:17 +00002784 if (cur == NULL)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002785 goto return1;
2786
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00002787 if (normOnTheFly)
2788 while IS_WSP_BLANK_CH(*cur) cur++;
2789
Kasimier T. Buchcik8dd1e1b2005-06-09 13:14:38 +00002790 start = cur;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002791 while (((*cur >= '0') && (*cur <= '9')) ||
2792 ((*cur >= 'A') && (*cur <= 'F')) ||
2793 ((*cur >= 'a') && (*cur <= 'f'))) {
2794 i++;
2795 cur++;
2796 }
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00002797 if (normOnTheFly)
2798 while IS_WSP_BLANK_CH(*cur) cur++;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002799
2800 if (*cur != 0)
2801 goto return1;
2802 if ((i % 2) != 0)
2803 goto return1;
2804
2805 if (val != NULL) {
2806
2807 v = xmlSchemaNewValue(XML_SCHEMAS_HEXBINARY);
2808 if (v == NULL)
2809 goto error;
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00002810 /*
2811 * Copy only the normalized piece.
2812 * CRITICAL TODO: Check this.
2813 */
Kasimier T. Buchcik8dd1e1b2005-06-09 13:14:38 +00002814 cur = xmlStrndup(start, i);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002815 if (cur == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002816 xmlSchemaTypeErrMemory(node, "allocating hexbin data");
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002817 xmlFree(v);
2818 goto return1;
2819 }
2820
2821 total = i / 2; /* number of octets */
2822
2823 base = (xmlChar *) cur;
2824 while (i-- > 0) {
2825 if (*base >= 'a')
2826 *base = *base - ('a' - 'A');
2827 base++;
2828 }
2829
2830 v->value.hex.str = (xmlChar *) cur;
2831 v->value.hex.total = total;
2832 *val = v;
2833 }
2834 goto return0;
2835 }
2836 case XML_SCHEMAS_BASE64BINARY:{
2837 /* ISSUE:
2838 *
2839 * Ignore all stray characters? (yes, currently)
2840 * Worry about long lines? (no, currently)
2841 *
2842 * rfc2045.txt:
2843 *
2844 * "The encoded output stream must be represented in lines of
2845 * no more than 76 characters each. All line breaks or other
2846 * characters not found in Table 1 must be ignored by decoding
2847 * software. In base64 data, characters other than those in
2848 * Table 1, line breaks, and other white space probably
2849 * indicate a transmission error, about which a warning
2850 * message or even a message rejection might be appropriate
2851 * under some circumstances." */
2852 const xmlChar *cur = value;
2853 xmlChar *base;
2854 int total, i = 0, pad = 0;
2855
2856 if (cur == NULL)
2857 goto return1;
2858
2859 for (; *cur; ++cur) {
2860 int decc;
2861
2862 decc = _xmlSchemaBase64Decode(*cur);
2863 if (decc < 0) ;
2864 else if (decc < 64)
2865 i++;
2866 else
2867 break;
2868 }
2869 for (; *cur; ++cur) {
2870 int decc;
2871
2872 decc = _xmlSchemaBase64Decode(*cur);
2873 if (decc < 0) ;
2874 else if (decc < 64)
2875 goto return1;
2876 if (decc == 64)
2877 pad++;
2878 }
2879
2880 /* rfc2045.txt: "Special processing is performed if fewer than
2881 * 24 bits are available at the end of the data being encoded.
2882 * A full encoding quantum is always completed at the end of a
2883 * body. When fewer than 24 input bits are available in an
2884 * input group, zero bits are added (on the right) to form an
2885 * integral number of 6-bit groups. Padding at the end of the
2886 * data is performed using the "=" character. Since all
2887 * base64 input is an integral number of octets, only the
2888 * following cases can arise: (1) the final quantum of
2889 * encoding input is an integral multiple of 24 bits; here,
2890 * the final unit of encoded output will be an integral
2891 * multiple ofindent: Standard input:701: Warning:old style
2892 * assignment ambiguity in "=*". Assuming "= *" 4 characters
2893 * with no "=" padding, (2) the final
2894 * quantum of encoding input is exactly 8 bits; here, the
2895 * final unit of encoded output will be two characters
2896 * followed by two "=" padding characters, or (3) the final
2897 * quantum of encoding input is exactly 16 bits; here, the
2898 * final unit of encoded output will be three characters
2899 * followed by one "=" padding character." */
2900
2901 total = 3 * (i / 4);
2902 if (pad == 0) {
2903 if (i % 4 != 0)
2904 goto return1;
2905 } else if (pad == 1) {
2906 int decc;
2907
2908 if (i % 4 != 3)
2909 goto return1;
2910 for (decc = _xmlSchemaBase64Decode(*cur);
2911 (decc < 0) || (decc > 63);
2912 decc = _xmlSchemaBase64Decode(*cur))
2913 --cur;
2914 /* 16bits in 24bits means 2 pad bits: nnnnnn nnmmmm mmmm00*/
2915 /* 00111100 -> 0x3c */
2916 if (decc & ~0x3c)
2917 goto return1;
2918 total += 2;
2919 } else if (pad == 2) {
2920 int decc;
2921
2922 if (i % 4 != 2)
2923 goto return1;
2924 for (decc = _xmlSchemaBase64Decode(*cur);
2925 (decc < 0) || (decc > 63);
2926 decc = _xmlSchemaBase64Decode(*cur))
2927 --cur;
2928 /* 8bits in 12bits means 4 pad bits: nnnnnn nn0000 */
2929 /* 00110000 -> 0x30 */
2930 if (decc & ~0x30)
2931 goto return1;
2932 total += 1;
2933 } else
2934 goto return1;
2935
2936 if (val != NULL) {
2937 v = xmlSchemaNewValue(XML_SCHEMAS_BASE64BINARY);
2938 if (v == NULL)
2939 goto error;
2940 base =
2941 (xmlChar *) xmlMallocAtomic((i + pad + 1) *
2942 sizeof(xmlChar));
2943 if (base == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002944 xmlSchemaTypeErrMemory(node, "allocating base64 data");
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002945 xmlFree(v);
2946 goto return1;
2947 }
2948 v->value.base64.str = base;
2949 for (cur = value; *cur; ++cur)
2950 if (_xmlSchemaBase64Decode(*cur) >= 0) {
2951 *base = *cur;
2952 ++base;
2953 }
2954 *base = 0;
2955 v->value.base64.total = total;
2956 *val = v;
2957 }
2958 goto return0;
2959 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002960 case XML_SCHEMAS_INTEGER:
2961 case XML_SCHEMAS_PINTEGER:
2962 case XML_SCHEMAS_NPINTEGER:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002963 case XML_SCHEMAS_NINTEGER:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002964 case XML_SCHEMAS_NNINTEGER:{
2965 const xmlChar *cur = value;
2966 unsigned long lo, mi, hi;
William M. Brackec3b4b72005-03-15 15:50:17 +00002967 int sign = 0;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002968
2969 if (cur == NULL)
2970 goto return1;
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00002971 if (normOnTheFly)
2972 while IS_WSP_BLANK_CH(*cur) cur++;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002973 if (*cur == '-') {
2974 sign = 1;
2975 cur++;
2976 } else if (*cur == '+')
2977 cur++;
William M. Brackec3b4b72005-03-15 15:50:17 +00002978 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2979 if (ret == -1)
2980 goto return1;
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00002981 if (normOnTheFly)
2982 while IS_WSP_BLANK_CH(*cur) cur++;
William M. Brackec3b4b72005-03-15 15:50:17 +00002983 if (*cur != 0)
2984 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002985 if (type->builtInType == XML_SCHEMAS_NPINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002986 if ((sign == 0) &&
2987 ((hi != 0) || (mi != 0) || (lo != 0)))
2988 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002989 } else if (type->builtInType == XML_SCHEMAS_PINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002990 if (sign == 1)
2991 goto return1;
2992 if ((hi == 0) && (mi == 0) && (lo == 0))
2993 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002994 } else if (type->builtInType == XML_SCHEMAS_NINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002995 if (sign == 0)
2996 goto return1;
2997 if ((hi == 0) && (mi == 0) && (lo == 0))
2998 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002999 } else if (type->builtInType == XML_SCHEMAS_NNINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003000 if ((sign == 1) &&
3001 ((hi != 0) || (mi != 0) || (lo != 0)))
3002 goto return1;
3003 }
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003004 if (val != NULL) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00003005 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003006 if (v != NULL) {
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00003007 if (ret == 0)
3008 ret++;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003009 v->value.decimal.lo = lo;
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003010 v->value.decimal.mi = mi;
3011 v->value.decimal.hi = hi;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003012 v->value.decimal.sign = sign;
3013 v->value.decimal.frac = 0;
William M. Brackec3b4b72005-03-15 15:50:17 +00003014 v->value.decimal.total = ret;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003015 *val = v;
3016 }
3017 }
3018 goto return0;
3019 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003020 case XML_SCHEMAS_LONG:
3021 case XML_SCHEMAS_BYTE:
3022 case XML_SCHEMAS_SHORT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003023 case XML_SCHEMAS_INT:{
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003024 const xmlChar *cur = value;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003025 unsigned long lo, mi, hi;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003026 int sign = 0;
3027
3028 if (cur == NULL)
3029 goto return1;
3030 if (*cur == '-') {
3031 sign = 1;
3032 cur++;
3033 } else if (*cur == '+')
3034 cur++;
William M. Brackec3b4b72005-03-15 15:50:17 +00003035 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
3036 if (ret < 0)
3037 goto return1;
3038 if (*cur != 0)
3039 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00003040 if (type->builtInType == XML_SCHEMAS_LONG) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003041 if (hi >= 922) {
3042 if (hi > 922)
3043 goto return1;
3044 if (mi >= 33720368) {
3045 if (mi > 33720368)
3046 goto return1;
3047 if ((sign == 0) && (lo > 54775807))
3048 goto return1;
3049 if ((sign == 1) && (lo > 54775808))
3050 goto return1;
3051 }
3052 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00003053 } else if (type->builtInType == XML_SCHEMAS_INT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003054 if (hi != 0)
3055 goto return1;
3056 if (mi >= 21) {
3057 if (mi > 21)
3058 goto return1;
3059 if ((sign == 0) && (lo > 47483647))
3060 goto return1;
3061 if ((sign == 1) && (lo > 47483648))
3062 goto return1;
3063 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00003064 } else if (type->builtInType == XML_SCHEMAS_SHORT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003065 if ((mi != 0) || (hi != 0))
3066 goto return1;
3067 if ((sign == 1) && (lo > 32768))
3068 goto return1;
3069 if ((sign == 0) && (lo > 32767))
3070 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00003071 } else if (type->builtInType == XML_SCHEMAS_BYTE) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003072 if ((mi != 0) || (hi != 0))
3073 goto return1;
3074 if ((sign == 1) && (lo > 128))
3075 goto return1;
3076 if ((sign == 0) && (lo > 127))
3077 goto return1;
3078 }
3079 if (val != NULL) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00003080 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003081 if (v != NULL) {
3082 v->value.decimal.lo = lo;
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003083 v->value.decimal.mi = mi;
3084 v->value.decimal.hi = hi;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003085 v->value.decimal.sign = sign;
3086 v->value.decimal.frac = 0;
William M. Brackec3b4b72005-03-15 15:50:17 +00003087 v->value.decimal.total = ret;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003088 *val = v;
3089 }
3090 }
3091 goto return0;
3092 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003093 case XML_SCHEMAS_UINT:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003094 case XML_SCHEMAS_ULONG:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003095 case XML_SCHEMAS_USHORT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003096 case XML_SCHEMAS_UBYTE:{
3097 const xmlChar *cur = value;
3098 unsigned long lo, mi, hi;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003099
3100 if (cur == NULL)
3101 goto return1;
William M. Brackec3b4b72005-03-15 15:50:17 +00003102 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
3103 if (ret < 0)
3104 goto return1;
3105 if (*cur != 0)
3106 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00003107 if (type->builtInType == XML_SCHEMAS_ULONG) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003108 if (hi >= 1844) {
3109 if (hi > 1844)
3110 goto return1;
3111 if (mi >= 67440737) {
3112 if (mi > 67440737)
3113 goto return1;
3114 if (lo > 9551615)
3115 goto return1;
3116 }
3117 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00003118 } else if (type->builtInType == XML_SCHEMAS_UINT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003119 if (hi != 0)
3120 goto return1;
3121 if (mi >= 42) {
3122 if (mi > 42)
3123 goto return1;
3124 if (lo > 94967295)
3125 goto return1;
3126 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00003127 } else if (type->builtInType == XML_SCHEMAS_USHORT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003128 if ((mi != 0) || (hi != 0))
3129 goto return1;
3130 if (lo > 65535)
3131 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00003132 } else if (type->builtInType == XML_SCHEMAS_UBYTE) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003133 if ((mi != 0) || (hi != 0))
3134 goto return1;
3135 if (lo > 255)
3136 goto return1;
3137 }
3138 if (val != NULL) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00003139 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003140 if (v != NULL) {
3141 v->value.decimal.lo = lo;
3142 v->value.decimal.mi = mi;
3143 v->value.decimal.hi = hi;
3144 v->value.decimal.sign = 0;
3145 v->value.decimal.frac = 0;
William M. Brackec3b4b72005-03-15 15:50:17 +00003146 v->value.decimal.total = ret;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003147 *val = v;
3148 }
3149 }
3150 goto return0;
3151 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003152 }
3153
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003154 done:
3155 if (norm != NULL)
3156 xmlFree(norm);
3157 return (ret);
3158 return3:
3159 if (norm != NULL)
3160 xmlFree(norm);
3161 return (3);
3162 return1:
3163 if (norm != NULL)
3164 xmlFree(norm);
3165 return (1);
3166 return0:
3167 if (norm != NULL)
3168 xmlFree(norm);
3169 return (0);
3170 error:
3171 if (norm != NULL)
3172 xmlFree(norm);
3173 return (-1);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003174}
3175
3176/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00003177 * xmlSchemaValPredefTypeNode:
Daniel Veillard4255d502002-04-16 15:50:10 +00003178 * @type: the predefined type
3179 * @value: the value to check
3180 * @val: the return computed value
Daniel Veillardc3da18a2003-03-18 00:31:04 +00003181 * @node: the node containing the value
Daniel Veillard4255d502002-04-16 15:50:10 +00003182 *
3183 * Check that a value conforms to the lexical space of the predefined type.
3184 * if true a value is computed and returned in @val.
3185 *
3186 * Returns 0 if this validates, a positive error code number otherwise
3187 * and -1 in case of internal or API error.
3188 */
3189int
Daniel Veillardc3da18a2003-03-18 00:31:04 +00003190xmlSchemaValPredefTypeNode(xmlSchemaTypePtr type, const xmlChar *value,
3191 xmlSchemaValPtr *val, xmlNodePtr node) {
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00003192 return(xmlSchemaValAtomicType(type, value, val, node, 0,
3193 XML_SCHEMA_WHITESPACE_UNKNOWN, 1, 1, 0));
Daniel Veillard4255d502002-04-16 15:50:10 +00003194}
3195
3196/**
Daniel Veillardc0826a72004-08-10 14:17:33 +00003197 * xmlSchemaValPredefTypeNodeNoNorm:
3198 * @type: the predefined type
3199 * @value: the value to check
3200 * @val: the return computed value
3201 * @node: the node containing the value
3202 *
3203 * Check that a value conforms to the lexical space of the predefined type.
3204 * if true a value is computed and returned in @val.
3205 * This one does apply any normalization to the value.
3206 *
3207 * Returns 0 if this validates, a positive error code number otherwise
3208 * and -1 in case of internal or API error.
3209 */
3210int
3211xmlSchemaValPredefTypeNodeNoNorm(xmlSchemaTypePtr type, const xmlChar *value,
3212 xmlSchemaValPtr *val, xmlNodePtr node) {
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00003213 return(xmlSchemaValAtomicType(type, value, val, node, 1,
3214 XML_SCHEMA_WHITESPACE_UNKNOWN, 1, 0, 1));
Daniel Veillardc0826a72004-08-10 14:17:33 +00003215}
3216
3217/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00003218 * xmlSchemaValidatePredefinedType:
3219 * @type: the predefined type
3220 * @value: the value to check
3221 * @val: the return computed value
3222 *
3223 * Check that a value conforms to the lexical space of the predefined type.
3224 * if true a value is computed and returned in @val.
3225 *
3226 * Returns 0 if this validates, a positive error code number otherwise
3227 * and -1 in case of internal or API error.
3228 */
3229int
3230xmlSchemaValidatePredefinedType(xmlSchemaTypePtr type, const xmlChar *value,
3231 xmlSchemaValPtr *val) {
3232 return(xmlSchemaValPredefTypeNode(type, value, val, NULL));
3233}
3234
3235/**
Daniel Veillard4255d502002-04-16 15:50:10 +00003236 * xmlSchemaCompareDecimals:
3237 * @x: a first decimal value
3238 * @y: a second decimal value
3239 *
3240 * Compare 2 decimals
3241 *
3242 * Returns -1 if x < y, 0 if x == y, 1 if x > y and -2 in case of error
3243 */
3244static int
3245xmlSchemaCompareDecimals(xmlSchemaValPtr x, xmlSchemaValPtr y)
3246{
3247 xmlSchemaValPtr swp;
William M. Brack273670f2005-03-11 15:55:14 +00003248 int order = 1, integx, integy, dlen;
3249 unsigned long hi, mi, lo;
Daniel Veillard4255d502002-04-16 15:50:10 +00003250
William M. Brack273670f2005-03-11 15:55:14 +00003251 /*
3252 * First test: If x is -ve and not zero
3253 */
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003254 if ((x->value.decimal.sign) &&
3255 ((x->value.decimal.lo != 0) ||
3256 (x->value.decimal.mi != 0) ||
3257 (x->value.decimal.hi != 0))) {
William M. Brack273670f2005-03-11 15:55:14 +00003258 /*
3259 * Then if y is -ve and not zero reverse the compare
3260 */
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003261 if ((y->value.decimal.sign) &&
3262 ((y->value.decimal.lo != 0) ||
3263 (y->value.decimal.mi != 0) ||
3264 (y->value.decimal.hi != 0)))
Daniel Veillard80b19092003-03-28 13:29:53 +00003265 order = -1;
William M. Brack273670f2005-03-11 15:55:14 +00003266 /*
3267 * Otherwise (y >= 0) we have the answer
3268 */
Daniel Veillard80b19092003-03-28 13:29:53 +00003269 else
3270 return (-1);
William M. Brack273670f2005-03-11 15:55:14 +00003271 /*
3272 * If x is not -ve and y is -ve we have the answer
3273 */
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003274 } else if ((y->value.decimal.sign) &&
3275 ((y->value.decimal.lo != 0) ||
3276 (y->value.decimal.mi != 0) ||
3277 (y->value.decimal.hi != 0))) {
Daniel Veillard4255d502002-04-16 15:50:10 +00003278 return (1);
Daniel Veillard80b19092003-03-28 13:29:53 +00003279 }
William M. Brack273670f2005-03-11 15:55:14 +00003280 /*
3281 * If it's not simply determined by a difference in sign,
3282 * then we need to compare the actual values of the two nums.
3283 * To do this, we start by looking at the integral parts.
3284 * If the number of integral digits differ, then we have our
3285 * answer.
3286 */
3287 integx = x->value.decimal.total - x->value.decimal.frac;
3288 integy = y->value.decimal.total - y->value.decimal.frac;
3289 if (integx > integy)
3290 return order;
3291 else if (integy > integx)
3292 return -order;
3293 /*
3294 * If the number of integral digits is the same for both numbers,
3295 * then things get a little more complicated. We need to "normalize"
3296 * the numbers in order to properly compare them. To do this, we
3297 * look at the total length of each number (length => number of
3298 * significant digits), and divide the "shorter" by 10 (decreasing
3299 * the length) until they are of equal length.
3300 */
3301 dlen = x->value.decimal.total - y->value.decimal.total;
3302 if (dlen < 0) { /* y has more digits than x */
3303 swp = x;
3304 hi = y->value.decimal.hi;
3305 mi = y->value.decimal.mi;
3306 lo = y->value.decimal.lo;
3307 dlen = -dlen;
3308 order = -order;
3309 } else { /* x has more digits than y */
3310 swp = y;
3311 hi = x->value.decimal.hi;
3312 mi = x->value.decimal.mi;
3313 lo = x->value.decimal.lo;
Daniel Veillard4255d502002-04-16 15:50:10 +00003314 }
William M. Brack273670f2005-03-11 15:55:14 +00003315 while (dlen > 8) { /* in effect, right shift by 10**8 */
3316 lo = mi;
3317 mi = hi;
3318 hi = 0;
3319 dlen -= 8;
Daniel Veillard4255d502002-04-16 15:50:10 +00003320 }
William M. Brack273670f2005-03-11 15:55:14 +00003321 while (dlen > 0) {
3322 unsigned long rem1, rem2;
3323 rem1 = (hi % 10) * 100000000L;
3324 hi = hi / 10;
3325 rem2 = (mi % 10) * 100000000L;
3326 mi = (mi + rem1) / 10;
3327 lo = (lo + rem2) / 10;
3328 dlen--;
3329 }
3330 if (hi > swp->value.decimal.hi) {
3331 return order;
3332 } else if (hi == swp->value.decimal.hi) {
3333 if (mi > swp->value.decimal.mi) {
3334 return order;
3335 } else if (mi == swp->value.decimal.mi) {
3336 if (lo > swp->value.decimal.lo) {
3337 return order;
3338 } else if (lo == swp->value.decimal.lo) {
3339 if (x->value.decimal.total == y->value.decimal.total) {
3340 return 0;
3341 } else {
3342 return order;
3343 }
3344 }
3345 }
3346 }
3347 return -order;
Daniel Veillard4255d502002-04-16 15:50:10 +00003348}
3349
3350/**
Daniel Veillard070803b2002-05-03 07:29:38 +00003351 * xmlSchemaCompareDurations:
3352 * @x: a first duration value
3353 * @y: a second duration value
3354 *
3355 * Compare 2 durations
3356 *
3357 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3358 * case of error
3359 */
3360static int
3361xmlSchemaCompareDurations(xmlSchemaValPtr x, xmlSchemaValPtr y)
3362{
3363 long carry, mon, day;
3364 double sec;
Daniel Veillard80b19092003-03-28 13:29:53 +00003365 int invert = 1;
3366 long xmon, xday, myear, minday, maxday;
Daniel Veillard070803b2002-05-03 07:29:38 +00003367 static const long dayRange [2][12] = {
3368 { 0, 28, 59, 89, 120, 150, 181, 212, 242, 273, 303, 334, },
3369 { 0, 31, 62, 92, 123, 153, 184, 215, 245, 276, 306, 337} };
3370
3371 if ((x == NULL) || (y == NULL))
Daniel Veillard5a872412002-05-22 06:40:27 +00003372 return -2;
Daniel Veillard070803b2002-05-03 07:29:38 +00003373
3374 /* months */
3375 mon = x->value.dur.mon - y->value.dur.mon;
3376
3377 /* seconds */
3378 sec = x->value.dur.sec - y->value.dur.sec;
3379 carry = (long)sec / SECS_PER_DAY;
3380 sec -= (double)(carry * SECS_PER_DAY);
3381
3382 /* days */
3383 day = x->value.dur.day - y->value.dur.day + carry;
3384
3385 /* easy test */
3386 if (mon == 0) {
3387 if (day == 0)
3388 if (sec == 0.0)
3389 return 0;
3390 else if (sec < 0.0)
3391 return -1;
3392 else
3393 return 1;
3394 else if (day < 0)
3395 return -1;
3396 else
3397 return 1;
3398 }
3399
3400 if (mon > 0) {
3401 if ((day >= 0) && (sec >= 0.0))
3402 return 1;
3403 else {
3404 xmon = mon;
3405 xday = -day;
3406 }
3407 } else if ((day <= 0) && (sec <= 0.0)) {
3408 return -1;
3409 } else {
Daniel Veillard80b19092003-03-28 13:29:53 +00003410 invert = -1;
Daniel Veillard070803b2002-05-03 07:29:38 +00003411 xmon = -mon;
3412 xday = day;
3413 }
3414
3415 myear = xmon / 12;
Daniel Veillard80b19092003-03-28 13:29:53 +00003416 if (myear == 0) {
3417 minday = 0;
3418 maxday = 0;
3419 } else {
3420 maxday = 366 * ((myear + 3) / 4) +
3421 365 * ((myear - 1) % 4);
3422 minday = maxday - 1;
3423 }
3424
Daniel Veillard070803b2002-05-03 07:29:38 +00003425 xmon = xmon % 12;
3426 minday += dayRange[0][xmon];
3427 maxday += dayRange[1][xmon];
3428
Daniel Veillard80b19092003-03-28 13:29:53 +00003429 if ((maxday == minday) && (maxday == xday))
3430 return(0); /* can this really happen ? */
Daniel Veillard070803b2002-05-03 07:29:38 +00003431 if (maxday < xday)
Daniel Veillard80b19092003-03-28 13:29:53 +00003432 return(-invert);
3433 if (minday > xday)
3434 return(invert);
Daniel Veillard070803b2002-05-03 07:29:38 +00003435
3436 /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00003437 return 2;
3438}
3439
3440/*
3441 * macros for adding date/times and durations
3442 */
3443#define FQUOTIENT(a,b) (floor(((double)a/(double)b)))
3444#define MODULO(a,b) (a - FQUOTIENT(a,b) * b)
3445#define FQUOTIENT_RANGE(a,low,high) (FQUOTIENT((a-low),(high-low)))
3446#define MODULO_RANGE(a,low,high) ((MODULO((a-low),(high-low)))+low)
3447
3448/**
Daniel Veillard669adfc2004-05-29 20:12:46 +00003449 * xmlSchemaDupVal:
3450 * @v: the #xmlSchemaValPtr value to duplicate
3451 *
3452 * Makes a copy of @v. The calling program is responsible for freeing
3453 * the returned value.
3454 *
3455 * returns a pointer to a duplicated #xmlSchemaValPtr or NULL if error.
3456 */
3457static xmlSchemaValPtr
3458xmlSchemaDupVal (xmlSchemaValPtr v)
3459{
3460 xmlSchemaValPtr ret = xmlSchemaNewValue(v->type);
3461 if (ret == NULL)
3462 return NULL;
3463
3464 memcpy(ret, v, sizeof(xmlSchemaVal));
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00003465 ret->next = NULL;
Daniel Veillard669adfc2004-05-29 20:12:46 +00003466 return ret;
3467}
3468
3469/**
Kasimier T. Buchcik285ebab2005-03-04 18:04:59 +00003470 * xmlSchemaCopyValue:
3471 * @val: the precomputed value to be copied
3472 *
3473 * Copies the precomputed value. This duplicates any string within.
3474 *
3475 * Returns the copy or NULL if a copy for a data-type is not implemented.
3476 */
3477xmlSchemaValPtr
3478xmlSchemaCopyValue(xmlSchemaValPtr val)
3479{
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00003480 xmlSchemaValPtr ret = NULL, prev = NULL, cur;
Kasimier T. Buchcik285ebab2005-03-04 18:04:59 +00003481
Kasimier T. Buchcik285ebab2005-03-04 18:04:59 +00003482 /*
3483 * Copy the string values.
3484 */
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00003485 while (val != NULL) {
3486 switch (val->type) {
3487 case XML_SCHEMAS_ANYTYPE:
3488 case XML_SCHEMAS_IDREFS:
3489 case XML_SCHEMAS_ENTITIES:
3490 case XML_SCHEMAS_NMTOKENS:
3491 xmlSchemaFreeValue(ret);
3492 return (NULL);
3493 case XML_SCHEMAS_ANYSIMPLETYPE:
3494 case XML_SCHEMAS_STRING:
3495 case XML_SCHEMAS_NORMSTRING:
3496 case XML_SCHEMAS_TOKEN:
3497 case XML_SCHEMAS_LANGUAGE:
3498 case XML_SCHEMAS_NAME:
3499 case XML_SCHEMAS_NCNAME:
3500 case XML_SCHEMAS_ID:
3501 case XML_SCHEMAS_IDREF:
3502 case XML_SCHEMAS_ENTITY:
3503 case XML_SCHEMAS_NMTOKEN:
3504 case XML_SCHEMAS_ANYURI:
3505 cur = xmlSchemaDupVal(val);
3506 if (val->value.str != NULL)
3507 cur->value.str = xmlStrdup(BAD_CAST val->value.str);
3508 break;
3509 case XML_SCHEMAS_QNAME:
3510 case XML_SCHEMAS_NOTATION:
3511 cur = xmlSchemaDupVal(val);
3512 if (val->value.qname.name != NULL)
3513 cur->value.qname.name =
Kasimier T. Buchcik285ebab2005-03-04 18:04:59 +00003514 xmlStrdup(BAD_CAST val->value.qname.name);
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00003515 if (val->value.qname.uri != NULL)
3516 cur->value.qname.uri =
Kasimier T. Buchcik285ebab2005-03-04 18:04:59 +00003517 xmlStrdup(BAD_CAST val->value.qname.uri);
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00003518 break;
3519 case XML_SCHEMAS_HEXBINARY:
3520 cur = xmlSchemaDupVal(val);
3521 if (val->value.hex.str != NULL)
3522 cur->value.hex.str = xmlStrdup(BAD_CAST val->value.hex.str);
3523 break;
3524 case XML_SCHEMAS_BASE64BINARY:
3525 cur = xmlSchemaDupVal(val);
3526 if (val->value.base64.str != NULL)
3527 cur->value.base64.str =
Kasimier T. Buchcik285ebab2005-03-04 18:04:59 +00003528 xmlStrdup(BAD_CAST val->value.base64.str);
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00003529 break;
3530 default:
3531 cur = xmlSchemaDupVal(val);
3532 break;
3533 }
3534 if (ret == NULL)
3535 ret = cur;
3536 else
3537 prev->next = cur;
3538 prev = cur;
3539 val = val->next;
Kasimier T. Buchcik285ebab2005-03-04 18:04:59 +00003540 }
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00003541 return (ret);
Kasimier T. Buchcik285ebab2005-03-04 18:04:59 +00003542}
3543
3544/**
Daniel Veillard5a872412002-05-22 06:40:27 +00003545 * _xmlSchemaDateAdd:
3546 * @dt: an #xmlSchemaValPtr
3547 * @dur: an #xmlSchemaValPtr of type #XS_DURATION
3548 *
3549 * Compute a new date/time from @dt and @dur. This function assumes @dt
3550 * is either #XML_SCHEMAS_DATETIME, #XML_SCHEMAS_DATE, #XML_SCHEMAS_GYEARMONTH,
Daniel Veillard669adfc2004-05-29 20:12:46 +00003551 * or #XML_SCHEMAS_GYEAR. The returned #xmlSchemaVal is the same type as
3552 * @dt. The calling program is responsible for freeing the returned value.
Daniel Veillard5a872412002-05-22 06:40:27 +00003553 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00003554 * Returns a pointer to a new #xmlSchemaVal or NULL if error.
Daniel Veillard5a872412002-05-22 06:40:27 +00003555 */
3556static xmlSchemaValPtr
3557_xmlSchemaDateAdd (xmlSchemaValPtr dt, xmlSchemaValPtr dur)
3558{
Daniel Veillard669adfc2004-05-29 20:12:46 +00003559 xmlSchemaValPtr ret, tmp;
Daniel Veillard5a872412002-05-22 06:40:27 +00003560 long carry, tempdays, temp;
3561 xmlSchemaValDatePtr r, d;
3562 xmlSchemaValDurationPtr u;
3563
3564 if ((dt == NULL) || (dur == NULL))
3565 return NULL;
3566
3567 ret = xmlSchemaNewValue(dt->type);
3568 if (ret == NULL)
3569 return NULL;
3570
Daniel Veillard669adfc2004-05-29 20:12:46 +00003571 /* make a copy so we don't alter the original value */
3572 tmp = xmlSchemaDupVal(dt);
3573 if (tmp == NULL) {
3574 xmlSchemaFreeValue(ret);
3575 return NULL;
3576 }
3577
Daniel Veillard5a872412002-05-22 06:40:27 +00003578 r = &(ret->value.date);
Daniel Veillard669adfc2004-05-29 20:12:46 +00003579 d = &(tmp->value.date);
Daniel Veillard5a872412002-05-22 06:40:27 +00003580 u = &(dur->value.dur);
3581
3582 /* normalization */
3583 if (d->mon == 0)
3584 d->mon = 1;
3585
3586 /* normalize for time zone offset */
3587 u->sec -= (d->tzo * 60);
3588 d->tzo = 0;
3589
3590 /* normalization */
3591 if (d->day == 0)
3592 d->day = 1;
3593
3594 /* month */
3595 carry = d->mon + u->mon;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003596 r->mon = (unsigned int) MODULO_RANGE(carry, 1, 13);
3597 carry = (long) FQUOTIENT_RANGE(carry, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00003598
3599 /* year (may be modified later) */
3600 r->year = d->year + carry;
3601 if (r->year == 0) {
3602 if (d->year > 0)
3603 r->year--;
3604 else
3605 r->year++;
3606 }
3607
3608 /* time zone */
3609 r->tzo = d->tzo;
3610 r->tz_flag = d->tz_flag;
3611
3612 /* seconds */
3613 r->sec = d->sec + u->sec;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003614 carry = (long) FQUOTIENT((long)r->sec, 60);
Daniel Veillard5a872412002-05-22 06:40:27 +00003615 if (r->sec != 0.0) {
3616 r->sec = MODULO(r->sec, 60.0);
3617 }
3618
3619 /* minute */
3620 carry += d->min;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003621 r->min = (unsigned int) MODULO(carry, 60);
3622 carry = (long) FQUOTIENT(carry, 60);
Daniel Veillard5a872412002-05-22 06:40:27 +00003623
3624 /* hours */
3625 carry += d->hour;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003626 r->hour = (unsigned int) MODULO(carry, 24);
3627 carry = (long)FQUOTIENT(carry, 24);
Daniel Veillard5a872412002-05-22 06:40:27 +00003628
3629 /*
3630 * days
3631 * Note we use tempdays because the temporary values may need more
3632 * than 5 bits
3633 */
3634 if ((VALID_YEAR(r->year)) && (VALID_MONTH(r->mon)) &&
3635 (d->day > MAX_DAYINMONTH(r->year, r->mon)))
3636 tempdays = MAX_DAYINMONTH(r->year, r->mon);
3637 else if (d->day < 1)
3638 tempdays = 1;
3639 else
3640 tempdays = d->day;
3641
3642 tempdays += u->day + carry;
3643
3644 while (1) {
3645 if (tempdays < 1) {
Daniel Veillardebe25d42004-03-25 09:35:49 +00003646 long tmon = (long) MODULO_RANGE(r->mon-1, 1, 13);
3647 long tyr = r->year + (long)FQUOTIENT_RANGE(r->mon-1, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00003648 if (tyr == 0)
3649 tyr--;
3650 tempdays += MAX_DAYINMONTH(tyr, tmon);
3651 carry = -1;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003652 } else if (tempdays > (long) MAX_DAYINMONTH(r->year, r->mon)) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003653 tempdays = tempdays - MAX_DAYINMONTH(r->year, r->mon);
3654 carry = 1;
3655 } else
3656 break;
3657
3658 temp = r->mon + carry;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003659 r->mon = (unsigned int) MODULO_RANGE(temp, 1, 13);
3660 r->year = r->year + (unsigned int) FQUOTIENT_RANGE(temp, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00003661 if (r->year == 0) {
3662 if (temp < 1)
3663 r->year--;
3664 else
3665 r->year++;
3666 }
3667 }
3668
3669 r->day = tempdays;
3670
3671 /*
3672 * adjust the date/time type to the date values
3673 */
3674 if (ret->type != XML_SCHEMAS_DATETIME) {
3675 if ((r->hour) || (r->min) || (r->sec))
3676 ret->type = XML_SCHEMAS_DATETIME;
3677 else if (ret->type != XML_SCHEMAS_DATE) {
3678 if ((r->mon != 1) && (r->day != 1))
3679 ret->type = XML_SCHEMAS_DATE;
3680 else if ((ret->type != XML_SCHEMAS_GYEARMONTH) && (r->mon != 1))
3681 ret->type = XML_SCHEMAS_GYEARMONTH;
3682 }
3683 }
3684
Daniel Veillard669adfc2004-05-29 20:12:46 +00003685 xmlSchemaFreeValue(tmp);
Daniel Veillard5a872412002-05-22 06:40:27 +00003686
Daniel Veillard5a872412002-05-22 06:40:27 +00003687 return ret;
3688}
3689
3690/**
3691 * xmlSchemaDateNormalize:
Daniel Veillard669adfc2004-05-29 20:12:46 +00003692 * @dt: an #xmlSchemaValPtr of a date/time type value.
3693 * @offset: number of seconds to adjust @dt by.
Daniel Veillard5a872412002-05-22 06:40:27 +00003694 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00003695 * Normalize @dt to GMT time. The @offset parameter is subtracted from
3696 * the return value is a time-zone offset is present on @dt.
Daniel Veillard5a872412002-05-22 06:40:27 +00003697 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00003698 * Returns a normalized copy of @dt or NULL if error.
Daniel Veillard5a872412002-05-22 06:40:27 +00003699 */
3700static xmlSchemaValPtr
3701xmlSchemaDateNormalize (xmlSchemaValPtr dt, double offset)
3702{
3703 xmlSchemaValPtr dur, ret;
3704
3705 if (dt == NULL)
3706 return NULL;
3707
3708 if (((dt->type != XML_SCHEMAS_TIME) &&
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00003709 (dt->type != XML_SCHEMAS_DATETIME) &&
3710 (dt->type != XML_SCHEMAS_DATE)) || (dt->value.date.tzo == 0))
Daniel Veillard5a872412002-05-22 06:40:27 +00003711 return xmlSchemaDupVal(dt);
3712
3713 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
3714 if (dur == NULL)
3715 return NULL;
3716
3717 dur->value.date.sec -= offset;
3718
3719 ret = _xmlSchemaDateAdd(dt, dur);
3720 if (ret == NULL)
3721 return NULL;
3722
3723 xmlSchemaFreeValue(dur);
3724
3725 /* ret->value.date.tzo = 0; */
3726 return ret;
3727}
3728
3729/**
3730 * _xmlSchemaDateCastYMToDays:
3731 * @dt: an #xmlSchemaValPtr
3732 *
3733 * Convert mon and year of @dt to total number of days. Take the
3734 * number of years since (or before) 1 AD and add the number of leap
3735 * years. This is a function because negative
3736 * years must be handled a little differently and there is no zero year.
3737 *
3738 * Returns number of days.
3739 */
3740static long
3741_xmlSchemaDateCastYMToDays (const xmlSchemaValPtr dt)
3742{
3743 long ret;
Daniel Veillard49e89632004-09-23 16:24:36 +00003744 int mon;
Daniel Veillard5a872412002-05-22 06:40:27 +00003745
Daniel Veillard49e89632004-09-23 16:24:36 +00003746 mon = dt->value.date.mon;
3747 if (mon <= 0) mon = 1; /* normalization */
3748
3749 if (dt->value.date.year <= 0)
Daniel Veillard5a872412002-05-22 06:40:27 +00003750 ret = (dt->value.date.year * 365) +
3751 (((dt->value.date.year+1)/4)-((dt->value.date.year+1)/100)+
3752 ((dt->value.date.year+1)/400)) +
Daniel Veillard49e89632004-09-23 16:24:36 +00003753 DAY_IN_YEAR(0, mon, dt->value.date.year);
Daniel Veillard5a872412002-05-22 06:40:27 +00003754 else
3755 ret = ((dt->value.date.year-1) * 365) +
3756 (((dt->value.date.year-1)/4)-((dt->value.date.year-1)/100)+
3757 ((dt->value.date.year-1)/400)) +
Daniel Veillard49e89632004-09-23 16:24:36 +00003758 DAY_IN_YEAR(0, mon, dt->value.date.year);
Daniel Veillard5a872412002-05-22 06:40:27 +00003759
3760 return ret;
3761}
3762
3763/**
3764 * TIME_TO_NUMBER:
3765 * @dt: an #xmlSchemaValPtr
3766 *
3767 * Calculates the number of seconds in the time portion of @dt.
3768 *
3769 * Returns seconds.
3770 */
3771#define TIME_TO_NUMBER(dt) \
3772 ((double)((dt->value.date.hour * SECS_PER_HOUR) + \
Daniel Veillardb3721c22003-03-31 11:22:25 +00003773 (dt->value.date.min * SECS_PER_MIN) + \
3774 (dt->value.date.tzo * SECS_PER_MIN)) + \
3775 dt->value.date.sec)
Daniel Veillard5a872412002-05-22 06:40:27 +00003776
3777/**
3778 * xmlSchemaCompareDates:
3779 * @x: a first date/time value
3780 * @y: a second date/time value
3781 *
3782 * Compare 2 date/times
3783 *
3784 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3785 * case of error
3786 */
3787static int
3788xmlSchemaCompareDates (xmlSchemaValPtr x, xmlSchemaValPtr y)
3789{
3790 unsigned char xmask, ymask, xor_mask, and_mask;
3791 xmlSchemaValPtr p1, p2, q1, q2;
3792 long p1d, p2d, q1d, q2d;
3793
3794 if ((x == NULL) || (y == NULL))
3795 return -2;
3796
3797 if (x->value.date.tz_flag) {
3798
3799 if (!y->value.date.tz_flag) {
3800 p1 = xmlSchemaDateNormalize(x, 0);
3801 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3802 /* normalize y + 14:00 */
3803 q1 = xmlSchemaDateNormalize(y, (14 * SECS_PER_HOUR));
3804
3805 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003806 if (p1d < q1d) {
3807 xmlSchemaFreeValue(p1);
3808 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003809 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003810 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003811 double sec;
3812
3813 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00003814 if (sec < 0.0) {
3815 xmlSchemaFreeValue(p1);
3816 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003817 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003818 } else {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003819 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003820 /* normalize y - 14:00 */
3821 q2 = xmlSchemaDateNormalize(y, -(14 * SECS_PER_HOUR));
3822 q2d = _xmlSchemaDateCastYMToDays(q2) + q2->value.date.day;
3823 if (p1d > q2d)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003824 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003825 else if (p1d == q2d) {
3826 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q2);
3827 if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003828 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003829 else
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003830 ret = 2; /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00003831 }
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003832 xmlSchemaFreeValue(p1);
3833 xmlSchemaFreeValue(q1);
3834 xmlSchemaFreeValue(q2);
3835 if (ret != 0)
3836 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003837 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00003838 } else {
3839 xmlSchemaFreeValue(p1);
3840 xmlSchemaFreeValue(q1);
3841 }
Daniel Veillard5a872412002-05-22 06:40:27 +00003842 }
3843 } else if (y->value.date.tz_flag) {
3844 q1 = xmlSchemaDateNormalize(y, 0);
3845 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
3846
3847 /* normalize x - 14:00 */
3848 p1 = xmlSchemaDateNormalize(x, -(14 * SECS_PER_HOUR));
3849 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3850
Daniel Veillardfdc91562002-07-01 21:52:03 +00003851 if (p1d < q1d) {
3852 xmlSchemaFreeValue(p1);
3853 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003854 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003855 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003856 double sec;
3857
3858 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00003859 if (sec < 0.0) {
3860 xmlSchemaFreeValue(p1);
3861 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003862 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003863 } else {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003864 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003865 /* normalize x + 14:00 */
3866 p2 = xmlSchemaDateNormalize(x, (14 * SECS_PER_HOUR));
3867 p2d = _xmlSchemaDateCastYMToDays(p2) + p2->value.date.day;
3868
Daniel Veillard6560a422003-03-27 21:25:38 +00003869 if (p2d > q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003870 ret = 1;
Daniel Veillard6560a422003-03-27 21:25:38 +00003871 } else if (p2d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003872 sec = TIME_TO_NUMBER(p2) - TIME_TO_NUMBER(q1);
3873 if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003874 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003875 else
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003876 ret = 2; /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00003877 }
Daniel Veillard6560a422003-03-27 21:25:38 +00003878 xmlSchemaFreeValue(p1);
3879 xmlSchemaFreeValue(q1);
3880 xmlSchemaFreeValue(p2);
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003881 if (ret != 0)
3882 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003883 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00003884 } else {
3885 xmlSchemaFreeValue(p1);
3886 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003887 }
3888 }
3889
3890 /*
3891 * if the same type then calculate the difference
3892 */
3893 if (x->type == y->type) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003894 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003895 q1 = xmlSchemaDateNormalize(y, 0);
3896 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
3897
3898 p1 = xmlSchemaDateNormalize(x, 0);
3899 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3900
Daniel Veillardfdc91562002-07-01 21:52:03 +00003901 if (p1d < q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003902 ret = -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003903 } else if (p1d > q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003904 ret = 1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003905 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00003906 double sec;
3907
3908 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
3909 if (sec < 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003910 ret = -1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003911 else if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003912 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003913
3914 }
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003915 xmlSchemaFreeValue(p1);
3916 xmlSchemaFreeValue(q1);
3917 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003918 }
3919
3920 switch (x->type) {
3921 case XML_SCHEMAS_DATETIME:
3922 xmask = 0xf;
3923 break;
3924 case XML_SCHEMAS_DATE:
3925 xmask = 0x7;
3926 break;
3927 case XML_SCHEMAS_GYEAR:
3928 xmask = 0x1;
3929 break;
3930 case XML_SCHEMAS_GMONTH:
3931 xmask = 0x2;
3932 break;
3933 case XML_SCHEMAS_GDAY:
3934 xmask = 0x3;
3935 break;
3936 case XML_SCHEMAS_GYEARMONTH:
3937 xmask = 0x3;
3938 break;
3939 case XML_SCHEMAS_GMONTHDAY:
3940 xmask = 0x6;
3941 break;
3942 case XML_SCHEMAS_TIME:
3943 xmask = 0x8;
3944 break;
3945 default:
3946 xmask = 0;
3947 break;
3948 }
3949
3950 switch (y->type) {
3951 case XML_SCHEMAS_DATETIME:
3952 ymask = 0xf;
3953 break;
3954 case XML_SCHEMAS_DATE:
3955 ymask = 0x7;
3956 break;
3957 case XML_SCHEMAS_GYEAR:
3958 ymask = 0x1;
3959 break;
3960 case XML_SCHEMAS_GMONTH:
3961 ymask = 0x2;
3962 break;
3963 case XML_SCHEMAS_GDAY:
3964 ymask = 0x3;
3965 break;
3966 case XML_SCHEMAS_GYEARMONTH:
3967 ymask = 0x3;
3968 break;
3969 case XML_SCHEMAS_GMONTHDAY:
3970 ymask = 0x6;
3971 break;
3972 case XML_SCHEMAS_TIME:
3973 ymask = 0x8;
3974 break;
3975 default:
3976 ymask = 0;
3977 break;
3978 }
3979
3980 xor_mask = xmask ^ ymask; /* mark type differences */
3981 and_mask = xmask & ymask; /* mark field specification */
3982
3983 /* year */
3984 if (xor_mask & 1)
3985 return 2; /* indeterminate */
3986 else if (and_mask & 1) {
3987 if (x->value.date.year < y->value.date.year)
3988 return -1;
3989 else if (x->value.date.year > y->value.date.year)
3990 return 1;
3991 }
3992
3993 /* month */
3994 if (xor_mask & 2)
3995 return 2; /* indeterminate */
3996 else if (and_mask & 2) {
3997 if (x->value.date.mon < y->value.date.mon)
3998 return -1;
3999 else if (x->value.date.mon > y->value.date.mon)
4000 return 1;
4001 }
4002
4003 /* day */
4004 if (xor_mask & 4)
4005 return 2; /* indeterminate */
4006 else if (and_mask & 4) {
4007 if (x->value.date.day < y->value.date.day)
4008 return -1;
4009 else if (x->value.date.day > y->value.date.day)
4010 return 1;
4011 }
4012
4013 /* time */
4014 if (xor_mask & 8)
4015 return 2; /* indeterminate */
4016 else if (and_mask & 8) {
4017 if (x->value.date.hour < y->value.date.hour)
4018 return -1;
4019 else if (x->value.date.hour > y->value.date.hour)
4020 return 1;
4021 else if (x->value.date.min < y->value.date.min)
4022 return -1;
4023 else if (x->value.date.min > y->value.date.min)
4024 return 1;
4025 else if (x->value.date.sec < y->value.date.sec)
4026 return -1;
4027 else if (x->value.date.sec > y->value.date.sec)
4028 return 1;
4029 }
4030
Daniel Veillard070803b2002-05-03 07:29:38 +00004031 return 0;
4032}
4033
4034/**
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004035 * xmlSchemaComparePreserveReplaceStrings:
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004036 * @x: a first string value
4037 * @y: a second string value
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004038 * @invert: inverts the result if x < y or x > y.
4039 *
4040 * Compare 2 string for their normalized values.
4041 * @x is a string with whitespace of "preserve", @y is
4042 * a string with a whitespace of "replace". I.e. @x could
4043 * be an "xsd:string" and @y an "xsd:normalizedString".
4044 *
4045 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
4046 * case of error
4047 */
4048static int
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004049xmlSchemaComparePreserveReplaceStrings(const xmlChar *x,
4050 const xmlChar *y,
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004051 int invert)
4052{
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004053 int tmp;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004054
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004055 while ((*x != 0) && (*y != 0)) {
4056 if (IS_WSP_REPLACE_CH(*y)) {
4057 if (! IS_WSP_SPACE_CH(*x)) {
4058 if ((*x - 0x20) < 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004059 if (invert)
4060 return(1);
4061 else
4062 return(-1);
4063 } else {
4064 if (invert)
4065 return(-1);
4066 else
4067 return(1);
4068 }
4069 }
4070 } else {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004071 tmp = *x - *y;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004072 if (tmp < 0) {
4073 if (invert)
4074 return(1);
4075 else
4076 return(-1);
4077 }
4078 if (tmp > 0) {
4079 if (invert)
4080 return(-1);
4081 else
4082 return(1);
4083 }
4084 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004085 x++;
4086 y++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004087 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004088 if (*x != 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004089 if (invert)
4090 return(-1);
4091 else
4092 return(1);
4093 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004094 if (*y != 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004095 if (invert)
4096 return(1);
4097 else
4098 return(-1);
4099 }
4100 return(0);
4101}
4102
4103/**
4104 * xmlSchemaComparePreserveCollapseStrings:
4105 * @x: a first string value
4106 * @y: a second string value
4107 *
4108 * Compare 2 string for their normalized values.
4109 * @x is a string with whitespace of "preserve", @y is
4110 * a string with a whitespace of "collapse". I.e. @x could
4111 * be an "xsd:string" and @y an "xsd:normalizedString".
4112 *
4113 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
4114 * case of error
4115 */
4116static int
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004117xmlSchemaComparePreserveCollapseStrings(const xmlChar *x,
4118 const xmlChar *y,
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004119 int invert)
4120{
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004121 int tmp;
4122
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004123 /*
4124 * Skip leading blank chars of the collapsed string.
4125 */
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004126 while IS_WSP_BLANK_CH(*y)
4127 y++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004128
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004129 while ((*x != 0) && (*y != 0)) {
4130 if IS_WSP_BLANK_CH(*y) {
4131 if (! IS_WSP_SPACE_CH(*x)) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004132 /*
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004133 * The yv character would have been replaced to 0x20.
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004134 */
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004135 if ((*x - 0x20) < 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004136 if (invert)
4137 return(1);
4138 else
4139 return(-1);
4140 } else {
4141 if (invert)
4142 return(-1);
4143 else
4144 return(1);
4145 }
4146 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004147 x++;
4148 y++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004149 /*
4150 * Skip contiguous blank chars of the collapsed string.
4151 */
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004152 while IS_WSP_BLANK_CH(*y)
4153 y++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004154 } else {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004155 tmp = *x++ - *y++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004156 if (tmp < 0) {
4157 if (invert)
4158 return(1);
4159 else
4160 return(-1);
4161 }
4162 if (tmp > 0) {
4163 if (invert)
4164 return(-1);
4165 else
4166 return(1);
4167 }
4168 }
4169 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004170 if (*x != 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004171 if (invert)
4172 return(-1);
4173 else
4174 return(1);
4175 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004176 if (*y != 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004177 /*
4178 * Skip trailing blank chars of the collapsed string.
4179 */
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004180 while IS_WSP_BLANK_CH(*y)
4181 y++;
4182 if (*y != 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004183 if (invert)
4184 return(1);
4185 else
4186 return(-1);
4187 }
4188 }
4189 return(0);
4190}
4191
4192/**
4193 * xmlSchemaComparePreserveCollapseStrings:
4194 * @x: a first string value
4195 * @y: a second string value
4196 *
4197 * Compare 2 string for their normalized values.
4198 * @x is a string with whitespace of "preserve", @y is
4199 * a string with a whitespace of "collapse". I.e. @x could
4200 * be an "xsd:string" and @y an "xsd:normalizedString".
4201 *
4202 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
4203 * case of error
4204 */
4205static int
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004206xmlSchemaCompareReplaceCollapseStrings(const xmlChar *x,
4207 const xmlChar *y,
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004208 int invert)
4209{
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004210 int tmp;
4211
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004212 /*
4213 * Skip leading blank chars of the collapsed string.
4214 */
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004215 while IS_WSP_BLANK_CH(*y)
4216 y++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004217
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004218 while ((*x != 0) && (*y != 0)) {
4219 if IS_WSP_BLANK_CH(*y) {
4220 if (! IS_WSP_BLANK_CH(*x)) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004221 /*
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004222 * The yv character would have been replaced to 0x20.
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004223 */
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004224 if ((*x - 0x20) < 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004225 if (invert)
4226 return(1);
4227 else
4228 return(-1);
4229 } else {
4230 if (invert)
4231 return(-1);
4232 else
4233 return(1);
4234 }
4235 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004236 x++;
4237 y++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004238 /*
4239 * Skip contiguous blank chars of the collapsed string.
4240 */
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004241 while IS_WSP_BLANK_CH(*y)
4242 y++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004243 } else {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004244 if IS_WSP_BLANK_CH(*x) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004245 /*
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004246 * The xv character would have been replaced to 0x20.
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004247 */
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004248 if ((0x20 - *y) < 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004249 if (invert)
4250 return(1);
4251 else
4252 return(-1);
4253 } else {
4254 if (invert)
4255 return(-1);
4256 else
4257 return(1);
4258 }
4259 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004260 tmp = *x++ - *y++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004261 if (tmp < 0)
4262 return(-1);
4263 if (tmp > 0)
4264 return(1);
4265 }
4266 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004267 if (*x != 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004268 if (invert)
4269 return(-1);
4270 else
4271 return(1);
4272 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004273 if (*y != 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004274 /*
4275 * Skip trailing blank chars of the collapsed string.
4276 */
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004277 while IS_WSP_BLANK_CH(*y)
4278 y++;
4279 if (*y != 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004280 if (invert)
4281 return(1);
4282 else
4283 return(-1);
4284 }
4285 }
4286 return(0);
4287}
4288
4289
4290/**
4291 * xmlSchemaCompareReplacedStrings:
4292 * @x: a first string value
4293 * @y: a second string value
4294 *
4295 * Compare 2 string for their normalized values.
4296 *
4297 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
4298 * case of error
4299 */
4300static int
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004301xmlSchemaCompareReplacedStrings(const xmlChar *x,
4302 const xmlChar *y)
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004303{
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004304 int tmp;
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004305
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004306 while ((*x != 0) && (*y != 0)) {
4307 if IS_WSP_BLANK_CH(*y) {
4308 if (! IS_WSP_BLANK_CH(*x)) {
4309 if ((*x - 0x20) < 0)
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004310 return(-1);
4311 else
4312 return(1);
4313 }
4314 } else {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004315 if IS_WSP_BLANK_CH(*x) {
4316 if ((0x20 - *y) < 0)
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004317 return(-1);
4318 else
4319 return(1);
4320 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004321 tmp = *x - *y;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004322 if (tmp < 0)
4323 return(-1);
4324 if (tmp > 0)
4325 return(1);
4326 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004327 x++;
4328 y++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004329 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004330 if (*x != 0)
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004331 return(1);
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004332 if (*y != 0)
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004333 return(-1);
4334 return(0);
4335}
4336
4337/**
Daniel Veillardc4c21552003-03-29 10:53:38 +00004338 * xmlSchemaCompareNormStrings:
4339 * @x: a first string value
4340 * @y: a second string value
4341 *
4342 * Compare 2 string for their normalized values.
4343 *
4344 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
4345 * case of error
4346 */
4347static int
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004348xmlSchemaCompareNormStrings(const xmlChar *x,
4349 const xmlChar *y) {
Daniel Veillardc4c21552003-03-29 10:53:38 +00004350 int tmp;
Daniel Veillardc4c21552003-03-29 10:53:38 +00004351
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004352 while (IS_BLANK_CH(*x)) x++;
4353 while (IS_BLANK_CH(*y)) y++;
4354 while ((*x != 0) && (*y != 0)) {
4355 if (IS_BLANK_CH(*x)) {
4356 if (!IS_BLANK_CH(*y)) {
4357 tmp = *x - *y;
Daniel Veillardc4c21552003-03-29 10:53:38 +00004358 return(tmp);
4359 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004360 while (IS_BLANK_CH(*x)) x++;
4361 while (IS_BLANK_CH(*y)) y++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00004362 } else {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004363 tmp = *x++ - *y++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00004364 if (tmp < 0)
4365 return(-1);
4366 if (tmp > 0)
4367 return(1);
4368 }
4369 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004370 if (*x != 0) {
4371 while (IS_BLANK_CH(*x)) x++;
4372 if (*x != 0)
Daniel Veillardc4c21552003-03-29 10:53:38 +00004373 return(1);
4374 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004375 if (*y != 0) {
4376 while (IS_BLANK_CH(*y)) y++;
4377 if (*y != 0)
Daniel Veillardc4c21552003-03-29 10:53:38 +00004378 return(-1);
4379 }
4380 return(0);
4381}
4382
4383/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00004384 * xmlSchemaCompareFloats:
4385 * @x: a first float or double value
4386 * @y: a second float or double value
4387 *
4388 * Compare 2 values
4389 *
4390 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
4391 * case of error
4392 */
4393static int
4394xmlSchemaCompareFloats(xmlSchemaValPtr x, xmlSchemaValPtr y) {
4395 double d1, d2;
4396
4397 if ((x == NULL) || (y == NULL))
4398 return(-2);
4399
4400 /*
4401 * Cast everything to doubles.
4402 */
4403 if (x->type == XML_SCHEMAS_DOUBLE)
4404 d1 = x->value.d;
4405 else if (x->type == XML_SCHEMAS_FLOAT)
4406 d1 = x->value.f;
4407 else
4408 return(-2);
4409
4410 if (y->type == XML_SCHEMAS_DOUBLE)
4411 d2 = y->value.d;
4412 else if (y->type == XML_SCHEMAS_FLOAT)
4413 d2 = y->value.f;
4414 else
4415 return(-2);
4416
4417 /*
4418 * Check for special cases.
4419 */
4420 if (xmlXPathIsNaN(d1)) {
4421 if (xmlXPathIsNaN(d2))
4422 return(0);
4423 return(1);
4424 }
4425 if (xmlXPathIsNaN(d2))
4426 return(-1);
4427 if (d1 == xmlXPathPINF) {
4428 if (d2 == xmlXPathPINF)
4429 return(0);
4430 return(1);
4431 }
4432 if (d2 == xmlXPathPINF)
4433 return(-1);
4434 if (d1 == xmlXPathNINF) {
4435 if (d2 == xmlXPathNINF)
4436 return(0);
4437 return(-1);
4438 }
4439 if (d2 == xmlXPathNINF)
4440 return(1);
4441
4442 /*
4443 * basic tests, the last one we should have equality, but
4444 * portability is more important than speed and handling
4445 * NaN or Inf in a portable way is always a challenge, so ...
4446 */
4447 if (d1 < d2)
4448 return(-1);
4449 if (d1 > d2)
4450 return(1);
4451 if (d1 == d2)
4452 return(0);
4453 return(2);
4454}
4455
4456/**
Daniel Veillard4255d502002-04-16 15:50:10 +00004457 * xmlSchemaCompareValues:
4458 * @x: a first value
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004459 * @xvalue: the first value as a string (optional)
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004460 * @xwtsp: the whitespace type
Daniel Veillard4255d502002-04-16 15:50:10 +00004461 * @y: a second value
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004462 * @xvalue: the second value as a string (optional)
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004463 * @ywtsp: the whitespace type
Daniel Veillard4255d502002-04-16 15:50:10 +00004464 *
4465 * Compare 2 values
4466 *
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00004467 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, 3 if not
4468 * comparable and -2 in case of error
Daniel Veillard4255d502002-04-16 15:50:10 +00004469 */
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004470static int
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004471xmlSchemaCompareValuesInternal(xmlSchemaValType xtype,
4472 xmlSchemaValPtr x,
4473 const xmlChar *xvalue,
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004474 xmlSchemaWhitespaceValueType xws,
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004475 xmlSchemaValType ytype,
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004476 xmlSchemaValPtr y,
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004477 const xmlChar *yvalue,
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004478 xmlSchemaWhitespaceValueType yws)
4479{
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004480 switch (xtype) {
Daniel Veillard80b19092003-03-28 13:29:53 +00004481 case XML_SCHEMAS_UNKNOWN:
William M. Brack2f2a6632004-08-20 23:09:47 +00004482 case XML_SCHEMAS_ANYTYPE:
Daniel Veillard80b19092003-03-28 13:29:53 +00004483 return(-2);
4484 case XML_SCHEMAS_INTEGER:
4485 case XML_SCHEMAS_NPINTEGER:
4486 case XML_SCHEMAS_NINTEGER:
4487 case XML_SCHEMAS_NNINTEGER:
4488 case XML_SCHEMAS_PINTEGER:
4489 case XML_SCHEMAS_INT:
4490 case XML_SCHEMAS_UINT:
4491 case XML_SCHEMAS_LONG:
4492 case XML_SCHEMAS_ULONG:
4493 case XML_SCHEMAS_SHORT:
4494 case XML_SCHEMAS_USHORT:
4495 case XML_SCHEMAS_BYTE:
4496 case XML_SCHEMAS_UBYTE:
Daniel Veillard4255d502002-04-16 15:50:10 +00004497 case XML_SCHEMAS_DECIMAL:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004498 if ((x == NULL) || (y == NULL))
4499 return(-2);
4500 if (ytype == xtype)
Daniel Veillard80b19092003-03-28 13:29:53 +00004501 return(xmlSchemaCompareDecimals(x, y));
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004502 if ((ytype == XML_SCHEMAS_DECIMAL) ||
4503 (ytype == XML_SCHEMAS_INTEGER) ||
4504 (ytype == XML_SCHEMAS_NPINTEGER) ||
4505 (ytype == XML_SCHEMAS_NINTEGER) ||
4506 (ytype == XML_SCHEMAS_NNINTEGER) ||
4507 (ytype == XML_SCHEMAS_PINTEGER) ||
4508 (ytype == XML_SCHEMAS_INT) ||
4509 (ytype == XML_SCHEMAS_UINT) ||
4510 (ytype == XML_SCHEMAS_LONG) ||
4511 (ytype == XML_SCHEMAS_ULONG) ||
4512 (ytype == XML_SCHEMAS_SHORT) ||
4513 (ytype == XML_SCHEMAS_USHORT) ||
4514 (ytype == XML_SCHEMAS_BYTE) ||
4515 (ytype == XML_SCHEMAS_UBYTE))
Daniel Veillard4255d502002-04-16 15:50:10 +00004516 return(xmlSchemaCompareDecimals(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00004517 return(-2);
Daniel Veillard070803b2002-05-03 07:29:38 +00004518 case XML_SCHEMAS_DURATION:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004519 if ((x == NULL) || (y == NULL))
4520 return(-2);
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004521 if (ytype == XML_SCHEMAS_DURATION)
Daniel Veillard070803b2002-05-03 07:29:38 +00004522 return(xmlSchemaCompareDurations(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00004523 return(-2);
4524 case XML_SCHEMAS_TIME:
4525 case XML_SCHEMAS_GDAY:
4526 case XML_SCHEMAS_GMONTH:
4527 case XML_SCHEMAS_GMONTHDAY:
4528 case XML_SCHEMAS_GYEAR:
4529 case XML_SCHEMAS_GYEARMONTH:
4530 case XML_SCHEMAS_DATE:
4531 case XML_SCHEMAS_DATETIME:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004532 if ((x == NULL) || (y == NULL))
4533 return(-2);
4534 if ((ytype == XML_SCHEMAS_DATETIME) ||
4535 (ytype == XML_SCHEMAS_TIME) ||
4536 (ytype == XML_SCHEMAS_GDAY) ||
4537 (ytype == XML_SCHEMAS_GMONTH) ||
4538 (ytype == XML_SCHEMAS_GMONTHDAY) ||
4539 (ytype == XML_SCHEMAS_GYEAR) ||
4540 (ytype == XML_SCHEMAS_DATE) ||
4541 (ytype == XML_SCHEMAS_GYEARMONTH))
Daniel Veillard5a872412002-05-22 06:40:27 +00004542 return (xmlSchemaCompareDates(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00004543 return (-2);
Kasimier T. Buchcik2ee855d2005-03-07 11:14:14 +00004544 /*
4545 * Note that we will support comparison of string types against
4546 * anySimpleType as well.
4547 */
4548 case XML_SCHEMAS_ANYSIMPLETYPE:
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004549 case XML_SCHEMAS_STRING:
4550 case XML_SCHEMAS_NORMSTRING:
Daniel Veillard80b19092003-03-28 13:29:53 +00004551 case XML_SCHEMAS_TOKEN:
4552 case XML_SCHEMAS_LANGUAGE:
4553 case XML_SCHEMAS_NMTOKEN:
Daniel Veillard80b19092003-03-28 13:29:53 +00004554 case XML_SCHEMAS_NAME:
Daniel Veillard80b19092003-03-28 13:29:53 +00004555 case XML_SCHEMAS_NCNAME:
4556 case XML_SCHEMAS_ID:
4557 case XML_SCHEMAS_IDREF:
Daniel Veillard80b19092003-03-28 13:29:53 +00004558 case XML_SCHEMAS_ENTITY:
Daniel Veillard80b19092003-03-28 13:29:53 +00004559 case XML_SCHEMAS_ANYURI:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004560 {
4561 const xmlChar *xv, *yv;
4562
4563 if (x == NULL)
4564 xv = xvalue;
4565 else
4566 xv = x->value.str;
4567 if (y == NULL)
4568 yv = yvalue;
4569 else
4570 yv = y->value.str;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004571 /*
4572 * TODO: Compare those against QName.
4573 */
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004574 if (ytype == XML_SCHEMAS_QNAME) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004575 TODO
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004576 if (y == NULL)
4577 return(-2);
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004578 return (-2);
4579 }
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004580 if ((ytype == XML_SCHEMAS_ANYSIMPLETYPE) ||
4581 (ytype == XML_SCHEMAS_STRING) ||
4582 (ytype == XML_SCHEMAS_NORMSTRING) ||
4583 (ytype == XML_SCHEMAS_TOKEN) ||
4584 (ytype == XML_SCHEMAS_LANGUAGE) ||
4585 (ytype == XML_SCHEMAS_NMTOKEN) ||
4586 (ytype == XML_SCHEMAS_NAME) ||
4587 (ytype == XML_SCHEMAS_NCNAME) ||
4588 (ytype == XML_SCHEMAS_ID) ||
4589 (ytype == XML_SCHEMAS_IDREF) ||
4590 (ytype == XML_SCHEMAS_ENTITY) ||
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004591 (ytype == XML_SCHEMAS_ANYURI)) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004592
4593 if (xws == XML_SCHEMA_WHITESPACE_PRESERVE) {
4594
4595 if (yws == XML_SCHEMA_WHITESPACE_PRESERVE) {
4596 /* TODO: What about x < y or x > y. */
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004597 if (xmlStrEqual(xv, yv))
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004598 return (0);
4599 else
4600 return (2);
4601 } else if (yws == XML_SCHEMA_WHITESPACE_REPLACE)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004602 return (xmlSchemaComparePreserveReplaceStrings(xv, yv, 0));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004603 else if (yws == XML_SCHEMA_WHITESPACE_COLLAPSE)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004604 return (xmlSchemaComparePreserveCollapseStrings(xv, yv, 0));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004605
4606 } else if (xws == XML_SCHEMA_WHITESPACE_REPLACE) {
4607
4608 if (yws == XML_SCHEMA_WHITESPACE_PRESERVE)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004609 return (xmlSchemaComparePreserveReplaceStrings(yv, xv, 1));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004610 if (yws == XML_SCHEMA_WHITESPACE_REPLACE)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004611 return (xmlSchemaCompareReplacedStrings(xv, yv));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004612 if (yws == XML_SCHEMA_WHITESPACE_COLLAPSE)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004613 return (xmlSchemaCompareReplaceCollapseStrings(xv, yv, 0));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004614
4615 } else if (xws == XML_SCHEMA_WHITESPACE_COLLAPSE) {
4616
4617 if (yws == XML_SCHEMA_WHITESPACE_PRESERVE)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004618 return (xmlSchemaComparePreserveCollapseStrings(yv, xv, 1));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004619 if (yws == XML_SCHEMA_WHITESPACE_REPLACE)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004620 return (xmlSchemaCompareReplaceCollapseStrings(yv, xv, 1));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004621 if (yws == XML_SCHEMA_WHITESPACE_COLLAPSE)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004622 return (xmlSchemaCompareNormStrings(xv, yv));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004623 } else
4624 return (-2);
4625
4626 }
Daniel Veillardc4c21552003-03-29 10:53:38 +00004627 return (-2);
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004628 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004629 case XML_SCHEMAS_QNAME:
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00004630 case XML_SCHEMAS_NOTATION:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004631 if ((x == NULL) || (y == NULL))
4632 return(-2);
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00004633 if ((ytype == XML_SCHEMAS_QNAME) ||
4634 (ytype == XML_SCHEMAS_NOTATION)) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004635 if ((xmlStrEqual(x->value.qname.name, y->value.qname.name)) &&
4636 (xmlStrEqual(x->value.qname.uri, y->value.qname.uri)))
4637 return(0);
4638 return(2);
4639 }
4640 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00004641 case XML_SCHEMAS_FLOAT:
4642 case XML_SCHEMAS_DOUBLE:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004643 if ((x == NULL) || (y == NULL))
4644 return(-2);
4645 if ((ytype == XML_SCHEMAS_FLOAT) ||
4646 (ytype == XML_SCHEMAS_DOUBLE))
Daniel Veillardb6c7f412003-03-29 16:41:55 +00004647 return (xmlSchemaCompareFloats(x, y));
4648 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00004649 case XML_SCHEMAS_BOOLEAN:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004650 if ((x == NULL) || (y == NULL))
4651 return(-2);
4652 if (ytype == XML_SCHEMAS_BOOLEAN) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00004653 if (x->value.b == y->value.b)
4654 return(0);
4655 if (x->value.b == 0)
4656 return(-1);
4657 return(1);
4658 }
4659 return (-2);
Daniel Veillard560c2a42003-07-06 21:13:49 +00004660 case XML_SCHEMAS_HEXBINARY:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004661 if ((x == NULL) || (y == NULL))
4662 return(-2);
4663 if (ytype == XML_SCHEMAS_HEXBINARY) {
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004664 if (x->value.hex.total == y->value.hex.total) {
4665 int ret = xmlStrcmp(x->value.hex.str, y->value.hex.str);
4666 if (ret > 0)
4667 return(1);
4668 else if (ret == 0)
4669 return(0);
4670 }
4671 else if (x->value.hex.total > y->value.hex.total)
4672 return(1);
4673
4674 return(-1);
4675 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00004676 return (-2);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00004677 case XML_SCHEMAS_BASE64BINARY:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004678 if ((x == NULL) || (y == NULL))
4679 return(-2);
4680 if (ytype == XML_SCHEMAS_BASE64BINARY) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00004681 if (x->value.base64.total == y->value.base64.total) {
4682 int ret = xmlStrcmp(x->value.base64.str,
4683 y->value.base64.str);
4684 if (ret > 0)
4685 return(1);
4686 else if (ret == 0)
4687 return(0);
Daniel Veillardd369b132005-07-14 15:54:44 +00004688 else
4689 return(-1);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00004690 }
4691 else if (x->value.base64.total > y->value.base64.total)
4692 return(1);
4693 else
4694 return(-1);
4695 }
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004696 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00004697 case XML_SCHEMAS_IDREFS:
4698 case XML_SCHEMAS_ENTITIES:
4699 case XML_SCHEMAS_NMTOKENS:
4700 TODO
4701 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00004702 }
Daniel Veillard5a872412002-05-22 06:40:27 +00004703 return -2;
Daniel Veillard4255d502002-04-16 15:50:10 +00004704}
4705
4706/**
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004707 * xmlSchemaCompareValues:
4708 * @x: a first value
4709 * @y: a second value
4710 *
4711 * Compare 2 values
4712 *
4713 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
4714 * case of error
4715 */
4716int
4717xmlSchemaCompareValues(xmlSchemaValPtr x, xmlSchemaValPtr y) {
4718 xmlSchemaWhitespaceValueType xws, yws;
4719
Daniel Veillard5e094142005-02-18 19:36:12 +00004720 if ((x == NULL) || (y == NULL))
4721 return(-2);
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004722 if (x->type == XML_SCHEMAS_STRING)
4723 xws = XML_SCHEMA_WHITESPACE_PRESERVE;
4724 else if (x->type == XML_SCHEMAS_NORMSTRING)
4725 xws = XML_SCHEMA_WHITESPACE_REPLACE;
4726 else
4727 xws = XML_SCHEMA_WHITESPACE_COLLAPSE;
4728
4729 if (y->type == XML_SCHEMAS_STRING)
4730 yws = XML_SCHEMA_WHITESPACE_PRESERVE;
4731 else if (x->type == XML_SCHEMAS_NORMSTRING)
4732 yws = XML_SCHEMA_WHITESPACE_REPLACE;
4733 else
4734 yws = XML_SCHEMA_WHITESPACE_COLLAPSE;
4735
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004736 return(xmlSchemaCompareValuesInternal(x->type, x, NULL, xws, y->type,
4737 y, NULL, yws));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004738}
4739
4740/**
4741 * xmlSchemaCompareValuesWhtsp:
4742 * @x: a first value
4743 * @xws: the whitespace value of x
4744 * @y: a second value
4745 * @yws: the whitespace value of y
4746 *
4747 * Compare 2 values
4748 *
4749 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
4750 * case of error
4751 */
4752int
4753xmlSchemaCompareValuesWhtsp(xmlSchemaValPtr x,
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004754 xmlSchemaWhitespaceValueType xws,
4755 xmlSchemaValPtr y,
4756 xmlSchemaWhitespaceValueType yws)
4757{
Kasimier T. Buchcik9dbb0ce2005-03-16 16:39:23 +00004758 if ((x == NULL) || (y == NULL))
4759 return(-2);
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004760 return(xmlSchemaCompareValuesInternal(x->type, x, NULL, xws, y->type,
4761 y, NULL, yws));
4762}
4763
4764/**
4765 * xmlSchemaCompareValuesWhtspExt:
4766 * @x: a first value
4767 * @xws: the whitespace value of x
4768 * @y: a second value
4769 * @yws: the whitespace value of y
4770 *
4771 * Compare 2 values
4772 *
4773 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
4774 * case of error
4775 */
4776static int
4777xmlSchemaCompareValuesWhtspExt(xmlSchemaValType xtype,
4778 xmlSchemaValPtr x,
4779 const xmlChar *xvalue,
4780 xmlSchemaWhitespaceValueType xws,
4781 xmlSchemaValType ytype,
4782 xmlSchemaValPtr y,
4783 const xmlChar *yvalue,
4784 xmlSchemaWhitespaceValueType yws)
4785{
4786 return(xmlSchemaCompareValuesInternal(xtype, x, xvalue, xws, ytype, y,
4787 yvalue, yws));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004788}
4789
4790/**
Daniel Veillardc4c21552003-03-29 10:53:38 +00004791 * xmlSchemaNormLen:
4792 * @value: a string
4793 *
4794 * Computes the UTF8 length of the normalized value of the string
4795 *
4796 * Returns the length or -1 in case of error.
4797 */
4798static int
4799xmlSchemaNormLen(const xmlChar *value) {
4800 const xmlChar *utf;
4801 int ret = 0;
4802
4803 if (value == NULL)
4804 return(-1);
4805 utf = value;
William M. Brack76e95df2003-10-18 16:20:14 +00004806 while (IS_BLANK_CH(*utf)) utf++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00004807 while (*utf != 0) {
4808 if (utf[0] & 0x80) {
4809 if ((utf[1] & 0xc0) != 0x80)
4810 return(-1);
4811 if ((utf[0] & 0xe0) == 0xe0) {
4812 if ((utf[2] & 0xc0) != 0x80)
4813 return(-1);
4814 if ((utf[0] & 0xf0) == 0xf0) {
4815 if ((utf[0] & 0xf8) != 0xf0 || (utf[3] & 0xc0) != 0x80)
4816 return(-1);
4817 utf += 4;
4818 } else {
4819 utf += 3;
4820 }
4821 } else {
4822 utf += 2;
4823 }
William M. Brack76e95df2003-10-18 16:20:14 +00004824 } else if (IS_BLANK_CH(*utf)) {
4825 while (IS_BLANK_CH(*utf)) utf++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00004826 if (*utf == 0)
4827 break;
4828 } else {
4829 utf++;
4830 }
4831 ret++;
4832 }
4833 return(ret);
4834}
4835
Daniel Veillard6927b102004-10-27 17:29:04 +00004836/**
4837 * xmlSchemaGetFacetValueAsULong:
4838 * @facet: an schemas type facet
4839 *
4840 * Extract the value of a facet
4841 *
4842 * Returns the value as a long
4843 */
Daniel Veillardc0826a72004-08-10 14:17:33 +00004844unsigned long
4845xmlSchemaGetFacetValueAsULong(xmlSchemaFacetPtr facet)
4846{
4847 /*
4848 * TODO: Check if this is a decimal.
4849 */
William M. Brack094dd862004-11-14 14:28:34 +00004850 if (facet == NULL)
4851 return 0;
Daniel Veillardc0826a72004-08-10 14:17:33 +00004852 return ((unsigned long) facet->val->value.decimal.lo);
4853}
4854
Daniel Veillardc4c21552003-03-29 10:53:38 +00004855/**
Daniel Veillard01fa6152004-06-29 17:04:39 +00004856 * xmlSchemaValidateListSimpleTypeFacet:
4857 * @facet: the facet to check
4858 * @value: the lexical repr of the value to validate
4859 * @actualLen: the number of list items
4860 * @expectedLen: the resulting expected number of list items
4861 *
4862 * Checks the value of a list simple type against a facet.
4863 *
4864 * Returns 0 if the value is valid, a positive error code
4865 * number otherwise and -1 in case of an internal error.
4866 */
4867int
4868xmlSchemaValidateListSimpleTypeFacet(xmlSchemaFacetPtr facet,
4869 const xmlChar *value,
4870 unsigned long actualLen,
4871 unsigned long *expectedLen)
4872{
Daniel Veillardce682bc2004-11-05 17:22:25 +00004873 if (facet == NULL)
4874 return(-1);
Daniel Veillard01fa6152004-06-29 17:04:39 +00004875 /*
4876 * TODO: Check if this will work with large numbers.
4877 * (compare value.decimal.mi and value.decimal.hi as well?).
4878 */
4879 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
4880 if (actualLen != facet->val->value.decimal.lo) {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004881 if (expectedLen != NULL)
Daniel Veillardc0826a72004-08-10 14:17:33 +00004882 *expectedLen = facet->val->value.decimal.lo;
Daniel Veillard01fa6152004-06-29 17:04:39 +00004883 return (XML_SCHEMAV_CVC_LENGTH_VALID);
4884 }
4885 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
4886 if (actualLen < facet->val->value.decimal.lo) {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004887 if (expectedLen != NULL)
Daniel Veillardc0826a72004-08-10 14:17:33 +00004888 *expectedLen = facet->val->value.decimal.lo;
Daniel Veillard01fa6152004-06-29 17:04:39 +00004889 return (XML_SCHEMAV_CVC_MINLENGTH_VALID);
4890 }
4891 } else if (facet->type == XML_SCHEMA_FACET_MAXLENGTH) {
4892 if (actualLen > facet->val->value.decimal.lo) {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004893 if (expectedLen != NULL)
Daniel Veillardc0826a72004-08-10 14:17:33 +00004894 *expectedLen = facet->val->value.decimal.lo;
Daniel Veillard01fa6152004-06-29 17:04:39 +00004895 return (XML_SCHEMAV_CVC_MAXLENGTH_VALID);
4896 }
4897 } else
4898 /*
4899 * NOTE: That we can pass NULL as xmlSchemaValPtr to
4900 * xmlSchemaValidateFacet, since the remaining facet types
4901 * are: XML_SCHEMA_FACET_PATTERN, XML_SCHEMA_FACET_ENUMERATION.
4902 */
4903 return(xmlSchemaValidateFacet(NULL, facet, value, NULL));
4904 return (0);
4905}
4906
4907/**
Daniel Veillard6927b102004-10-27 17:29:04 +00004908 * xmlSchemaValidateLengthFacet:
Daniel Veillardc0826a72004-08-10 14:17:33 +00004909 * @type: the built-in type
4910 * @facet: the facet to check
4911 * @value: the lexical repr. of the value to be validated
4912 * @val: the precomputed value
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004913 * @ws: the whitespace type of the value
4914 * @length: the actual length of the value
4915 *
4916 * Checka a value against a "length", "minLength" and "maxLength"
4917 * facet; sets @length to the computed length of @value.
4918 *
4919 * Returns 0 if the value is valid, a positive error code
4920 * otherwise and -1 in case of an internal or API error.
4921 */
4922static int
4923xmlSchemaValidateLengthFacetInternal(xmlSchemaFacetPtr facet,
4924 xmlSchemaTypeType valType,
4925 const xmlChar *value,
4926 xmlSchemaValPtr val,
4927 unsigned long *length,
4928 xmlSchemaWhitespaceValueType ws)
4929{
4930 unsigned int len = 0;
4931
4932 if ((length == NULL) || (facet == NULL))
4933 return (-1);
4934 *length = 0;
4935 if ((facet->type != XML_SCHEMA_FACET_LENGTH) &&
4936 (facet->type != XML_SCHEMA_FACET_MAXLENGTH) &&
4937 (facet->type != XML_SCHEMA_FACET_MINLENGTH))
4938 return (-1);
4939
4940 /*
4941 * TODO: length, maxLength and minLength must be of type
4942 * nonNegativeInteger only. Check if decimal is used somehow.
4943 */
4944 if ((facet->val == NULL) ||
4945 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
4946 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
4947 (facet->val->value.decimal.frac != 0)) {
4948 return(-1);
4949 }
4950 if ((val != NULL) && (val->type == XML_SCHEMAS_HEXBINARY))
4951 len = val->value.hex.total;
4952 else if ((val != NULL) && (val->type == XML_SCHEMAS_BASE64BINARY))
4953 len = val->value.base64.total;
4954 else {
4955 switch (valType) {
4956 case XML_SCHEMAS_STRING:
4957 case XML_SCHEMAS_NORMSTRING:
4958 if (ws == XML_SCHEMA_WHITESPACE_UNKNOWN) {
4959 /*
4960 * This is to ensure API compatibility with the old
4961 * xmlSchemaValidateLengthFacet(). Anyway, this was and
4962 * is not the correct handling.
4963 * TODO: Get rid of this case somehow.
4964 */
4965 if (valType == XML_SCHEMAS_STRING)
4966 len = xmlUTF8Strlen(value);
4967 else
4968 len = xmlSchemaNormLen(value);
4969 } else if (value != NULL) {
4970 if (ws == XML_SCHEMA_WHITESPACE_COLLAPSE)
4971 len = xmlSchemaNormLen(value);
4972 else
4973 /*
4974 * Should be OK for "preserve" as well.
4975 */
4976 len = xmlUTF8Strlen(value);
4977 }
4978 break;
4979 case XML_SCHEMAS_IDREF:
4980 case XML_SCHEMAS_TOKEN:
4981 case XML_SCHEMAS_LANGUAGE:
4982 case XML_SCHEMAS_NMTOKEN:
4983 case XML_SCHEMAS_NAME:
4984 case XML_SCHEMAS_NCNAME:
Kasimier T. Buchcikbd6c3f72005-05-25 17:29:36 +00004985 case XML_SCHEMAS_ID:
4986 /*
4987 * FIXME: What exactly to do with anyURI?
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004988 */
4989 case XML_SCHEMAS_ANYURI:
4990 if (value != NULL)
4991 len = xmlSchemaNormLen(value);
4992 break;
Kasimier T. Buchcikbd6c3f72005-05-25 17:29:36 +00004993 case XML_SCHEMAS_QNAME:
4994 case XML_SCHEMAS_NOTATION:
4995 /*
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00004996 * For QName and NOTATION, those facets are
4997 * deprecated and should be ignored.
Kasimier T. Buchcikbd6c3f72005-05-25 17:29:36 +00004998 */
4999 return (0);
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005000 default:
5001 TODO
5002 }
5003 }
5004 *length = (unsigned long) len;
5005 /*
5006 * TODO: Return the whole expected value, i.e. "lo", "mi" and "hi".
5007 */
5008 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
5009 if (len != facet->val->value.decimal.lo)
5010 return(XML_SCHEMAV_CVC_LENGTH_VALID);
5011 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
5012 if (len < facet->val->value.decimal.lo)
5013 return(XML_SCHEMAV_CVC_MINLENGTH_VALID);
5014 } else {
5015 if (len > facet->val->value.decimal.lo)
5016 return(XML_SCHEMAV_CVC_MAXLENGTH_VALID);
5017 }
5018
5019 return (0);
5020}
5021
5022/**
5023 * xmlSchemaValidateLengthFacet:
5024 * @type: the built-in type
5025 * @facet: the facet to check
5026 * @value: the lexical repr. of the value to be validated
5027 * @val: the precomputed value
Daniel Veillardc0826a72004-08-10 14:17:33 +00005028 * @length: the actual length of the value
5029 *
5030 * Checka a value against a "length", "minLength" and "maxLength"
5031 * facet; sets @length to the computed length of @value.
5032 *
5033 * Returns 0 if the value is valid, a positive error code
5034 * otherwise and -1 in case of an internal or API error.
5035 */
5036int
5037xmlSchemaValidateLengthFacet(xmlSchemaTypePtr type,
5038 xmlSchemaFacetPtr facet,
5039 const xmlChar *value,
5040 xmlSchemaValPtr val,
5041 unsigned long *length)
5042{
Daniel Veillardcc5e2332005-03-16 21:55:35 +00005043 if (type == NULL)
5044 return(-1);
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005045 return (xmlSchemaValidateLengthFacetInternal(facet,
5046 type->builtInType, value, val, length,
5047 XML_SCHEMA_WHITESPACE_UNKNOWN));
5048}
Daniel Veillardc0826a72004-08-10 14:17:33 +00005049
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005050/**
5051 * xmlSchemaValidateLengthFacetWhtsp:
5052 * @facet: the facet to check
5053 * @valType: the built-in type
5054 * @value: the lexical repr. of the value to be validated
5055 * @val: the precomputed value
5056 * @ws: the whitespace type of the value
5057 * @length: the actual length of the value
5058 *
5059 * Checka a value against a "length", "minLength" and "maxLength"
5060 * facet; sets @length to the computed length of @value.
5061 *
5062 * Returns 0 if the value is valid, a positive error code
5063 * otherwise and -1 in case of an internal or API error.
5064 */
5065int
5066xmlSchemaValidateLengthFacetWhtsp(xmlSchemaFacetPtr facet,
5067 xmlSchemaValType valType,
5068 const xmlChar *value,
5069 xmlSchemaValPtr val,
5070 unsigned long *length,
5071 xmlSchemaWhitespaceValueType ws)
5072{
5073 return (xmlSchemaValidateLengthFacetInternal(facet, valType, value, val,
5074 length, ws));
Daniel Veillardc0826a72004-08-10 14:17:33 +00005075}
5076
5077/**
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005078 * xmlSchemaValidateFacetInternal:
Daniel Veillard4255d502002-04-16 15:50:10 +00005079 * @facet: the facet to check
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005080 * @fws: the whitespace type of the facet's value
5081 * @valType: the built-in type of the value
Daniel Veillard4255d502002-04-16 15:50:10 +00005082 * @value: the lexical repr of the value to validate
5083 * @val: the precomputed value
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005084 * @ws: the whitespace type of the value
Daniel Veillard4255d502002-04-16 15:50:10 +00005085 *
5086 * Check a value against a facet condition
5087 *
5088 * Returns 0 if the element is schemas valid, a positive error code
5089 * number otherwise and -1 in case of internal or API error.
5090 */
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005091static int
5092xmlSchemaValidateFacetInternal(xmlSchemaFacetPtr facet,
5093 xmlSchemaWhitespaceValueType fws,
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005094 xmlSchemaValType valType,
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005095 const xmlChar *value,
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005096 xmlSchemaValPtr val,
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005097 xmlSchemaWhitespaceValueType ws)
Daniel Veillard4255d502002-04-16 15:50:10 +00005098{
5099 int ret;
5100
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005101 if (facet == NULL)
5102 return(-1);
5103
Daniel Veillard4255d502002-04-16 15:50:10 +00005104 switch (facet->type) {
5105 case XML_SCHEMA_FACET_PATTERN:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005106 /*
5107 * NOTE that for patterns, the @value needs to be the normalized
5108 * value, *not* the lexical initial value or the canonical value.
5109 */
5110 if (value == NULL)
5111 return(-1);
Daniel Veillard4255d502002-04-16 15:50:10 +00005112 ret = xmlRegexpExec(facet->regexp, value);
5113 if (ret == 1)
5114 return(0);
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005115 if (ret == 0)
Daniel Veillard01fa6152004-06-29 17:04:39 +00005116 return(XML_SCHEMAV_CVC_PATTERN_VALID);
Daniel Veillard4255d502002-04-16 15:50:10 +00005117 return(ret);
5118 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
5119 ret = xmlSchemaCompareValues(val, facet->val);
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005120 if (ret == -2)
Daniel Veillard4255d502002-04-16 15:50:10 +00005121 return(-1);
Daniel Veillard4255d502002-04-16 15:50:10 +00005122 if (ret == -1)
5123 return(0);
Daniel Veillard01fa6152004-06-29 17:04:39 +00005124 return(XML_SCHEMAV_CVC_MAXEXCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00005125 case XML_SCHEMA_FACET_MAXINCLUSIVE:
5126 ret = xmlSchemaCompareValues(val, facet->val);
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005127 if (ret == -2)
Daniel Veillard070803b2002-05-03 07:29:38 +00005128 return(-1);
Daniel Veillard070803b2002-05-03 07:29:38 +00005129 if ((ret == -1) || (ret == 0))
5130 return(0);
Daniel Veillard01fa6152004-06-29 17:04:39 +00005131 return(XML_SCHEMAV_CVC_MAXINCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00005132 case XML_SCHEMA_FACET_MINEXCLUSIVE:
5133 ret = xmlSchemaCompareValues(val, facet->val);
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005134 if (ret == -2)
Daniel Veillard070803b2002-05-03 07:29:38 +00005135 return(-1);
Daniel Veillard070803b2002-05-03 07:29:38 +00005136 if (ret == 1)
5137 return(0);
Daniel Veillard01fa6152004-06-29 17:04:39 +00005138 return(XML_SCHEMAV_CVC_MINEXCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00005139 case XML_SCHEMA_FACET_MININCLUSIVE:
5140 ret = xmlSchemaCompareValues(val, facet->val);
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005141 if (ret == -2)
Daniel Veillard070803b2002-05-03 07:29:38 +00005142 return(-1);
Daniel Veillard070803b2002-05-03 07:29:38 +00005143 if ((ret == 1) || (ret == 0))
5144 return(0);
Daniel Veillard01fa6152004-06-29 17:04:39 +00005145 return(XML_SCHEMAV_CVC_MININCLUSIVE_VALID);
Daniel Veillard8651f532002-04-17 09:06:27 +00005146 case XML_SCHEMA_FACET_WHITESPACE:
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00005147 /* TODO whitespaces */
Daniel Veillard01fa6152004-06-29 17:04:39 +00005148 /*
5149 * NOTE: Whitespace should be handled to normalize
5150 * the value to be validated against a the facets;
5151 * not to normalize the value in-between.
5152 */
Daniel Veillard8651f532002-04-17 09:06:27 +00005153 return(0);
Daniel Veillard88c58912002-04-23 07:12:20 +00005154 case XML_SCHEMA_FACET_ENUMERATION:
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005155 if (ws == XML_SCHEMA_WHITESPACE_UNKNOWN) {
5156 /*
5157 * This is to ensure API compatibility with the old
5158 * xmlSchemaValidateFacet().
5159 * TODO: Get rid of this case.
5160 */
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005161 if ((facet->value != NULL) &&
5162 (xmlStrEqual(facet->value, value)))
5163 return(0);
5164 } else {
5165 ret = xmlSchemaCompareValuesWhtspExt(facet->val->type,
5166 facet->val, facet->value, fws, valType, val,
5167 value, ws);
5168 if (ret == -2)
5169 return(-1);
5170 if (ret == 0)
5171 return(0);
5172 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00005173 return(XML_SCHEMAV_CVC_ENUMERATION_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00005174 case XML_SCHEMA_FACET_LENGTH:
Kasimier T. Buchcikaba15f72005-04-01 15:17:27 +00005175 /*
5176 * SPEC (1.3) "if {primitive type definition} is QName or NOTATION,
5177 * then any {value} is facet-valid."
5178 */
5179 if ((valType == XML_SCHEMAS_QNAME) ||
5180 (valType == XML_SCHEMAS_NOTATION))
5181 return (0);
5182 /* No break on purpose. */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00005183 case XML_SCHEMA_FACET_MAXLENGTH:
5184 case XML_SCHEMA_FACET_MINLENGTH: {
5185 unsigned int len = 0;
5186
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00005187 if ((valType == XML_SCHEMAS_QNAME) ||
5188 (valType == XML_SCHEMAS_NOTATION))
5189 return (0);
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005190 /*
5191 * TODO: length, maxLength and minLength must be of type
5192 * nonNegativeInteger only. Check if decimal is used somehow.
5193 */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00005194 if ((facet->val == NULL) ||
Daniel Veillarde637c4a2003-03-30 21:10:09 +00005195 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
5196 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00005197 (facet->val->value.decimal.frac != 0)) {
5198 return(-1);
5199 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00005200 if ((val != NULL) && (val->type == XML_SCHEMAS_HEXBINARY))
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00005201 len = val->value.hex.total;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00005202 else if ((val != NULL) && (val->type == XML_SCHEMAS_BASE64BINARY))
5203 len = val->value.base64.total;
5204 else {
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005205 switch (valType) {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005206 case XML_SCHEMAS_STRING:
5207 case XML_SCHEMAS_NORMSTRING:
5208 if (ws == XML_SCHEMA_WHITESPACE_UNKNOWN) {
5209 /*
5210 * This is to ensure API compatibility with the old
5211 * xmlSchemaValidateFacet(). Anyway, this was and
5212 * is not the correct handling.
5213 * TODO: Get rid of this case somehow.
5214 */
5215 if (valType == XML_SCHEMAS_STRING)
5216 len = xmlUTF8Strlen(value);
5217 else
5218 len = xmlSchemaNormLen(value);
5219 } else if (value != NULL) {
5220 if (ws == XML_SCHEMA_WHITESPACE_COLLAPSE)
5221 len = xmlSchemaNormLen(value);
5222 else
5223 /*
5224 * Should be OK for "preserve" as well.
5225 */
5226 len = xmlUTF8Strlen(value);
5227 }
5228 break;
5229 case XML_SCHEMAS_IDREF:
Daniel Veillard560c2a42003-07-06 21:13:49 +00005230 case XML_SCHEMAS_TOKEN:
5231 case XML_SCHEMAS_LANGUAGE:
5232 case XML_SCHEMAS_NMTOKEN:
5233 case XML_SCHEMAS_NAME:
5234 case XML_SCHEMAS_NCNAME:
5235 case XML_SCHEMAS_ID:
Daniel Veillard01fa6152004-06-29 17:04:39 +00005236 case XML_SCHEMAS_ANYURI:
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005237 if (value != NULL)
5238 len = xmlSchemaNormLen(value);
5239 break;
Daniel Veillard560c2a42003-07-06 21:13:49 +00005240 default:
5241 TODO
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00005242 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00005243 }
5244 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00005245 if (len != facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00005246 return(XML_SCHEMAV_CVC_LENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00005247 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00005248 if (len < facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00005249 return(XML_SCHEMAV_CVC_MINLENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00005250 } else {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00005251 if (len > facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00005252 return(XML_SCHEMAV_CVC_MAXLENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00005253 }
5254 break;
5255 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00005256 case XML_SCHEMA_FACET_TOTALDIGITS:
5257 case XML_SCHEMA_FACET_FRACTIONDIGITS:
5258
5259 if ((facet->val == NULL) ||
5260 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
5261 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
5262 (facet->val->value.decimal.frac != 0)) {
5263 return(-1);
5264 }
5265 if ((val == NULL) ||
5266 ((val->type != XML_SCHEMAS_DECIMAL) &&
5267 (val->type != XML_SCHEMAS_INTEGER) &&
5268 (val->type != XML_SCHEMAS_NPINTEGER) &&
5269 (val->type != XML_SCHEMAS_NINTEGER) &&
5270 (val->type != XML_SCHEMAS_NNINTEGER) &&
5271 (val->type != XML_SCHEMAS_PINTEGER) &&
5272 (val->type != XML_SCHEMAS_INT) &&
5273 (val->type != XML_SCHEMAS_UINT) &&
5274 (val->type != XML_SCHEMAS_LONG) &&
5275 (val->type != XML_SCHEMAS_ULONG) &&
5276 (val->type != XML_SCHEMAS_SHORT) &&
5277 (val->type != XML_SCHEMAS_USHORT) &&
5278 (val->type != XML_SCHEMAS_BYTE) &&
5279 (val->type != XML_SCHEMAS_UBYTE))) {
5280 return(-1);
5281 }
5282 if (facet->type == XML_SCHEMA_FACET_TOTALDIGITS) {
5283 if (val->value.decimal.total > facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00005284 return(XML_SCHEMAV_CVC_TOTALDIGITS_VALID);
Daniel Veillard560c2a42003-07-06 21:13:49 +00005285
5286 } else if (facet->type == XML_SCHEMA_FACET_FRACTIONDIGITS) {
5287 if (val->value.decimal.frac > facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00005288 return(XML_SCHEMAV_CVC_FRACTIONDIGITS_VALID);
Daniel Veillard560c2a42003-07-06 21:13:49 +00005289 }
5290 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00005291 default:
5292 TODO
5293 }
5294 return(0);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00005295
Daniel Veillard4255d502002-04-16 15:50:10 +00005296}
5297
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00005298/**
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005299 * xmlSchemaValidateFacet:
5300 * @base: the base type
5301 * @facet: the facet to check
5302 * @value: the lexical repr of the value to validate
5303 * @val: the precomputed value
5304 *
5305 * Check a value against a facet condition
5306 *
5307 * Returns 0 if the element is schemas valid, a positive error code
5308 * number otherwise and -1 in case of internal or API error.
5309 */
5310int
Kasimier T. Buchcik9dbb0ce2005-03-16 16:39:23 +00005311xmlSchemaValidateFacet(xmlSchemaTypePtr base,
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005312 xmlSchemaFacetPtr facet,
5313 const xmlChar *value,
5314 xmlSchemaValPtr val)
5315{
5316 /*
5317 * This tries to ensure API compatibility regarding the old
5318 * xmlSchemaValidateFacet() and the new xmlSchemaValidateFacetInternal() and
5319 * xmlSchemaValidateFacetWhtsp().
5320 */
Kasimier T. Buchcik9dbb0ce2005-03-16 16:39:23 +00005321 if (val != NULL)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005322 return(xmlSchemaValidateFacetInternal(facet,
Kasimier T. Buchcik9dbb0ce2005-03-16 16:39:23 +00005323 XML_SCHEMA_WHITESPACE_UNKNOWN, val->type, value, val,
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005324 XML_SCHEMA_WHITESPACE_UNKNOWN));
Kasimier T. Buchcik9dbb0ce2005-03-16 16:39:23 +00005325 else if (base != NULL)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005326 return(xmlSchemaValidateFacetInternal(facet,
Kasimier T. Buchcik9dbb0ce2005-03-16 16:39:23 +00005327 XML_SCHEMA_WHITESPACE_UNKNOWN, base->builtInType, value, val,
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005328 XML_SCHEMA_WHITESPACE_UNKNOWN));
Kasimier T. Buchcik9dbb0ce2005-03-16 16:39:23 +00005329 return(-1);
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005330}
5331
5332/**
5333 * xmlSchemaValidateFacetWhtsp:
5334 * @facet: the facet to check
5335 * @fws: the whitespace type of the facet's value
5336 * @valType: the built-in type of the value
5337 * @value: the lexical (or normalized for pattern) repr of the value to validate
5338 * @val: the precomputed value
5339 * @ws: the whitespace type of the value
5340 *
5341 * Check a value against a facet condition. This takes value normalization
5342 * according to the specified whitespace types into account.
5343 * Note that @value needs to be the *normalized* value if the facet
5344 * is of type "pattern".
5345 *
5346 * Returns 0 if the element is schemas valid, a positive error code
5347 * number otherwise and -1 in case of internal or API error.
5348 */
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005349int
5350xmlSchemaValidateFacetWhtsp(xmlSchemaFacetPtr facet,
5351 xmlSchemaWhitespaceValueType fws,
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005352 xmlSchemaValType valType,
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005353 const xmlChar *value,
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005354 xmlSchemaValPtr val,
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005355 xmlSchemaWhitespaceValueType ws)
5356{
5357 return(xmlSchemaValidateFacetInternal(facet, fws, valType,
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005358 value, val, ws));
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005359}
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005360
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00005361#if 0
5362#ifndef DBL_DIG
5363#define DBL_DIG 16
5364#endif
5365#ifndef DBL_EPSILON
5366#define DBL_EPSILON 1E-9
5367#endif
5368
5369#define INTEGER_DIGITS DBL_DIG
5370#define FRACTION_DIGITS (DBL_DIG + 1)
5371#define EXPONENT_DIGITS (3 + 2)
5372
5373/**
5374 * xmlXPathFormatNumber:
5375 * @number: number to format
5376 * @buffer: output buffer
5377 * @buffersize: size of output buffer
5378 *
5379 * Convert the number into a string representation.
5380 */
5381static void
5382xmlSchemaFormatFloat(double number, char buffer[], int buffersize)
5383{
5384 switch (xmlXPathIsInf(number)) {
5385 case 1:
5386 if (buffersize > (int)sizeof("INF"))
5387 snprintf(buffer, buffersize, "INF");
5388 break;
5389 case -1:
5390 if (buffersize > (int)sizeof("-INF"))
5391 snprintf(buffer, buffersize, "-INF");
5392 break;
5393 default:
5394 if (xmlXPathIsNaN(number)) {
5395 if (buffersize > (int)sizeof("NaN"))
5396 snprintf(buffer, buffersize, "NaN");
5397 } else if (number == 0) {
5398 snprintf(buffer, buffersize, "0.0E0");
5399 } else {
5400 /* 3 is sign, decimal point, and terminating zero */
5401 char work[DBL_DIG + EXPONENT_DIGITS + 3];
5402 int integer_place, fraction_place;
5403 char *ptr;
5404 char *after_fraction;
5405 double absolute_value;
5406 int size;
5407
5408 absolute_value = fabs(number);
5409
5410 /*
5411 * Result is in work, and after_fraction points
5412 * just past the fractional part.
5413 * Use scientific notation
5414 */
5415 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
5416 fraction_place = DBL_DIG - 1;
5417 snprintf(work, sizeof(work),"%*.*e",
5418 integer_place, fraction_place, number);
5419 after_fraction = strchr(work + DBL_DIG, 'e');
5420 /* Remove fractional trailing zeroes */
5421 ptr = after_fraction;
5422 while (*(--ptr) == '0')
5423 ;
5424 if (*ptr != '.')
5425 ptr++;
5426 while ((*ptr++ = *after_fraction++) != 0);
5427
5428 /* Finally copy result back to caller */
5429 size = strlen(work) + 1;
5430 if (size > buffersize) {
5431 work[buffersize - 1] = 0;
5432 size = buffersize;
5433 }
5434 memmove(buffer, work, size);
5435 }
5436 break;
5437 }
5438}
5439#endif
5440
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005441/**
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00005442 * xmlSchemaGetCanonValue:
5443 * @val: the precomputed value
5444 * @retValue: the returned value
5445 *
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005446 * Get a the cononical lexical representation of the value.
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00005447 * The caller has to FREE the returned retValue.
5448 *
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005449 * WARNING: Some value types are not supported yet, resulting
5450 * in a @retValue of "???".
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00005451 *
5452 * TODO: XML Schema 1.0 does not define canonical representations
5453 * for: duration, gYearMonth, gYear, gMonthDay, gMonth, gDay,
5454 * anyURI, QName, NOTATION. This will be fixed in XML Schema 1.1.
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00005455 *
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00005456 *
5457 * Returns 0 if the value could be built, 1 if the value type is
5458 * not supported yet and -1 in case of API errors.
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00005459 */
5460int
Daniel Veillardb5839c32005-02-19 18:27:14 +00005461xmlSchemaGetCanonValue(xmlSchemaValPtr val, const xmlChar **retValue)
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00005462{
Daniel Veillardb5839c32005-02-19 18:27:14 +00005463 if ((retValue == NULL) || (val == NULL))
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00005464 return (-1);
5465 *retValue = NULL;
5466 switch (val->type) {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005467 case XML_SCHEMAS_STRING:
5468 if (val->value.str == NULL)
5469 *retValue = BAD_CAST xmlStrdup(BAD_CAST "");
5470 else
5471 *retValue =
5472 BAD_CAST xmlStrdup((const xmlChar *) val->value.str);
5473 break;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00005474 case XML_SCHEMAS_NORMSTRING:
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005475 if (val->value.str == NULL)
5476 *retValue = BAD_CAST xmlStrdup(BAD_CAST "");
5477 else {
5478 *retValue = xmlSchemaWhiteSpaceReplace(
5479 (const xmlChar *) val->value.str);
5480 if ((*retValue) == NULL)
5481 *retValue = BAD_CAST xmlStrdup(
5482 (const xmlChar *) val->value.str);
5483 }
5484 break;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00005485 case XML_SCHEMAS_TOKEN:
5486 case XML_SCHEMAS_LANGUAGE:
5487 case XML_SCHEMAS_NMTOKEN:
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005488 case XML_SCHEMAS_NAME:
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00005489 case XML_SCHEMAS_NCNAME:
5490 case XML_SCHEMAS_ID:
5491 case XML_SCHEMAS_IDREF:
5492 case XML_SCHEMAS_ENTITY:
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00005493 case XML_SCHEMAS_NOTATION: /* Unclear */
5494 case XML_SCHEMAS_ANYURI: /* Unclear */
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00005495 if (val->value.str == NULL)
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005496 return (-1);
Kasimier T. Buchcikaba15f72005-04-01 15:17:27 +00005497 *retValue =
5498 BAD_CAST xmlSchemaCollapseString(BAD_CAST val->value.str);
5499 if (*retValue == NULL)
5500 *retValue =
5501 BAD_CAST xmlStrdup((const xmlChar *) val->value.str);
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005502 break;
5503 case XML_SCHEMAS_QNAME:
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00005504 /* TODO: Unclear in XML Schema 1.0. */
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005505 if (val->value.qname.uri == NULL) {
5506 *retValue = BAD_CAST xmlStrdup(BAD_CAST val->value.qname.name);
5507 return (0);
5508 } else {
5509 *retValue = BAD_CAST xmlStrdup(BAD_CAST "{");
5510 *retValue = BAD_CAST xmlStrcat((xmlChar *) (*retValue),
5511 BAD_CAST val->value.qname.uri);
5512 *retValue = BAD_CAST xmlStrcat((xmlChar *) (*retValue),
5513 BAD_CAST "}");
5514 *retValue = BAD_CAST xmlStrcat((xmlChar *) (*retValue),
5515 BAD_CAST val->value.qname.uri);
5516 }
5517 break;
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00005518 case XML_SCHEMAS_DECIMAL:
5519 /*
5520 * TODO: Lookout for a more simple implementation.
5521 */
5522 if ((val->value.decimal.total == 1) &&
5523 (val->value.decimal.lo == 0)) {
5524 *retValue = xmlStrdup(BAD_CAST "0.0");
5525 } else {
5526 xmlSchemaValDecimal dec = val->value.decimal;
5527 int bufsize;
5528 char *buf = NULL, *offs;
5529
5530 /* Add room for the decimal point as well. */
5531 bufsize = dec.total + 2;
5532 if (dec.sign)
5533 bufsize++;
5534 /* Add room for leading/trailing zero. */
5535 if ((dec.frac == 0) || (dec.frac == dec.total))
5536 bufsize++;
5537 buf = xmlMalloc(bufsize);
5538 offs = buf;
5539 if (dec.sign)
5540 *offs++ = '-';
5541 if (dec.frac == dec.total) {
5542 *offs++ = '0';
5543 *offs++ = '.';
5544 }
5545 if (dec.hi != 0)
5546 snprintf(offs, bufsize - (offs - buf),
5547 "%lu%lu%lu", dec.hi, dec.mi, dec.lo);
5548 else if (dec.mi != 0)
5549 snprintf(offs, bufsize - (offs - buf),
5550 "%lu%lu", dec.mi, dec.lo);
5551 else
5552 snprintf(offs, bufsize - (offs - buf),
5553 "%lu", dec.lo);
5554
5555 if (dec.frac != 0) {
5556 if (dec.frac != dec.total) {
5557 int diff = dec.total - dec.frac;
5558 /*
5559 * Insert the decimal point.
5560 */
5561 memmove(offs + diff + 1, offs + diff, dec.frac +1);
5562 offs[diff] = '.';
5563 } else {
5564 unsigned int i = 0;
5565 /*
5566 * Insert missing zeroes behind the decimal point.
5567 */
5568 while (*(offs + i) != 0)
5569 i++;
5570 if (i < dec.total) {
5571 memmove(offs + (dec.total - i), offs, i +1);
5572 memset(offs, '0', dec.total - i);
5573 }
5574 }
5575 } else {
5576 /*
5577 * Append decimal point and zero.
5578 */
5579 offs = buf + bufsize - 1;
5580 *offs-- = 0;
5581 *offs-- = '0';
5582 *offs-- = '.';
5583 }
5584 *retValue = BAD_CAST buf;
5585 }
5586 break;
5587 case XML_SCHEMAS_INTEGER:
5588 case XML_SCHEMAS_PINTEGER:
5589 case XML_SCHEMAS_NPINTEGER:
5590 case XML_SCHEMAS_NINTEGER:
5591 case XML_SCHEMAS_NNINTEGER:
5592 case XML_SCHEMAS_LONG:
5593 case XML_SCHEMAS_BYTE:
5594 case XML_SCHEMAS_SHORT:
5595 case XML_SCHEMAS_INT:
5596 case XML_SCHEMAS_UINT:
5597 case XML_SCHEMAS_ULONG:
5598 case XML_SCHEMAS_USHORT:
5599 case XML_SCHEMAS_UBYTE:
5600 if ((val->value.decimal.total == 1) &&
5601 (val->value.decimal.lo == 0))
5602 *retValue = xmlStrdup(BAD_CAST "0");
5603 else {
5604 xmlSchemaValDecimal dec = val->value.decimal;
5605 int bufsize = dec.total + 1;
5606
5607 /* Add room for the decimal point as well. */
5608 if (dec.sign)
5609 bufsize++;
5610 *retValue = xmlMalloc(bufsize);
5611 if (dec.hi != 0) {
5612 if (dec.sign)
5613 snprintf((char *) *retValue, bufsize,
5614 "-%lu%lu%lu", dec.hi, dec.mi, dec.lo);
5615 else
5616 snprintf((char *) *retValue, bufsize,
5617 "%lu%lu%lu", dec.hi, dec.mi, dec.lo);
5618 } else if (dec.mi != 0) {
5619 if (dec.sign)
5620 snprintf((char *) *retValue, bufsize,
5621 "-%lu%lu", dec.mi, dec.lo);
5622 else
5623 snprintf((char *) *retValue, bufsize,
5624 "%lu%lu", dec.mi, dec.lo);
5625 } else {
5626 if (dec.sign)
5627 snprintf((char *) *retValue, bufsize, "-%lu", dec.lo);
5628 else
5629 snprintf((char *) *retValue, bufsize, "%lu", dec.lo);
5630 }
5631 }
5632 break;
5633 case XML_SCHEMAS_BOOLEAN:
5634 if (val->value.b)
5635 *retValue = BAD_CAST xmlStrdup(BAD_CAST "true");
5636 else
5637 *retValue = BAD_CAST xmlStrdup(BAD_CAST "false");
5638 break;
5639 case XML_SCHEMAS_DURATION: {
5640 char buf[100];
5641 unsigned long year;
5642 unsigned long mon, day, hour = 0, min = 0;
5643 double sec = 0, left;
5644
5645 /* TODO: Unclear in XML Schema 1.0 */
5646 /*
5647 * TODO: This results in a normalized output of the value
5648 * - which is NOT conformant to the spec -
5649 * since the exact values of each property are not
5650 * recoverable. Think about extending the structure to
5651 * provide a field for every property.
5652 */
5653 year = (unsigned long) FQUOTIENT(labs(val->value.dur.mon), 12);
5654 mon = labs(val->value.dur.mon) - 12 * year;
5655
5656 day = (unsigned long) FQUOTIENT(fabs(val->value.dur.sec), 86400);
5657 left = fabs(val->value.dur.sec) - day * 86400;
5658 if (left > 0) {
5659 hour = (unsigned long) FQUOTIENT(left, 3600);
5660 left = left - (hour * 3600);
5661 if (left > 0) {
5662 min = (unsigned long) FQUOTIENT(left, 60);
5663 sec = left - (min * 60);
5664 }
5665 }
5666 if ((val->value.dur.mon < 0) || (val->value.dur.sec < 0))
5667 snprintf(buf, 100, "P%luY%luM%luDT%luH%luM%.14gS",
5668 year, mon, day, hour, min, sec);
5669 else
5670 snprintf(buf, 100, "-P%luY%luM%luDT%luH%luM%.14gS",
5671 year, mon, day, hour, min, sec);
5672 *retValue = BAD_CAST xmlStrdup(BAD_CAST buf);
5673 }
5674 break;
5675 case XML_SCHEMAS_GYEAR: {
5676 char buf[30];
5677 /* TODO: Unclear in XML Schema 1.0 */
5678 /* TODO: What to do with the timezone? */
5679 snprintf(buf, 30, "%04ld", val->value.date.year);
5680 *retValue = BAD_CAST xmlStrdup(BAD_CAST buf);
5681 }
5682 break;
5683 case XML_SCHEMAS_GMONTH: {
5684 /* TODO: Unclear in XML Schema 1.0 */
5685 /* TODO: What to do with the timezone? */
5686 *retValue = xmlMalloc(5);
5687 snprintf((char *) *retValue, 6, "--%02u",
5688 val->value.date.mon);
5689 }
5690 break;
5691 case XML_SCHEMAS_GDAY: {
5692 /* TODO: Unclear in XML Schema 1.0 */
5693 /* TODO: What to do with the timezone? */
5694 *retValue = xmlMalloc(6);
5695 snprintf((char *) *retValue, 6, "---%02u",
5696 val->value.date.day);
5697 }
5698 break;
5699 case XML_SCHEMAS_GMONTHDAY: {
5700 /* TODO: Unclear in XML Schema 1.0 */
5701 /* TODO: What to do with the timezone? */
5702 *retValue = xmlMalloc(8);
5703 snprintf((char *) *retValue, 8, "--%02u-%02u",
5704 val->value.date.mon, val->value.date.day);
5705 }
5706 break;
5707 case XML_SCHEMAS_GYEARMONTH: {
5708 char buf[35];
5709 /* TODO: Unclear in XML Schema 1.0 */
5710 /* TODO: What to do with the timezone? */
5711 if (val->value.date.year < 0)
5712 snprintf(buf, 35, "-%04ld-%02u",
5713 labs(val->value.date.year),
5714 val->value.date.mon);
5715 else
5716 snprintf(buf, 35, "%04ld-%02u",
5717 val->value.date.year, val->value.date.mon);
5718 *retValue = BAD_CAST xmlStrdup(BAD_CAST buf);
5719 }
5720 break;
5721 case XML_SCHEMAS_TIME:
5722 {
5723 char buf[30];
5724
5725 if (val->value.date.tz_flag) {
5726 xmlSchemaValPtr norm;
5727
5728 norm = xmlSchemaDateNormalize(val, 0);
5729 if (norm == NULL)
5730 return (-1);
5731 /*
5732 * TODO: Check if "%.14g" is portable.
5733 */
5734 snprintf(buf, 30,
5735 "%02u:%02u:%02.14gZ",
5736 norm->value.date.hour,
5737 norm->value.date.min,
5738 norm->value.date.sec);
5739 xmlSchemaFreeValue(norm);
5740 } else {
5741 snprintf(buf, 30,
5742 "%02u:%02u:%02.14g",
5743 val->value.date.hour,
5744 val->value.date.min,
5745 val->value.date.sec);
5746 }
5747 *retValue = BAD_CAST xmlStrdup(BAD_CAST buf);
5748 }
5749 break;
5750 case XML_SCHEMAS_DATE:
5751 {
5752 char buf[30];
5753
5754 if (val->value.date.tz_flag) {
5755 xmlSchemaValPtr norm;
5756
5757 norm = xmlSchemaDateNormalize(val, 0);
5758 if (norm == NULL)
5759 return (-1);
5760 /*
5761 * TODO: Append the canonical value of the
5762 * recoverable timezone and not "Z".
5763 */
5764 snprintf(buf, 30,
5765 "%04ld:%02u:%02uZ",
5766 norm->value.date.year, norm->value.date.mon,
5767 norm->value.date.day);
5768 xmlSchemaFreeValue(norm);
5769 } else {
5770 snprintf(buf, 30,
5771 "%04ld:%02u:%02u",
5772 val->value.date.year, val->value.date.mon,
5773 val->value.date.day);
5774 }
5775 *retValue = BAD_CAST xmlStrdup(BAD_CAST buf);
5776 }
5777 break;
5778 case XML_SCHEMAS_DATETIME:
5779 {
5780 char buf[50];
5781
5782 if (val->value.date.tz_flag) {
5783 xmlSchemaValPtr norm;
5784
5785 norm = xmlSchemaDateNormalize(val, 0);
5786 if (norm == NULL)
5787 return (-1);
5788 /*
5789 * TODO: Check if "%.14g" is portable.
5790 */
5791 snprintf(buf, 50,
5792 "%04ld:%02u:%02uT%02u:%02u:%02.14gZ",
5793 norm->value.date.year, norm->value.date.mon,
5794 norm->value.date.day, norm->value.date.hour,
5795 norm->value.date.min, norm->value.date.sec);
5796 xmlSchemaFreeValue(norm);
5797 } else {
5798 snprintf(buf, 50,
5799 "%04ld:%02u:%02uT%02u:%02u:%02.14g",
5800 val->value.date.year, val->value.date.mon,
5801 val->value.date.day, val->value.date.hour,
5802 val->value.date.min, val->value.date.sec);
5803 }
5804 *retValue = BAD_CAST xmlStrdup(BAD_CAST buf);
5805 }
5806 break;
5807 case XML_SCHEMAS_HEXBINARY:
5808 *retValue = BAD_CAST xmlStrdup(BAD_CAST val->value.hex.str);
5809 break;
5810 case XML_SCHEMAS_BASE64BINARY:
5811 /*
5812 * TODO: Is the following spec piece implemented?:
5813 * SPEC: "Note: For some values the canonical form defined
5814 * above does not conform to [RFC 2045], which requires breaking
5815 * with linefeeds at appropriate intervals."
5816 */
5817 *retValue = BAD_CAST xmlStrdup(BAD_CAST val->value.base64.str);
5818 break;
5819 case XML_SCHEMAS_FLOAT: {
5820 char buf[30];
5821 /*
5822 * |m| < 16777216, -149 <= e <= 104.
5823 * TODO: Handle, NaN, INF, -INF. The format is not
5824 * yet conformant. The c type float does not cover
5825 * the whole range.
5826 */
5827 snprintf(buf, 30, "%01.14e", val->value.f);
5828 *retValue = BAD_CAST xmlStrdup(BAD_CAST buf);
5829 }
5830 break;
5831 case XML_SCHEMAS_DOUBLE: {
5832 char buf[40];
5833 /* |m| < 9007199254740992, -1075 <= e <= 970 */
5834 /*
5835 * TODO: Handle, NaN, INF, -INF. The format is not
5836 * yet conformant. The c type float does not cover
5837 * the whole range.
5838 */
5839 snprintf(buf, 40, "%01.14e", val->value.d);
5840 *retValue = BAD_CAST xmlStrdup(BAD_CAST buf);
5841 }
5842 break;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00005843 default:
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005844 *retValue = BAD_CAST xmlStrdup(BAD_CAST "???");
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00005845 return (1);
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00005846 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005847 return (0);
5848}
5849
Daniel Veillardbda59572005-04-01 17:15:17 +00005850/**
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00005851 * xmlSchemaGetCanonValueWhtsp:
5852 * @val: the precomputed value
5853 * @retValue: the returned value
5854 * @ws: the whitespace type of the value
5855 *
5856 * Get a the cononical representation of the value.
5857 * The caller has to free the returned @retValue.
5858 *
5859 * Returns 0 if the value could be built, 1 if the value type is
5860 * not supported yet and -1 in case of API errors.
5861 */
5862int
5863xmlSchemaGetCanonValueWhtsp(xmlSchemaValPtr val,
5864 const xmlChar **retValue,
5865 xmlSchemaWhitespaceValueType ws)
5866{
5867 if ((retValue == NULL) || (val == NULL))
5868 return (-1);
5869 if ((ws == XML_SCHEMA_WHITESPACE_UNKNOWN) ||
5870 (ws > XML_SCHEMA_WHITESPACE_COLLAPSE))
5871 return (-1);
5872
5873 *retValue = NULL;
5874 switch (val->type) {
5875 case XML_SCHEMAS_STRING:
5876 if (val->value.str == NULL)
5877 *retValue = BAD_CAST xmlStrdup(BAD_CAST "");
5878 else if (ws == XML_SCHEMA_WHITESPACE_COLLAPSE)
5879 *retValue = xmlSchemaCollapseString(val->value.str);
5880 else if (ws == XML_SCHEMA_WHITESPACE_REPLACE)
5881 *retValue = xmlSchemaWhiteSpaceReplace(val->value.str);
5882 if ((*retValue) == NULL)
5883 *retValue = BAD_CAST xmlStrdup(val->value.str);
5884 break;
5885 case XML_SCHEMAS_NORMSTRING:
5886 if (val->value.str == NULL)
5887 *retValue = BAD_CAST xmlStrdup(BAD_CAST "");
5888 else {
5889 if (ws == XML_SCHEMA_WHITESPACE_COLLAPSE)
5890 *retValue = xmlSchemaCollapseString(val->value.str);
5891 else
5892 *retValue = xmlSchemaWhiteSpaceReplace(val->value.str);
5893 if ((*retValue) == NULL)
5894 *retValue = BAD_CAST xmlStrdup(val->value.str);
5895 }
5896 break;
5897 default:
5898 return (xmlSchemaGetCanonValue(val, retValue));
5899 }
5900 return (0);
5901}
5902
5903/**
Daniel Veillardbda59572005-04-01 17:15:17 +00005904 * xmlSchemaGetValType:
5905 * @val: a schemas value
5906 *
5907 * Accessor for the type of a value
5908 *
5909 * Returns the xmlSchemaValType of the value
5910 */
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005911xmlSchemaValType
5912xmlSchemaGetValType(xmlSchemaValPtr val)
5913{
Daniel Veillardbda59572005-04-01 17:15:17 +00005914 if (val == NULL)
5915 return(XML_SCHEMAS_UNKNOWN);
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005916 return (val->type);
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00005917}
5918
Daniel Veillard5d4644e2005-04-01 13:11:58 +00005919#define bottom_xmlschemastypes
5920#include "elfgcchack.h"
Daniel Veillard4255d502002-04-16 15:50:10 +00005921#endif /* LIBXML_SCHEMAS_ENABLED */