blob: d9fee06ef7987e4921f7180fa157dce003c44311 [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) {
William M. Brack273670f2005-03-11 15:55:14 +00002197 while ((cptr > cval) && (*(cptr-1) == '0')) {
2198 cptr--;
2199 len--;
2200 }
2201 }
2202 *cptr = 0; /* Terminate our (preparsed) string */
2203 cptr = cval;
2204 /*
2205 * Now evaluate the significant digits of the number
2206 */
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00002207 if (*cptr != 0)
2208 xmlSchemaParseUInt((const xmlChar **)&cptr,
William M. Brack273670f2005-03-11 15:55:14 +00002209 &v->value.decimal.lo,
2210 &v->value.decimal.mi,
2211 &v->value.decimal.hi);
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00002212 /*
2213 * Set the total digits to 1 if a zero value.
2214 */
2215 if (len == 0)
2216 len++;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002217 v->value.decimal.sign = neg;
William M. Brack273670f2005-03-11 15:55:14 +00002218 if (dec == -1) {
2219 v->value.decimal.frac = 0;
2220 v->value.decimal.total = len;
2221 } else {
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00002222 v->value.decimal.frac = len - dec;
2223 v->value.decimal.total = len;
William M. Brack273670f2005-03-11 15:55:14 +00002224 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002225 *val = v;
2226 }
2227 }
2228 goto return0;
2229 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002230 case XML_SCHEMAS_TIME:
2231 case XML_SCHEMAS_GDAY:
2232 case XML_SCHEMAS_GMONTH:
2233 case XML_SCHEMAS_GMONTHDAY:
2234 case XML_SCHEMAS_GYEAR:
2235 case XML_SCHEMAS_GYEARMONTH:
2236 case XML_SCHEMAS_DATE:
2237 case XML_SCHEMAS_DATETIME:
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00002238 ret = xmlSchemaValidateDates(type->builtInType, value, val,
2239 normOnTheFly);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002240 break;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002241 case XML_SCHEMAS_DURATION:
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00002242 ret = xmlSchemaValidateDuration(type, value, val,
2243 normOnTheFly);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002244 break;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002245 case XML_SCHEMAS_FLOAT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002246 case XML_SCHEMAS_DOUBLE:{
2247 const xmlChar *cur = value;
2248 int neg = 0;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002249
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002250 if (cur == NULL)
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00002251 goto return1;
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00002252
2253 if (normOnTheFly)
2254 while IS_WSP_BLANK_CH(*cur) cur++;
2255
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002256 if ((cur[0] == 'N') && (cur[1] == 'a') && (cur[2] == 'N')) {
2257 cur += 3;
2258 if (*cur != 0)
2259 goto return1;
2260 if (val != NULL) {
2261 if (type == xmlSchemaTypeFloatDef) {
2262 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
2263 if (v != NULL) {
2264 v->value.f = (float) xmlXPathNAN;
2265 } else {
2266 xmlSchemaFreeValue(v);
2267 goto error;
2268 }
2269 } else {
2270 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
2271 if (v != NULL) {
2272 v->value.d = xmlXPathNAN;
2273 } else {
2274 xmlSchemaFreeValue(v);
2275 goto error;
2276 }
2277 }
2278 *val = v;
2279 }
2280 goto return0;
2281 }
2282 if (*cur == '-') {
2283 neg = 1;
2284 cur++;
2285 }
2286 if ((cur[0] == 'I') && (cur[1] == 'N') && (cur[2] == 'F')) {
2287 cur += 3;
2288 if (*cur != 0)
2289 goto return1;
2290 if (val != NULL) {
2291 if (type == xmlSchemaTypeFloatDef) {
2292 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
2293 if (v != NULL) {
2294 if (neg)
2295 v->value.f = (float) xmlXPathNINF;
2296 else
2297 v->value.f = (float) xmlXPathPINF;
2298 } else {
2299 xmlSchemaFreeValue(v);
2300 goto error;
2301 }
2302 } else {
2303 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
2304 if (v != NULL) {
2305 if (neg)
2306 v->value.d = xmlXPathNINF;
2307 else
2308 v->value.d = xmlXPathPINF;
2309 } else {
2310 xmlSchemaFreeValue(v);
2311 goto error;
2312 }
2313 }
2314 *val = v;
2315 }
2316 goto return0;
2317 }
2318 if ((neg == 0) && (*cur == '+'))
2319 cur++;
2320 if ((cur[0] == 0) || (cur[0] == '+') || (cur[0] == '-'))
2321 goto return1;
2322 while ((*cur >= '0') && (*cur <= '9')) {
2323 cur++;
2324 }
2325 if (*cur == '.') {
2326 cur++;
2327 while ((*cur >= '0') && (*cur <= '9'))
2328 cur++;
2329 }
2330 if ((*cur == 'e') || (*cur == 'E')) {
2331 cur++;
2332 if ((*cur == '-') || (*cur == '+'))
2333 cur++;
2334 while ((*cur >= '0') && (*cur <= '9'))
2335 cur++;
2336 }
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00002337 if (normOnTheFly)
2338 while IS_WSP_BLANK_CH(*cur) cur++;
2339
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002340 if (*cur != 0)
2341 goto return1;
2342 if (val != NULL) {
2343 if (type == xmlSchemaTypeFloatDef) {
2344 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
2345 if (v != NULL) {
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00002346 /*
2347 * TODO: sscanf seems not to give the correct
2348 * value for extremely high/low values.
2349 * E.g. "1E-149" results in zero.
2350 */
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002351 if (sscanf((const char *) value, "%f",
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002352 &(v->value.f)) == 1) {
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00002353 *val = v;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002354 } else {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002355 xmlSchemaFreeValue(v);
2356 goto return1;
2357 }
2358 } else {
2359 goto error;
2360 }
2361 } else {
2362 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
2363 if (v != NULL) {
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00002364 /*
2365 * TODO: sscanf seems not to give the correct
2366 * value for extremely high/low values.
2367 */
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002368 if (sscanf((const char *) value, "%lf",
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002369 &(v->value.d)) == 1) {
2370 *val = v;
2371 } else {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002372 xmlSchemaFreeValue(v);
2373 goto return1;
2374 }
2375 } else {
2376 goto error;
2377 }
2378 }
2379 }
2380 goto return0;
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00002381 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002382 case XML_SCHEMAS_BOOLEAN:{
2383 const xmlChar *cur = value;
2384
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00002385 if (normOnTheFly) {
2386 while IS_WSP_BLANK_CH(*cur) cur++;
2387 if (*cur == '0') {
2388 ret = 0;
2389 cur++;
2390 } else if (*cur == '1') {
2391 ret = 1;
2392 cur++;
2393 } else if (*cur == 't') {
2394 cur++;
2395 if ((*cur++ == 'r') && (*cur++ == 'u') &&
2396 (*cur++ == 'e')) {
2397 ret = 1;
2398 } else
2399 goto return1;
2400 } else if (*cur == 'f') {
2401 cur++;
2402 if ((*cur++ == 'a') && (*cur++ == 'l') &&
2403 (*cur++ == 's') && (*cur++ == 'e')) {
2404 ret = 0;
2405 } else
2406 goto return1;
2407 }
2408 if (*cur != 0) {
2409 while IS_WSP_BLANK_CH(*cur) cur++;
2410 if (*cur != 0)
2411 goto return1;
2412 }
2413 } else {
2414 if ((cur[0] == '0') && (cur[1] == 0))
2415 ret = 0;
2416 else if ((cur[0] == '1') && (cur[1] == 0))
2417 ret = 1;
2418 else if ((cur[0] == 't') && (cur[1] == 'r')
2419 && (cur[2] == 'u') && (cur[3] == 'e')
2420 && (cur[4] == 0))
2421 ret = 1;
2422 else if ((cur[0] == 'f') && (cur[1] == 'a')
2423 && (cur[2] == 'l') && (cur[3] == 's')
2424 && (cur[4] == 'e') && (cur[5] == 0))
2425 ret = 0;
2426 else
2427 goto return1;
2428 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002429 if (val != NULL) {
2430 v = xmlSchemaNewValue(XML_SCHEMAS_BOOLEAN);
2431 if (v != NULL) {
2432 v->value.b = ret;
2433 *val = v;
2434 } else {
2435 goto error;
2436 }
2437 }
2438 goto return0;
2439 }
2440 case XML_SCHEMAS_TOKEN:{
2441 const xmlChar *cur = value;
2442
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00002443 if (! normOnTheFly) {
2444 while (*cur != 0) {
2445 if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) {
2446 goto return1;
2447 } else if (*cur == ' ') {
2448 cur++;
2449 if (*cur == 0)
2450 goto return1;
2451 if (*cur == ' ')
2452 goto return1;
2453 } else {
2454 cur++;
2455 }
2456 }
2457 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002458 if (val != NULL) {
2459 v = xmlSchemaNewValue(XML_SCHEMAS_TOKEN);
2460 if (v != NULL) {
2461 v->value.str = xmlStrdup(value);
2462 *val = v;
2463 } else {
2464 goto error;
2465 }
2466 }
2467 goto return0;
2468 }
2469 case XML_SCHEMAS_LANGUAGE:
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00002470 if (normOnTheFly) {
2471 norm = xmlSchemaCollapseString(value);
2472 if (norm != NULL)
2473 value = norm;
2474 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002475 if (xmlCheckLanguageID(value) == 1) {
2476 if (val != NULL) {
2477 v = xmlSchemaNewValue(XML_SCHEMAS_LANGUAGE);
2478 if (v != NULL) {
2479 v->value.str = xmlStrdup(value);
2480 *val = v;
2481 } else {
2482 goto error;
2483 }
2484 }
2485 goto return0;
2486 }
2487 goto return1;
2488 case XML_SCHEMAS_NMTOKEN:
2489 if (xmlValidateNMToken(value, 1) == 0) {
2490 if (val != NULL) {
2491 v = xmlSchemaNewValue(XML_SCHEMAS_NMTOKEN);
2492 if (v != NULL) {
2493 v->value.str = xmlStrdup(value);
2494 *val = v;
2495 } else {
2496 goto error;
2497 }
2498 }
2499 goto return0;
2500 }
2501 goto return1;
2502 case XML_SCHEMAS_NMTOKENS:
2503 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeNmtokenDef,
2504 value, val, node);
2505 if (ret > 0)
2506 ret = 0;
2507 else
2508 ret = 1;
2509 goto done;
2510 case XML_SCHEMAS_NAME:
2511 ret = xmlValidateName(value, 1);
Daniel Veillarddf292f72005-01-16 19:00:15 +00002512 if ((ret == 0) && (val != NULL) && (value != NULL)) {
2513 v = xmlSchemaNewValue(XML_SCHEMAS_NAME);
2514 if (v != NULL) {
2515 const xmlChar *start = value, *end;
2516 while (IS_BLANK_CH(*start)) start++;
2517 end = start;
2518 while ((*end != 0) && (!IS_BLANK_CH(*end))) end++;
2519 v->value.str = xmlStrndup(start, end - start);
2520 *val = v;
2521 } else {
2522 goto error;
2523 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002524 }
2525 goto done;
2526 case XML_SCHEMAS_QNAME:{
Kasimier T. Buchcik1c720df2005-06-09 14:54:59 +00002527 const xmlChar *uri = NULL;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002528 xmlChar *local = NULL;
2529
2530 ret = xmlValidateQName(value, 1);
Kasimier T. Buchcik1c720df2005-06-09 14:54:59 +00002531 if (ret != 0)
2532 goto done;
2533 if (node != NULL) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002534 xmlChar *prefix;
Kasimier T. Buchcik1c720df2005-06-09 14:54:59 +00002535 xmlNsPtr ns;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002536
2537 local = xmlSplitQName2(value, &prefix);
Kasimier T. Buchcik1c720df2005-06-09 14:54:59 +00002538 ns = xmlSearchNs(node->doc, node, prefix);
2539 if ((ns == NULL) && (prefix != NULL)) {
2540 xmlFree(prefix);
2541 if (local != NULL)
2542 xmlFree(local);
2543 goto return1;
2544 }
2545 if (ns != NULL)
2546 uri = ns->href;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002547 if (prefix != NULL)
2548 xmlFree(prefix);
2549 }
Kasimier T. Buchcik1c720df2005-06-09 14:54:59 +00002550 if (val != NULL) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002551 v = xmlSchemaNewValue(XML_SCHEMAS_QNAME);
Kasimier T. Buchcik1c720df2005-06-09 14:54:59 +00002552 if (v == NULL) {
2553 if (local != NULL)
2554 xmlFree(local);
2555 goto error;
2556 }
2557 if (local != NULL)
2558 v->value.qname.name = local;
2559 else
2560 v->value.qname.name = xmlStrdup(value);
2561 if (uri != NULL)
2562 v->value.qname.uri = xmlStrdup(uri);
2563 *val = v;
2564 } else
2565 if (local != NULL)
2566 xmlFree(local);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002567 goto done;
2568 }
2569 case XML_SCHEMAS_NCNAME:
2570 ret = xmlValidateNCName(value, 1);
2571 if ((ret == 0) && (val != NULL)) {
2572 v = xmlSchemaNewValue(XML_SCHEMAS_NCNAME);
2573 if (v != NULL) {
2574 v->value.str = xmlStrdup(value);
2575 *val = v;
2576 } else {
2577 goto error;
2578 }
2579 }
2580 goto done;
2581 case XML_SCHEMAS_ID:
2582 ret = xmlValidateNCName(value, 1);
2583 if ((ret == 0) && (val != NULL)) {
2584 v = xmlSchemaNewValue(XML_SCHEMAS_ID);
2585 if (v != NULL) {
2586 v->value.str = xmlStrdup(value);
2587 *val = v;
2588 } else {
2589 goto error;
2590 }
2591 }
2592 if ((ret == 0) && (node != NULL) &&
2593 (node->type == XML_ATTRIBUTE_NODE)) {
2594 xmlAttrPtr attr = (xmlAttrPtr) node;
2595
2596 /*
2597 * NOTE: the IDness might have already be declared in the DTD
2598 */
2599 if (attr->atype != XML_ATTRIBUTE_ID) {
2600 xmlIDPtr res;
2601 xmlChar *strip;
2602
2603 strip = xmlSchemaStrip(value);
2604 if (strip != NULL) {
2605 res = xmlAddID(NULL, node->doc, strip, attr);
2606 xmlFree(strip);
2607 } else
2608 res = xmlAddID(NULL, node->doc, value, attr);
2609 if (res == NULL) {
2610 ret = 2;
2611 } else {
2612 attr->atype = XML_ATTRIBUTE_ID;
2613 }
2614 }
2615 }
2616 goto done;
2617 case XML_SCHEMAS_IDREF:
2618 ret = xmlValidateNCName(value, 1);
2619 if ((ret == 0) && (val != NULL)) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00002620 v = xmlSchemaNewValue(XML_SCHEMAS_IDREF);
2621 if (v == NULL)
2622 goto error;
2623 v->value.str = xmlStrdup(value);
2624 *val = v;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002625 }
2626 if ((ret == 0) && (node != NULL) &&
2627 (node->type == XML_ATTRIBUTE_NODE)) {
2628 xmlAttrPtr attr = (xmlAttrPtr) node;
2629 xmlChar *strip;
2630
2631 strip = xmlSchemaStrip(value);
2632 if (strip != NULL) {
2633 xmlAddRef(NULL, node->doc, strip, attr);
2634 xmlFree(strip);
2635 } else
2636 xmlAddRef(NULL, node->doc, value, attr);
2637 attr->atype = XML_ATTRIBUTE_IDREF;
2638 }
2639 goto done;
2640 case XML_SCHEMAS_IDREFS:
2641 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeIdrefDef,
2642 value, val, node);
2643 if (ret < 0)
2644 ret = 2;
2645 else
2646 ret = 0;
2647 if ((ret == 0) && (node != NULL) &&
2648 (node->type == XML_ATTRIBUTE_NODE)) {
2649 xmlAttrPtr attr = (xmlAttrPtr) node;
2650
2651 attr->atype = XML_ATTRIBUTE_IDREFS;
2652 }
2653 goto done;
2654 case XML_SCHEMAS_ENTITY:{
2655 xmlChar *strip;
2656
2657 ret = xmlValidateNCName(value, 1);
2658 if ((node == NULL) || (node->doc == NULL))
2659 ret = 3;
2660 if (ret == 0) {
2661 xmlEntityPtr ent;
2662
2663 strip = xmlSchemaStrip(value);
2664 if (strip != NULL) {
2665 ent = xmlGetDocEntity(node->doc, strip);
2666 xmlFree(strip);
2667 } else {
2668 ent = xmlGetDocEntity(node->doc, value);
2669 }
2670 if ((ent == NULL) ||
2671 (ent->etype !=
2672 XML_EXTERNAL_GENERAL_UNPARSED_ENTITY))
2673 ret = 4;
2674 }
2675 if ((ret == 0) && (val != NULL)) {
2676 TODO;
2677 }
2678 if ((ret == 0) && (node != NULL) &&
2679 (node->type == XML_ATTRIBUTE_NODE)) {
2680 xmlAttrPtr attr = (xmlAttrPtr) node;
2681
2682 attr->atype = XML_ATTRIBUTE_ENTITY;
2683 }
2684 goto done;
2685 }
2686 case XML_SCHEMAS_ENTITIES:
2687 if ((node == NULL) || (node->doc == NULL))
2688 goto return3;
2689 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeEntityDef,
2690 value, val, node);
2691 if (ret <= 0)
2692 ret = 1;
2693 else
2694 ret = 0;
2695 if ((ret == 0) && (node != NULL) &&
2696 (node->type == XML_ATTRIBUTE_NODE)) {
2697 xmlAttrPtr attr = (xmlAttrPtr) node;
2698
2699 attr->atype = XML_ATTRIBUTE_ENTITIES;
2700 }
2701 goto done;
2702 case XML_SCHEMAS_NOTATION:{
2703 xmlChar *uri = NULL;
2704 xmlChar *local = NULL;
2705
2706 ret = xmlValidateQName(value, 1);
2707 if ((ret == 0) && (node != NULL)) {
2708 xmlChar *prefix;
2709
2710 local = xmlSplitQName2(value, &prefix);
2711 if (prefix != NULL) {
2712 xmlNsPtr ns;
2713
2714 ns = xmlSearchNs(node->doc, node, prefix);
2715 if (ns == NULL)
2716 ret = 1;
2717 else if (val != NULL)
2718 uri = xmlStrdup(ns->href);
2719 }
2720 if ((local != NULL) && ((val == NULL) || (ret != 0)))
2721 xmlFree(local);
2722 if (prefix != NULL)
2723 xmlFree(prefix);
2724 }
2725 if ((node == NULL) || (node->doc == NULL))
2726 ret = 3;
2727 if (ret == 0) {
2728 ret = xmlValidateNotationUse(NULL, node->doc, value);
2729 if (ret == 1)
2730 ret = 0;
2731 else
2732 ret = 1;
2733 }
2734 if ((ret == 0) && (val != NULL)) {
2735 v = xmlSchemaNewValue(XML_SCHEMAS_NOTATION);
2736 if (v != NULL) {
2737 if (local != NULL)
2738 v->value.qname.name = local;
2739 else
2740 v->value.qname.name = xmlStrdup(value);
2741 if (uri != NULL)
2742 v->value.qname.uri = uri;
2743
2744 *val = v;
2745 } else {
2746 if (local != NULL)
2747 xmlFree(local);
2748 if (uri != NULL)
2749 xmlFree(uri);
2750 goto error;
2751 }
2752 }
2753 goto done;
2754 }
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00002755 case XML_SCHEMAS_ANYURI:{
Daniel Veillard11c466a2004-03-14 12:20:15 +00002756 if (*value != 0) {
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00002757 xmlURIPtr uri;
2758 if (normOnTheFly) {
2759 norm = xmlSchemaCollapseString(value);
2760 if (norm != NULL)
2761 value = norm;
2762 }
2763 uri = xmlParseURI((const char *) value);
Daniel Veillard11c466a2004-03-14 12:20:15 +00002764 if (uri == NULL)
2765 goto return1;
2766 xmlFreeURI(uri);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002767 }
Daniel Veillard11c466a2004-03-14 12:20:15 +00002768
2769 if (val != NULL) {
2770 v = xmlSchemaNewValue(XML_SCHEMAS_ANYURI);
2771 if (v == NULL)
2772 goto error;
2773 v->value.str = xmlStrdup(value);
2774 *val = v;
2775 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002776 goto return0;
2777 }
2778 case XML_SCHEMAS_HEXBINARY:{
Kasimier T. Buchcik8dd1e1b2005-06-09 13:14:38 +00002779 const xmlChar *cur = value, *start;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002780 xmlChar *base;
2781 int total, i = 0;
2782
Daniel Veillardf34a20e2004-08-31 08:42:17 +00002783 if (cur == NULL)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002784 goto return1;
2785
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00002786 if (normOnTheFly)
2787 while IS_WSP_BLANK_CH(*cur) cur++;
2788
Kasimier T. Buchcik8dd1e1b2005-06-09 13:14:38 +00002789 start = cur;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002790 while (((*cur >= '0') && (*cur <= '9')) ||
2791 ((*cur >= 'A') && (*cur <= 'F')) ||
2792 ((*cur >= 'a') && (*cur <= 'f'))) {
2793 i++;
2794 cur++;
2795 }
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00002796 if (normOnTheFly)
2797 while IS_WSP_BLANK_CH(*cur) cur++;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002798
2799 if (*cur != 0)
2800 goto return1;
2801 if ((i % 2) != 0)
2802 goto return1;
2803
2804 if (val != NULL) {
2805
2806 v = xmlSchemaNewValue(XML_SCHEMAS_HEXBINARY);
2807 if (v == NULL)
2808 goto error;
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00002809 /*
2810 * Copy only the normalized piece.
2811 * CRITICAL TODO: Check this.
2812 */
Kasimier T. Buchcik8dd1e1b2005-06-09 13:14:38 +00002813 cur = xmlStrndup(start, i);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002814 if (cur == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002815 xmlSchemaTypeErrMemory(node, "allocating hexbin data");
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002816 xmlFree(v);
2817 goto return1;
2818 }
2819
2820 total = i / 2; /* number of octets */
2821
2822 base = (xmlChar *) cur;
2823 while (i-- > 0) {
2824 if (*base >= 'a')
2825 *base = *base - ('a' - 'A');
2826 base++;
2827 }
2828
2829 v->value.hex.str = (xmlChar *) cur;
2830 v->value.hex.total = total;
2831 *val = v;
2832 }
2833 goto return0;
2834 }
2835 case XML_SCHEMAS_BASE64BINARY:{
2836 /* ISSUE:
2837 *
2838 * Ignore all stray characters? (yes, currently)
2839 * Worry about long lines? (no, currently)
2840 *
2841 * rfc2045.txt:
2842 *
2843 * "The encoded output stream must be represented in lines of
2844 * no more than 76 characters each. All line breaks or other
2845 * characters not found in Table 1 must be ignored by decoding
2846 * software. In base64 data, characters other than those in
2847 * Table 1, line breaks, and other white space probably
2848 * indicate a transmission error, about which a warning
2849 * message or even a message rejection might be appropriate
2850 * under some circumstances." */
2851 const xmlChar *cur = value;
2852 xmlChar *base;
2853 int total, i = 0, pad = 0;
2854
2855 if (cur == NULL)
2856 goto return1;
2857
2858 for (; *cur; ++cur) {
2859 int decc;
2860
2861 decc = _xmlSchemaBase64Decode(*cur);
2862 if (decc < 0) ;
2863 else if (decc < 64)
2864 i++;
2865 else
2866 break;
2867 }
2868 for (; *cur; ++cur) {
2869 int decc;
2870
2871 decc = _xmlSchemaBase64Decode(*cur);
2872 if (decc < 0) ;
2873 else if (decc < 64)
2874 goto return1;
2875 if (decc == 64)
2876 pad++;
2877 }
2878
2879 /* rfc2045.txt: "Special processing is performed if fewer than
2880 * 24 bits are available at the end of the data being encoded.
2881 * A full encoding quantum is always completed at the end of a
2882 * body. When fewer than 24 input bits are available in an
2883 * input group, zero bits are added (on the right) to form an
2884 * integral number of 6-bit groups. Padding at the end of the
2885 * data is performed using the "=" character. Since all
2886 * base64 input is an integral number of octets, only the
2887 * following cases can arise: (1) the final quantum of
2888 * encoding input is an integral multiple of 24 bits; here,
2889 * the final unit of encoded output will be an integral
2890 * multiple ofindent: Standard input:701: Warning:old style
2891 * assignment ambiguity in "=*". Assuming "= *" 4 characters
2892 * with no "=" padding, (2) the final
2893 * quantum of encoding input is exactly 8 bits; here, the
2894 * final unit of encoded output will be two characters
2895 * followed by two "=" padding characters, or (3) the final
2896 * quantum of encoding input is exactly 16 bits; here, the
2897 * final unit of encoded output will be three characters
2898 * followed by one "=" padding character." */
2899
2900 total = 3 * (i / 4);
2901 if (pad == 0) {
2902 if (i % 4 != 0)
2903 goto return1;
2904 } else if (pad == 1) {
2905 int decc;
2906
2907 if (i % 4 != 3)
2908 goto return1;
2909 for (decc = _xmlSchemaBase64Decode(*cur);
2910 (decc < 0) || (decc > 63);
2911 decc = _xmlSchemaBase64Decode(*cur))
2912 --cur;
2913 /* 16bits in 24bits means 2 pad bits: nnnnnn nnmmmm mmmm00*/
2914 /* 00111100 -> 0x3c */
2915 if (decc & ~0x3c)
2916 goto return1;
2917 total += 2;
2918 } else if (pad == 2) {
2919 int decc;
2920
2921 if (i % 4 != 2)
2922 goto return1;
2923 for (decc = _xmlSchemaBase64Decode(*cur);
2924 (decc < 0) || (decc > 63);
2925 decc = _xmlSchemaBase64Decode(*cur))
2926 --cur;
2927 /* 8bits in 12bits means 4 pad bits: nnnnnn nn0000 */
2928 /* 00110000 -> 0x30 */
2929 if (decc & ~0x30)
2930 goto return1;
2931 total += 1;
2932 } else
2933 goto return1;
2934
2935 if (val != NULL) {
2936 v = xmlSchemaNewValue(XML_SCHEMAS_BASE64BINARY);
2937 if (v == NULL)
2938 goto error;
2939 base =
2940 (xmlChar *) xmlMallocAtomic((i + pad + 1) *
2941 sizeof(xmlChar));
2942 if (base == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002943 xmlSchemaTypeErrMemory(node, "allocating base64 data");
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002944 xmlFree(v);
2945 goto return1;
2946 }
2947 v->value.base64.str = base;
2948 for (cur = value; *cur; ++cur)
2949 if (_xmlSchemaBase64Decode(*cur) >= 0) {
2950 *base = *cur;
2951 ++base;
2952 }
2953 *base = 0;
2954 v->value.base64.total = total;
2955 *val = v;
2956 }
2957 goto return0;
2958 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002959 case XML_SCHEMAS_INTEGER:
2960 case XML_SCHEMAS_PINTEGER:
2961 case XML_SCHEMAS_NPINTEGER:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002962 case XML_SCHEMAS_NINTEGER:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002963 case XML_SCHEMAS_NNINTEGER:{
2964 const xmlChar *cur = value;
2965 unsigned long lo, mi, hi;
William M. Brackec3b4b72005-03-15 15:50:17 +00002966 int sign = 0;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002967
2968 if (cur == NULL)
2969 goto return1;
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00002970 if (normOnTheFly)
2971 while IS_WSP_BLANK_CH(*cur) cur++;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002972 if (*cur == '-') {
2973 sign = 1;
2974 cur++;
2975 } else if (*cur == '+')
2976 cur++;
William M. Brackec3b4b72005-03-15 15:50:17 +00002977 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2978 if (ret == -1)
2979 goto return1;
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00002980 if (normOnTheFly)
2981 while IS_WSP_BLANK_CH(*cur) cur++;
William M. Brackec3b4b72005-03-15 15:50:17 +00002982 if (*cur != 0)
2983 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002984 if (type->builtInType == XML_SCHEMAS_NPINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002985 if ((sign == 0) &&
2986 ((hi != 0) || (mi != 0) || (lo != 0)))
2987 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002988 } else if (type->builtInType == XML_SCHEMAS_PINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002989 if (sign == 1)
2990 goto return1;
2991 if ((hi == 0) && (mi == 0) && (lo == 0))
2992 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002993 } else if (type->builtInType == XML_SCHEMAS_NINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002994 if (sign == 0)
2995 goto return1;
2996 if ((hi == 0) && (mi == 0) && (lo == 0))
2997 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002998 } else if (type->builtInType == XML_SCHEMAS_NNINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002999 if ((sign == 1) &&
3000 ((hi != 0) || (mi != 0) || (lo != 0)))
3001 goto return1;
3002 }
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003003 if (val != NULL) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00003004 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003005 if (v != NULL) {
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00003006 if (ret == 0)
3007 ret++;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003008 v->value.decimal.lo = lo;
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003009 v->value.decimal.mi = mi;
3010 v->value.decimal.hi = hi;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003011 v->value.decimal.sign = sign;
3012 v->value.decimal.frac = 0;
William M. Brackec3b4b72005-03-15 15:50:17 +00003013 v->value.decimal.total = ret;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003014 *val = v;
3015 }
3016 }
3017 goto return0;
3018 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003019 case XML_SCHEMAS_LONG:
3020 case XML_SCHEMAS_BYTE:
3021 case XML_SCHEMAS_SHORT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003022 case XML_SCHEMAS_INT:{
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003023 const xmlChar *cur = value;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003024 unsigned long lo, mi, hi;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003025 int sign = 0;
3026
3027 if (cur == NULL)
3028 goto return1;
3029 if (*cur == '-') {
3030 sign = 1;
3031 cur++;
3032 } else if (*cur == '+')
3033 cur++;
William M. Brackec3b4b72005-03-15 15:50:17 +00003034 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
3035 if (ret < 0)
3036 goto return1;
3037 if (*cur != 0)
3038 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00003039 if (type->builtInType == XML_SCHEMAS_LONG) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003040 if (hi >= 922) {
3041 if (hi > 922)
3042 goto return1;
3043 if (mi >= 33720368) {
3044 if (mi > 33720368)
3045 goto return1;
3046 if ((sign == 0) && (lo > 54775807))
3047 goto return1;
3048 if ((sign == 1) && (lo > 54775808))
3049 goto return1;
3050 }
3051 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00003052 } else if (type->builtInType == XML_SCHEMAS_INT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003053 if (hi != 0)
3054 goto return1;
3055 if (mi >= 21) {
3056 if (mi > 21)
3057 goto return1;
3058 if ((sign == 0) && (lo > 47483647))
3059 goto return1;
3060 if ((sign == 1) && (lo > 47483648))
3061 goto return1;
3062 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00003063 } else if (type->builtInType == XML_SCHEMAS_SHORT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003064 if ((mi != 0) || (hi != 0))
3065 goto return1;
3066 if ((sign == 1) && (lo > 32768))
3067 goto return1;
3068 if ((sign == 0) && (lo > 32767))
3069 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00003070 } else if (type->builtInType == XML_SCHEMAS_BYTE) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003071 if ((mi != 0) || (hi != 0))
3072 goto return1;
3073 if ((sign == 1) && (lo > 128))
3074 goto return1;
3075 if ((sign == 0) && (lo > 127))
3076 goto return1;
3077 }
3078 if (val != NULL) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00003079 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003080 if (v != NULL) {
3081 v->value.decimal.lo = lo;
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003082 v->value.decimal.mi = mi;
3083 v->value.decimal.hi = hi;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003084 v->value.decimal.sign = sign;
3085 v->value.decimal.frac = 0;
William M. Brackec3b4b72005-03-15 15:50:17 +00003086 v->value.decimal.total = ret;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003087 *val = v;
3088 }
3089 }
3090 goto return0;
3091 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003092 case XML_SCHEMAS_UINT:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003093 case XML_SCHEMAS_ULONG:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003094 case XML_SCHEMAS_USHORT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003095 case XML_SCHEMAS_UBYTE:{
3096 const xmlChar *cur = value;
3097 unsigned long lo, mi, hi;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003098
3099 if (cur == NULL)
3100 goto return1;
William M. Brackec3b4b72005-03-15 15:50:17 +00003101 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
3102 if (ret < 0)
3103 goto return1;
3104 if (*cur != 0)
3105 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00003106 if (type->builtInType == XML_SCHEMAS_ULONG) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003107 if (hi >= 1844) {
3108 if (hi > 1844)
3109 goto return1;
3110 if (mi >= 67440737) {
3111 if (mi > 67440737)
3112 goto return1;
3113 if (lo > 9551615)
3114 goto return1;
3115 }
3116 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00003117 } else if (type->builtInType == XML_SCHEMAS_UINT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003118 if (hi != 0)
3119 goto return1;
3120 if (mi >= 42) {
3121 if (mi > 42)
3122 goto return1;
3123 if (lo > 94967295)
3124 goto return1;
3125 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00003126 } else if (type->builtInType == XML_SCHEMAS_USHORT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003127 if ((mi != 0) || (hi != 0))
3128 goto return1;
3129 if (lo > 65535)
3130 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00003131 } else if (type->builtInType == XML_SCHEMAS_UBYTE) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003132 if ((mi != 0) || (hi != 0))
3133 goto return1;
3134 if (lo > 255)
3135 goto return1;
3136 }
3137 if (val != NULL) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00003138 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003139 if (v != NULL) {
3140 v->value.decimal.lo = lo;
3141 v->value.decimal.mi = mi;
3142 v->value.decimal.hi = hi;
3143 v->value.decimal.sign = 0;
3144 v->value.decimal.frac = 0;
William M. Brackec3b4b72005-03-15 15:50:17 +00003145 v->value.decimal.total = ret;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003146 *val = v;
3147 }
3148 }
3149 goto return0;
3150 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003151 }
3152
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003153 done:
3154 if (norm != NULL)
3155 xmlFree(norm);
3156 return (ret);
3157 return3:
3158 if (norm != NULL)
3159 xmlFree(norm);
3160 return (3);
3161 return1:
3162 if (norm != NULL)
3163 xmlFree(norm);
3164 return (1);
3165 return0:
3166 if (norm != NULL)
3167 xmlFree(norm);
3168 return (0);
3169 error:
3170 if (norm != NULL)
3171 xmlFree(norm);
3172 return (-1);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003173}
3174
3175/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00003176 * xmlSchemaValPredefTypeNode:
Daniel Veillard4255d502002-04-16 15:50:10 +00003177 * @type: the predefined type
3178 * @value: the value to check
3179 * @val: the return computed value
Daniel Veillardc3da18a2003-03-18 00:31:04 +00003180 * @node: the node containing the value
Daniel Veillard4255d502002-04-16 15:50:10 +00003181 *
3182 * Check that a value conforms to the lexical space of the predefined type.
3183 * if true a value is computed and returned in @val.
3184 *
3185 * Returns 0 if this validates, a positive error code number otherwise
3186 * and -1 in case of internal or API error.
3187 */
3188int
Daniel Veillardc3da18a2003-03-18 00:31:04 +00003189xmlSchemaValPredefTypeNode(xmlSchemaTypePtr type, const xmlChar *value,
3190 xmlSchemaValPtr *val, xmlNodePtr node) {
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00003191 return(xmlSchemaValAtomicType(type, value, val, node, 0,
3192 XML_SCHEMA_WHITESPACE_UNKNOWN, 1, 1, 0));
Daniel Veillard4255d502002-04-16 15:50:10 +00003193}
3194
3195/**
Daniel Veillardc0826a72004-08-10 14:17:33 +00003196 * xmlSchemaValPredefTypeNodeNoNorm:
3197 * @type: the predefined type
3198 * @value: the value to check
3199 * @val: the return computed value
3200 * @node: the node containing the value
3201 *
3202 * Check that a value conforms to the lexical space of the predefined type.
3203 * if true a value is computed and returned in @val.
3204 * This one does apply any normalization to the value.
3205 *
3206 * Returns 0 if this validates, a positive error code number otherwise
3207 * and -1 in case of internal or API error.
3208 */
3209int
3210xmlSchemaValPredefTypeNodeNoNorm(xmlSchemaTypePtr type, const xmlChar *value,
3211 xmlSchemaValPtr *val, xmlNodePtr node) {
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00003212 return(xmlSchemaValAtomicType(type, value, val, node, 1,
3213 XML_SCHEMA_WHITESPACE_UNKNOWN, 1, 0, 1));
Daniel Veillardc0826a72004-08-10 14:17:33 +00003214}
3215
3216/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00003217 * xmlSchemaValidatePredefinedType:
3218 * @type: the predefined type
3219 * @value: the value to check
3220 * @val: the return computed value
3221 *
3222 * Check that a value conforms to the lexical space of the predefined type.
3223 * if true a value is computed and returned in @val.
3224 *
3225 * Returns 0 if this validates, a positive error code number otherwise
3226 * and -1 in case of internal or API error.
3227 */
3228int
3229xmlSchemaValidatePredefinedType(xmlSchemaTypePtr type, const xmlChar *value,
3230 xmlSchemaValPtr *val) {
3231 return(xmlSchemaValPredefTypeNode(type, value, val, NULL));
3232}
3233
3234/**
Daniel Veillard4255d502002-04-16 15:50:10 +00003235 * xmlSchemaCompareDecimals:
3236 * @x: a first decimal value
3237 * @y: a second decimal value
3238 *
3239 * Compare 2 decimals
3240 *
3241 * Returns -1 if x < y, 0 if x == y, 1 if x > y and -2 in case of error
3242 */
3243static int
3244xmlSchemaCompareDecimals(xmlSchemaValPtr x, xmlSchemaValPtr y)
3245{
3246 xmlSchemaValPtr swp;
William M. Brack273670f2005-03-11 15:55:14 +00003247 int order = 1, integx, integy, dlen;
3248 unsigned long hi, mi, lo;
Daniel Veillard4255d502002-04-16 15:50:10 +00003249
William M. Brack273670f2005-03-11 15:55:14 +00003250 /*
3251 * First test: If x is -ve and not zero
3252 */
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003253 if ((x->value.decimal.sign) &&
3254 ((x->value.decimal.lo != 0) ||
3255 (x->value.decimal.mi != 0) ||
3256 (x->value.decimal.hi != 0))) {
William M. Brack273670f2005-03-11 15:55:14 +00003257 /*
3258 * Then if y is -ve and not zero reverse the compare
3259 */
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003260 if ((y->value.decimal.sign) &&
3261 ((y->value.decimal.lo != 0) ||
3262 (y->value.decimal.mi != 0) ||
3263 (y->value.decimal.hi != 0)))
Daniel Veillard80b19092003-03-28 13:29:53 +00003264 order = -1;
William M. Brack273670f2005-03-11 15:55:14 +00003265 /*
3266 * Otherwise (y >= 0) we have the answer
3267 */
Daniel Veillard80b19092003-03-28 13:29:53 +00003268 else
3269 return (-1);
William M. Brack273670f2005-03-11 15:55:14 +00003270 /*
3271 * If x is not -ve and y is -ve we have the answer
3272 */
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003273 } else if ((y->value.decimal.sign) &&
3274 ((y->value.decimal.lo != 0) ||
3275 (y->value.decimal.mi != 0) ||
3276 (y->value.decimal.hi != 0))) {
Daniel Veillard4255d502002-04-16 15:50:10 +00003277 return (1);
Daniel Veillard80b19092003-03-28 13:29:53 +00003278 }
William M. Brack273670f2005-03-11 15:55:14 +00003279 /*
3280 * If it's not simply determined by a difference in sign,
3281 * then we need to compare the actual values of the two nums.
3282 * To do this, we start by looking at the integral parts.
3283 * If the number of integral digits differ, then we have our
3284 * answer.
3285 */
3286 integx = x->value.decimal.total - x->value.decimal.frac;
3287 integy = y->value.decimal.total - y->value.decimal.frac;
3288 if (integx > integy)
3289 return order;
3290 else if (integy > integx)
3291 return -order;
3292 /*
3293 * If the number of integral digits is the same for both numbers,
3294 * then things get a little more complicated. We need to "normalize"
3295 * the numbers in order to properly compare them. To do this, we
3296 * look at the total length of each number (length => number of
3297 * significant digits), and divide the "shorter" by 10 (decreasing
3298 * the length) until they are of equal length.
3299 */
3300 dlen = x->value.decimal.total - y->value.decimal.total;
3301 if (dlen < 0) { /* y has more digits than x */
3302 swp = x;
3303 hi = y->value.decimal.hi;
3304 mi = y->value.decimal.mi;
3305 lo = y->value.decimal.lo;
3306 dlen = -dlen;
3307 order = -order;
3308 } else { /* x has more digits than y */
3309 swp = y;
3310 hi = x->value.decimal.hi;
3311 mi = x->value.decimal.mi;
3312 lo = x->value.decimal.lo;
Daniel Veillard4255d502002-04-16 15:50:10 +00003313 }
William M. Brack273670f2005-03-11 15:55:14 +00003314 while (dlen > 8) { /* in effect, right shift by 10**8 */
3315 lo = mi;
3316 mi = hi;
3317 hi = 0;
3318 dlen -= 8;
Daniel Veillard4255d502002-04-16 15:50:10 +00003319 }
William M. Brack273670f2005-03-11 15:55:14 +00003320 while (dlen > 0) {
3321 unsigned long rem1, rem2;
3322 rem1 = (hi % 10) * 100000000L;
3323 hi = hi / 10;
3324 rem2 = (mi % 10) * 100000000L;
3325 mi = (mi + rem1) / 10;
3326 lo = (lo + rem2) / 10;
3327 dlen--;
3328 }
3329 if (hi > swp->value.decimal.hi) {
3330 return order;
3331 } else if (hi == swp->value.decimal.hi) {
3332 if (mi > swp->value.decimal.mi) {
3333 return order;
3334 } else if (mi == swp->value.decimal.mi) {
3335 if (lo > swp->value.decimal.lo) {
3336 return order;
3337 } else if (lo == swp->value.decimal.lo) {
3338 if (x->value.decimal.total == y->value.decimal.total) {
3339 return 0;
3340 } else {
3341 return order;
3342 }
3343 }
3344 }
3345 }
3346 return -order;
Daniel Veillard4255d502002-04-16 15:50:10 +00003347}
3348
3349/**
Daniel Veillard070803b2002-05-03 07:29:38 +00003350 * xmlSchemaCompareDurations:
3351 * @x: a first duration value
3352 * @y: a second duration value
3353 *
3354 * Compare 2 durations
3355 *
3356 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3357 * case of error
3358 */
3359static int
3360xmlSchemaCompareDurations(xmlSchemaValPtr x, xmlSchemaValPtr y)
3361{
3362 long carry, mon, day;
3363 double sec;
Daniel Veillard80b19092003-03-28 13:29:53 +00003364 int invert = 1;
3365 long xmon, xday, myear, minday, maxday;
Daniel Veillard070803b2002-05-03 07:29:38 +00003366 static const long dayRange [2][12] = {
3367 { 0, 28, 59, 89, 120, 150, 181, 212, 242, 273, 303, 334, },
3368 { 0, 31, 62, 92, 123, 153, 184, 215, 245, 276, 306, 337} };
3369
3370 if ((x == NULL) || (y == NULL))
Daniel Veillard5a872412002-05-22 06:40:27 +00003371 return -2;
Daniel Veillard070803b2002-05-03 07:29:38 +00003372
3373 /* months */
3374 mon = x->value.dur.mon - y->value.dur.mon;
3375
3376 /* seconds */
3377 sec = x->value.dur.sec - y->value.dur.sec;
3378 carry = (long)sec / SECS_PER_DAY;
3379 sec -= (double)(carry * SECS_PER_DAY);
3380
3381 /* days */
3382 day = x->value.dur.day - y->value.dur.day + carry;
3383
3384 /* easy test */
3385 if (mon == 0) {
3386 if (day == 0)
3387 if (sec == 0.0)
3388 return 0;
3389 else if (sec < 0.0)
3390 return -1;
3391 else
3392 return 1;
3393 else if (day < 0)
3394 return -1;
3395 else
3396 return 1;
3397 }
3398
3399 if (mon > 0) {
3400 if ((day >= 0) && (sec >= 0.0))
3401 return 1;
3402 else {
3403 xmon = mon;
3404 xday = -day;
3405 }
3406 } else if ((day <= 0) && (sec <= 0.0)) {
3407 return -1;
3408 } else {
Daniel Veillard80b19092003-03-28 13:29:53 +00003409 invert = -1;
Daniel Veillard070803b2002-05-03 07:29:38 +00003410 xmon = -mon;
3411 xday = day;
3412 }
3413
3414 myear = xmon / 12;
Daniel Veillard80b19092003-03-28 13:29:53 +00003415 if (myear == 0) {
3416 minday = 0;
3417 maxday = 0;
3418 } else {
3419 maxday = 366 * ((myear + 3) / 4) +
3420 365 * ((myear - 1) % 4);
3421 minday = maxday - 1;
3422 }
3423
Daniel Veillard070803b2002-05-03 07:29:38 +00003424 xmon = xmon % 12;
3425 minday += dayRange[0][xmon];
3426 maxday += dayRange[1][xmon];
3427
Daniel Veillard80b19092003-03-28 13:29:53 +00003428 if ((maxday == minday) && (maxday == xday))
3429 return(0); /* can this really happen ? */
Daniel Veillard070803b2002-05-03 07:29:38 +00003430 if (maxday < xday)
Daniel Veillard80b19092003-03-28 13:29:53 +00003431 return(-invert);
3432 if (minday > xday)
3433 return(invert);
Daniel Veillard070803b2002-05-03 07:29:38 +00003434
3435 /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00003436 return 2;
3437}
3438
3439/*
3440 * macros for adding date/times and durations
3441 */
3442#define FQUOTIENT(a,b) (floor(((double)a/(double)b)))
3443#define MODULO(a,b) (a - FQUOTIENT(a,b) * b)
3444#define FQUOTIENT_RANGE(a,low,high) (FQUOTIENT((a-low),(high-low)))
3445#define MODULO_RANGE(a,low,high) ((MODULO((a-low),(high-low)))+low)
3446
3447/**
Daniel Veillard669adfc2004-05-29 20:12:46 +00003448 * xmlSchemaDupVal:
3449 * @v: the #xmlSchemaValPtr value to duplicate
3450 *
3451 * Makes a copy of @v. The calling program is responsible for freeing
3452 * the returned value.
3453 *
3454 * returns a pointer to a duplicated #xmlSchemaValPtr or NULL if error.
3455 */
3456static xmlSchemaValPtr
3457xmlSchemaDupVal (xmlSchemaValPtr v)
3458{
3459 xmlSchemaValPtr ret = xmlSchemaNewValue(v->type);
3460 if (ret == NULL)
3461 return NULL;
3462
3463 memcpy(ret, v, sizeof(xmlSchemaVal));
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00003464 ret->next = NULL;
Daniel Veillard669adfc2004-05-29 20:12:46 +00003465 return ret;
3466}
3467
3468/**
Kasimier T. Buchcik285ebab2005-03-04 18:04:59 +00003469 * xmlSchemaCopyValue:
3470 * @val: the precomputed value to be copied
3471 *
3472 * Copies the precomputed value. This duplicates any string within.
3473 *
3474 * Returns the copy or NULL if a copy for a data-type is not implemented.
3475 */
3476xmlSchemaValPtr
3477xmlSchemaCopyValue(xmlSchemaValPtr val)
3478{
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00003479 xmlSchemaValPtr ret = NULL, prev = NULL, cur;
Kasimier T. Buchcik285ebab2005-03-04 18:04:59 +00003480
Kasimier T. Buchcik285ebab2005-03-04 18:04:59 +00003481 /*
3482 * Copy the string values.
3483 */
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00003484 while (val != NULL) {
3485 switch (val->type) {
3486 case XML_SCHEMAS_ANYTYPE:
3487 case XML_SCHEMAS_IDREFS:
3488 case XML_SCHEMAS_ENTITIES:
3489 case XML_SCHEMAS_NMTOKENS:
3490 xmlSchemaFreeValue(ret);
3491 return (NULL);
3492 case XML_SCHEMAS_ANYSIMPLETYPE:
3493 case XML_SCHEMAS_STRING:
3494 case XML_SCHEMAS_NORMSTRING:
3495 case XML_SCHEMAS_TOKEN:
3496 case XML_SCHEMAS_LANGUAGE:
3497 case XML_SCHEMAS_NAME:
3498 case XML_SCHEMAS_NCNAME:
3499 case XML_SCHEMAS_ID:
3500 case XML_SCHEMAS_IDREF:
3501 case XML_SCHEMAS_ENTITY:
3502 case XML_SCHEMAS_NMTOKEN:
3503 case XML_SCHEMAS_ANYURI:
3504 cur = xmlSchemaDupVal(val);
3505 if (val->value.str != NULL)
3506 cur->value.str = xmlStrdup(BAD_CAST val->value.str);
3507 break;
3508 case XML_SCHEMAS_QNAME:
3509 case XML_SCHEMAS_NOTATION:
3510 cur = xmlSchemaDupVal(val);
3511 if (val->value.qname.name != NULL)
3512 cur->value.qname.name =
Kasimier T. Buchcik285ebab2005-03-04 18:04:59 +00003513 xmlStrdup(BAD_CAST val->value.qname.name);
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00003514 if (val->value.qname.uri != NULL)
3515 cur->value.qname.uri =
Kasimier T. Buchcik285ebab2005-03-04 18:04:59 +00003516 xmlStrdup(BAD_CAST val->value.qname.uri);
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00003517 break;
3518 case XML_SCHEMAS_HEXBINARY:
3519 cur = xmlSchemaDupVal(val);
3520 if (val->value.hex.str != NULL)
3521 cur->value.hex.str = xmlStrdup(BAD_CAST val->value.hex.str);
3522 break;
3523 case XML_SCHEMAS_BASE64BINARY:
3524 cur = xmlSchemaDupVal(val);
3525 if (val->value.base64.str != NULL)
3526 cur->value.base64.str =
Kasimier T. Buchcik285ebab2005-03-04 18:04:59 +00003527 xmlStrdup(BAD_CAST val->value.base64.str);
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00003528 break;
3529 default:
3530 cur = xmlSchemaDupVal(val);
3531 break;
3532 }
3533 if (ret == NULL)
3534 ret = cur;
3535 else
3536 prev->next = cur;
3537 prev = cur;
3538 val = val->next;
Kasimier T. Buchcik285ebab2005-03-04 18:04:59 +00003539 }
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00003540 return (ret);
Kasimier T. Buchcik285ebab2005-03-04 18:04:59 +00003541}
3542
3543/**
Daniel Veillard5a872412002-05-22 06:40:27 +00003544 * _xmlSchemaDateAdd:
3545 * @dt: an #xmlSchemaValPtr
3546 * @dur: an #xmlSchemaValPtr of type #XS_DURATION
3547 *
3548 * Compute a new date/time from @dt and @dur. This function assumes @dt
3549 * is either #XML_SCHEMAS_DATETIME, #XML_SCHEMAS_DATE, #XML_SCHEMAS_GYEARMONTH,
Daniel Veillard669adfc2004-05-29 20:12:46 +00003550 * or #XML_SCHEMAS_GYEAR. The returned #xmlSchemaVal is the same type as
3551 * @dt. The calling program is responsible for freeing the returned value.
Daniel Veillard5a872412002-05-22 06:40:27 +00003552 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00003553 * Returns a pointer to a new #xmlSchemaVal or NULL if error.
Daniel Veillard5a872412002-05-22 06:40:27 +00003554 */
3555static xmlSchemaValPtr
3556_xmlSchemaDateAdd (xmlSchemaValPtr dt, xmlSchemaValPtr dur)
3557{
Daniel Veillard669adfc2004-05-29 20:12:46 +00003558 xmlSchemaValPtr ret, tmp;
Daniel Veillard5a872412002-05-22 06:40:27 +00003559 long carry, tempdays, temp;
3560 xmlSchemaValDatePtr r, d;
3561 xmlSchemaValDurationPtr u;
3562
3563 if ((dt == NULL) || (dur == NULL))
3564 return NULL;
3565
3566 ret = xmlSchemaNewValue(dt->type);
3567 if (ret == NULL)
3568 return NULL;
3569
Daniel Veillard669adfc2004-05-29 20:12:46 +00003570 /* make a copy so we don't alter the original value */
3571 tmp = xmlSchemaDupVal(dt);
3572 if (tmp == NULL) {
3573 xmlSchemaFreeValue(ret);
3574 return NULL;
3575 }
3576
Daniel Veillard5a872412002-05-22 06:40:27 +00003577 r = &(ret->value.date);
Daniel Veillard669adfc2004-05-29 20:12:46 +00003578 d = &(tmp->value.date);
Daniel Veillard5a872412002-05-22 06:40:27 +00003579 u = &(dur->value.dur);
3580
3581 /* normalization */
3582 if (d->mon == 0)
3583 d->mon = 1;
3584
3585 /* normalize for time zone offset */
3586 u->sec -= (d->tzo * 60);
3587 d->tzo = 0;
3588
3589 /* normalization */
3590 if (d->day == 0)
3591 d->day = 1;
3592
3593 /* month */
3594 carry = d->mon + u->mon;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003595 r->mon = (unsigned int) MODULO_RANGE(carry, 1, 13);
3596 carry = (long) FQUOTIENT_RANGE(carry, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00003597
3598 /* year (may be modified later) */
3599 r->year = d->year + carry;
3600 if (r->year == 0) {
3601 if (d->year > 0)
3602 r->year--;
3603 else
3604 r->year++;
3605 }
3606
3607 /* time zone */
3608 r->tzo = d->tzo;
3609 r->tz_flag = d->tz_flag;
3610
3611 /* seconds */
3612 r->sec = d->sec + u->sec;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003613 carry = (long) FQUOTIENT((long)r->sec, 60);
Daniel Veillard5a872412002-05-22 06:40:27 +00003614 if (r->sec != 0.0) {
3615 r->sec = MODULO(r->sec, 60.0);
3616 }
3617
3618 /* minute */
3619 carry += d->min;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003620 r->min = (unsigned int) MODULO(carry, 60);
3621 carry = (long) FQUOTIENT(carry, 60);
Daniel Veillard5a872412002-05-22 06:40:27 +00003622
3623 /* hours */
3624 carry += d->hour;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003625 r->hour = (unsigned int) MODULO(carry, 24);
3626 carry = (long)FQUOTIENT(carry, 24);
Daniel Veillard5a872412002-05-22 06:40:27 +00003627
3628 /*
3629 * days
3630 * Note we use tempdays because the temporary values may need more
3631 * than 5 bits
3632 */
3633 if ((VALID_YEAR(r->year)) && (VALID_MONTH(r->mon)) &&
3634 (d->day > MAX_DAYINMONTH(r->year, r->mon)))
3635 tempdays = MAX_DAYINMONTH(r->year, r->mon);
3636 else if (d->day < 1)
3637 tempdays = 1;
3638 else
3639 tempdays = d->day;
3640
3641 tempdays += u->day + carry;
3642
3643 while (1) {
3644 if (tempdays < 1) {
Daniel Veillardebe25d42004-03-25 09:35:49 +00003645 long tmon = (long) MODULO_RANGE(r->mon-1, 1, 13);
3646 long tyr = r->year + (long)FQUOTIENT_RANGE(r->mon-1, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00003647 if (tyr == 0)
3648 tyr--;
3649 tempdays += MAX_DAYINMONTH(tyr, tmon);
3650 carry = -1;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003651 } else if (tempdays > (long) MAX_DAYINMONTH(r->year, r->mon)) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003652 tempdays = tempdays - MAX_DAYINMONTH(r->year, r->mon);
3653 carry = 1;
3654 } else
3655 break;
3656
3657 temp = r->mon + carry;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003658 r->mon = (unsigned int) MODULO_RANGE(temp, 1, 13);
3659 r->year = r->year + (unsigned int) FQUOTIENT_RANGE(temp, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00003660 if (r->year == 0) {
3661 if (temp < 1)
3662 r->year--;
3663 else
3664 r->year++;
3665 }
3666 }
3667
3668 r->day = tempdays;
3669
3670 /*
3671 * adjust the date/time type to the date values
3672 */
3673 if (ret->type != XML_SCHEMAS_DATETIME) {
3674 if ((r->hour) || (r->min) || (r->sec))
3675 ret->type = XML_SCHEMAS_DATETIME;
3676 else if (ret->type != XML_SCHEMAS_DATE) {
3677 if ((r->mon != 1) && (r->day != 1))
3678 ret->type = XML_SCHEMAS_DATE;
3679 else if ((ret->type != XML_SCHEMAS_GYEARMONTH) && (r->mon != 1))
3680 ret->type = XML_SCHEMAS_GYEARMONTH;
3681 }
3682 }
3683
Daniel Veillard669adfc2004-05-29 20:12:46 +00003684 xmlSchemaFreeValue(tmp);
Daniel Veillard5a872412002-05-22 06:40:27 +00003685
Daniel Veillard5a872412002-05-22 06:40:27 +00003686 return ret;
3687}
3688
3689/**
3690 * xmlSchemaDateNormalize:
Daniel Veillard669adfc2004-05-29 20:12:46 +00003691 * @dt: an #xmlSchemaValPtr of a date/time type value.
3692 * @offset: number of seconds to adjust @dt by.
Daniel Veillard5a872412002-05-22 06:40:27 +00003693 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00003694 * Normalize @dt to GMT time. The @offset parameter is subtracted from
3695 * the return value is a time-zone offset is present on @dt.
Daniel Veillard5a872412002-05-22 06:40:27 +00003696 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00003697 * Returns a normalized copy of @dt or NULL if error.
Daniel Veillard5a872412002-05-22 06:40:27 +00003698 */
3699static xmlSchemaValPtr
3700xmlSchemaDateNormalize (xmlSchemaValPtr dt, double offset)
3701{
3702 xmlSchemaValPtr dur, ret;
3703
3704 if (dt == NULL)
3705 return NULL;
3706
3707 if (((dt->type != XML_SCHEMAS_TIME) &&
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00003708 (dt->type != XML_SCHEMAS_DATETIME) &&
3709 (dt->type != XML_SCHEMAS_DATE)) || (dt->value.date.tzo == 0))
Daniel Veillard5a872412002-05-22 06:40:27 +00003710 return xmlSchemaDupVal(dt);
3711
3712 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
3713 if (dur == NULL)
3714 return NULL;
3715
3716 dur->value.date.sec -= offset;
3717
3718 ret = _xmlSchemaDateAdd(dt, dur);
3719 if (ret == NULL)
3720 return NULL;
3721
3722 xmlSchemaFreeValue(dur);
3723
3724 /* ret->value.date.tzo = 0; */
3725 return ret;
3726}
3727
3728/**
3729 * _xmlSchemaDateCastYMToDays:
3730 * @dt: an #xmlSchemaValPtr
3731 *
3732 * Convert mon and year of @dt to total number of days. Take the
3733 * number of years since (or before) 1 AD and add the number of leap
3734 * years. This is a function because negative
3735 * years must be handled a little differently and there is no zero year.
3736 *
3737 * Returns number of days.
3738 */
3739static long
3740_xmlSchemaDateCastYMToDays (const xmlSchemaValPtr dt)
3741{
3742 long ret;
Daniel Veillard49e89632004-09-23 16:24:36 +00003743 int mon;
Daniel Veillard5a872412002-05-22 06:40:27 +00003744
Daniel Veillard49e89632004-09-23 16:24:36 +00003745 mon = dt->value.date.mon;
3746 if (mon <= 0) mon = 1; /* normalization */
3747
3748 if (dt->value.date.year <= 0)
Daniel Veillard5a872412002-05-22 06:40:27 +00003749 ret = (dt->value.date.year * 365) +
3750 (((dt->value.date.year+1)/4)-((dt->value.date.year+1)/100)+
3751 ((dt->value.date.year+1)/400)) +
Daniel Veillard49e89632004-09-23 16:24:36 +00003752 DAY_IN_YEAR(0, mon, dt->value.date.year);
Daniel Veillard5a872412002-05-22 06:40:27 +00003753 else
3754 ret = ((dt->value.date.year-1) * 365) +
3755 (((dt->value.date.year-1)/4)-((dt->value.date.year-1)/100)+
3756 ((dt->value.date.year-1)/400)) +
Daniel Veillard49e89632004-09-23 16:24:36 +00003757 DAY_IN_YEAR(0, mon, dt->value.date.year);
Daniel Veillard5a872412002-05-22 06:40:27 +00003758
3759 return ret;
3760}
3761
3762/**
3763 * TIME_TO_NUMBER:
3764 * @dt: an #xmlSchemaValPtr
3765 *
3766 * Calculates the number of seconds in the time portion of @dt.
3767 *
3768 * Returns seconds.
3769 */
3770#define TIME_TO_NUMBER(dt) \
3771 ((double)((dt->value.date.hour * SECS_PER_HOUR) + \
Daniel Veillardb3721c22003-03-31 11:22:25 +00003772 (dt->value.date.min * SECS_PER_MIN) + \
3773 (dt->value.date.tzo * SECS_PER_MIN)) + \
3774 dt->value.date.sec)
Daniel Veillard5a872412002-05-22 06:40:27 +00003775
3776/**
3777 * xmlSchemaCompareDates:
3778 * @x: a first date/time value
3779 * @y: a second date/time value
3780 *
3781 * Compare 2 date/times
3782 *
3783 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3784 * case of error
3785 */
3786static int
3787xmlSchemaCompareDates (xmlSchemaValPtr x, xmlSchemaValPtr y)
3788{
3789 unsigned char xmask, ymask, xor_mask, and_mask;
3790 xmlSchemaValPtr p1, p2, q1, q2;
3791 long p1d, p2d, q1d, q2d;
3792
3793 if ((x == NULL) || (y == NULL))
3794 return -2;
3795
3796 if (x->value.date.tz_flag) {
3797
3798 if (!y->value.date.tz_flag) {
3799 p1 = xmlSchemaDateNormalize(x, 0);
3800 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3801 /* normalize y + 14:00 */
3802 q1 = xmlSchemaDateNormalize(y, (14 * SECS_PER_HOUR));
3803
3804 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003805 if (p1d < q1d) {
3806 xmlSchemaFreeValue(p1);
3807 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003808 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003809 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003810 double sec;
3811
3812 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00003813 if (sec < 0.0) {
3814 xmlSchemaFreeValue(p1);
3815 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003816 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003817 } else {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003818 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003819 /* normalize y - 14:00 */
3820 q2 = xmlSchemaDateNormalize(y, -(14 * SECS_PER_HOUR));
3821 q2d = _xmlSchemaDateCastYMToDays(q2) + q2->value.date.day;
3822 if (p1d > q2d)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003823 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003824 else if (p1d == q2d) {
3825 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q2);
3826 if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003827 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003828 else
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003829 ret = 2; /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00003830 }
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003831 xmlSchemaFreeValue(p1);
3832 xmlSchemaFreeValue(q1);
3833 xmlSchemaFreeValue(q2);
3834 if (ret != 0)
3835 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003836 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00003837 } else {
3838 xmlSchemaFreeValue(p1);
3839 xmlSchemaFreeValue(q1);
3840 }
Daniel Veillard5a872412002-05-22 06:40:27 +00003841 }
3842 } else if (y->value.date.tz_flag) {
3843 q1 = xmlSchemaDateNormalize(y, 0);
3844 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
3845
3846 /* normalize x - 14:00 */
3847 p1 = xmlSchemaDateNormalize(x, -(14 * SECS_PER_HOUR));
3848 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3849
Daniel Veillardfdc91562002-07-01 21:52:03 +00003850 if (p1d < q1d) {
3851 xmlSchemaFreeValue(p1);
3852 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003853 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003854 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003855 double sec;
3856
3857 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00003858 if (sec < 0.0) {
3859 xmlSchemaFreeValue(p1);
3860 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003861 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003862 } else {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003863 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003864 /* normalize x + 14:00 */
3865 p2 = xmlSchemaDateNormalize(x, (14 * SECS_PER_HOUR));
3866 p2d = _xmlSchemaDateCastYMToDays(p2) + p2->value.date.day;
3867
Daniel Veillard6560a422003-03-27 21:25:38 +00003868 if (p2d > q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003869 ret = 1;
Daniel Veillard6560a422003-03-27 21:25:38 +00003870 } else if (p2d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003871 sec = TIME_TO_NUMBER(p2) - TIME_TO_NUMBER(q1);
3872 if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003873 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003874 else
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003875 ret = 2; /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00003876 }
Daniel Veillard6560a422003-03-27 21:25:38 +00003877 xmlSchemaFreeValue(p1);
3878 xmlSchemaFreeValue(q1);
3879 xmlSchemaFreeValue(p2);
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003880 if (ret != 0)
3881 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003882 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00003883 } else {
3884 xmlSchemaFreeValue(p1);
3885 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003886 }
3887 }
3888
3889 /*
3890 * if the same type then calculate the difference
3891 */
3892 if (x->type == y->type) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003893 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003894 q1 = xmlSchemaDateNormalize(y, 0);
3895 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
3896
3897 p1 = xmlSchemaDateNormalize(x, 0);
3898 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3899
Daniel Veillardfdc91562002-07-01 21:52:03 +00003900 if (p1d < q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003901 ret = -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003902 } else if (p1d > q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003903 ret = 1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003904 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00003905 double sec;
3906
3907 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
3908 if (sec < 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003909 ret = -1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003910 else if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003911 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003912
3913 }
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003914 xmlSchemaFreeValue(p1);
3915 xmlSchemaFreeValue(q1);
3916 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003917 }
3918
3919 switch (x->type) {
3920 case XML_SCHEMAS_DATETIME:
3921 xmask = 0xf;
3922 break;
3923 case XML_SCHEMAS_DATE:
3924 xmask = 0x7;
3925 break;
3926 case XML_SCHEMAS_GYEAR:
3927 xmask = 0x1;
3928 break;
3929 case XML_SCHEMAS_GMONTH:
3930 xmask = 0x2;
3931 break;
3932 case XML_SCHEMAS_GDAY:
3933 xmask = 0x3;
3934 break;
3935 case XML_SCHEMAS_GYEARMONTH:
3936 xmask = 0x3;
3937 break;
3938 case XML_SCHEMAS_GMONTHDAY:
3939 xmask = 0x6;
3940 break;
3941 case XML_SCHEMAS_TIME:
3942 xmask = 0x8;
3943 break;
3944 default:
3945 xmask = 0;
3946 break;
3947 }
3948
3949 switch (y->type) {
3950 case XML_SCHEMAS_DATETIME:
3951 ymask = 0xf;
3952 break;
3953 case XML_SCHEMAS_DATE:
3954 ymask = 0x7;
3955 break;
3956 case XML_SCHEMAS_GYEAR:
3957 ymask = 0x1;
3958 break;
3959 case XML_SCHEMAS_GMONTH:
3960 ymask = 0x2;
3961 break;
3962 case XML_SCHEMAS_GDAY:
3963 ymask = 0x3;
3964 break;
3965 case XML_SCHEMAS_GYEARMONTH:
3966 ymask = 0x3;
3967 break;
3968 case XML_SCHEMAS_GMONTHDAY:
3969 ymask = 0x6;
3970 break;
3971 case XML_SCHEMAS_TIME:
3972 ymask = 0x8;
3973 break;
3974 default:
3975 ymask = 0;
3976 break;
3977 }
3978
3979 xor_mask = xmask ^ ymask; /* mark type differences */
3980 and_mask = xmask & ymask; /* mark field specification */
3981
3982 /* year */
3983 if (xor_mask & 1)
3984 return 2; /* indeterminate */
3985 else if (and_mask & 1) {
3986 if (x->value.date.year < y->value.date.year)
3987 return -1;
3988 else if (x->value.date.year > y->value.date.year)
3989 return 1;
3990 }
3991
3992 /* month */
3993 if (xor_mask & 2)
3994 return 2; /* indeterminate */
3995 else if (and_mask & 2) {
3996 if (x->value.date.mon < y->value.date.mon)
3997 return -1;
3998 else if (x->value.date.mon > y->value.date.mon)
3999 return 1;
4000 }
4001
4002 /* day */
4003 if (xor_mask & 4)
4004 return 2; /* indeterminate */
4005 else if (and_mask & 4) {
4006 if (x->value.date.day < y->value.date.day)
4007 return -1;
4008 else if (x->value.date.day > y->value.date.day)
4009 return 1;
4010 }
4011
4012 /* time */
4013 if (xor_mask & 8)
4014 return 2; /* indeterminate */
4015 else if (and_mask & 8) {
4016 if (x->value.date.hour < y->value.date.hour)
4017 return -1;
4018 else if (x->value.date.hour > y->value.date.hour)
4019 return 1;
4020 else if (x->value.date.min < y->value.date.min)
4021 return -1;
4022 else if (x->value.date.min > y->value.date.min)
4023 return 1;
4024 else if (x->value.date.sec < y->value.date.sec)
4025 return -1;
4026 else if (x->value.date.sec > y->value.date.sec)
4027 return 1;
4028 }
4029
Daniel Veillard070803b2002-05-03 07:29:38 +00004030 return 0;
4031}
4032
4033/**
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004034 * xmlSchemaComparePreserveReplaceStrings:
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004035 * @x: a first string value
4036 * @y: a second string value
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004037 * @invert: inverts the result if x < y or x > y.
4038 *
4039 * Compare 2 string for their normalized values.
4040 * @x is a string with whitespace of "preserve", @y is
4041 * a string with a whitespace of "replace". I.e. @x could
4042 * be an "xsd:string" and @y an "xsd:normalizedString".
4043 *
4044 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
4045 * case of error
4046 */
4047static int
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004048xmlSchemaComparePreserveReplaceStrings(const xmlChar *x,
4049 const xmlChar *y,
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004050 int invert)
4051{
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004052 int tmp;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004053
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004054 while ((*x != 0) && (*y != 0)) {
4055 if (IS_WSP_REPLACE_CH(*y)) {
4056 if (! IS_WSP_SPACE_CH(*x)) {
4057 if ((*x - 0x20) < 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004058 if (invert)
4059 return(1);
4060 else
4061 return(-1);
4062 } else {
4063 if (invert)
4064 return(-1);
4065 else
4066 return(1);
4067 }
4068 }
4069 } else {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004070 tmp = *x - *y;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004071 if (tmp < 0) {
4072 if (invert)
4073 return(1);
4074 else
4075 return(-1);
4076 }
4077 if (tmp > 0) {
4078 if (invert)
4079 return(-1);
4080 else
4081 return(1);
4082 }
4083 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004084 x++;
4085 y++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004086 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004087 if (*x != 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004088 if (invert)
4089 return(-1);
4090 else
4091 return(1);
4092 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004093 if (*y != 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004094 if (invert)
4095 return(1);
4096 else
4097 return(-1);
4098 }
4099 return(0);
4100}
4101
4102/**
4103 * xmlSchemaComparePreserveCollapseStrings:
4104 * @x: a first string value
4105 * @y: a second string value
4106 *
4107 * Compare 2 string for their normalized values.
4108 * @x is a string with whitespace of "preserve", @y is
4109 * a string with a whitespace of "collapse". I.e. @x could
4110 * be an "xsd:string" and @y an "xsd:normalizedString".
4111 *
4112 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
4113 * case of error
4114 */
4115static int
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004116xmlSchemaComparePreserveCollapseStrings(const xmlChar *x,
4117 const xmlChar *y,
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004118 int invert)
4119{
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004120 int tmp;
4121
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004122 /*
4123 * Skip leading blank chars of the collapsed string.
4124 */
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004125 while IS_WSP_BLANK_CH(*y)
4126 y++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004127
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004128 while ((*x != 0) && (*y != 0)) {
4129 if IS_WSP_BLANK_CH(*y) {
4130 if (! IS_WSP_SPACE_CH(*x)) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004131 /*
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004132 * The yv character would have been replaced to 0x20.
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004133 */
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004134 if ((*x - 0x20) < 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004135 if (invert)
4136 return(1);
4137 else
4138 return(-1);
4139 } else {
4140 if (invert)
4141 return(-1);
4142 else
4143 return(1);
4144 }
4145 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004146 x++;
4147 y++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004148 /*
4149 * Skip contiguous blank chars of the collapsed string.
4150 */
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004151 while IS_WSP_BLANK_CH(*y)
4152 y++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004153 } else {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004154 tmp = *x++ - *y++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004155 if (tmp < 0) {
4156 if (invert)
4157 return(1);
4158 else
4159 return(-1);
4160 }
4161 if (tmp > 0) {
4162 if (invert)
4163 return(-1);
4164 else
4165 return(1);
4166 }
4167 }
4168 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004169 if (*x != 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004170 if (invert)
4171 return(-1);
4172 else
4173 return(1);
4174 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004175 if (*y != 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004176 /*
4177 * Skip trailing blank chars of the collapsed string.
4178 */
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004179 while IS_WSP_BLANK_CH(*y)
4180 y++;
4181 if (*y != 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004182 if (invert)
4183 return(1);
4184 else
4185 return(-1);
4186 }
4187 }
4188 return(0);
4189}
4190
4191/**
4192 * xmlSchemaComparePreserveCollapseStrings:
4193 * @x: a first string value
4194 * @y: a second string value
4195 *
4196 * Compare 2 string for their normalized values.
4197 * @x is a string with whitespace of "preserve", @y is
4198 * a string with a whitespace of "collapse". I.e. @x could
4199 * be an "xsd:string" and @y an "xsd:normalizedString".
4200 *
4201 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
4202 * case of error
4203 */
4204static int
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004205xmlSchemaCompareReplaceCollapseStrings(const xmlChar *x,
4206 const xmlChar *y,
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004207 int invert)
4208{
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004209 int tmp;
4210
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004211 /*
4212 * Skip leading blank chars of the collapsed string.
4213 */
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004214 while IS_WSP_BLANK_CH(*y)
4215 y++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004216
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004217 while ((*x != 0) && (*y != 0)) {
4218 if IS_WSP_BLANK_CH(*y) {
4219 if (! IS_WSP_BLANK_CH(*x)) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004220 /*
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004221 * The yv character would have been replaced to 0x20.
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004222 */
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004223 if ((*x - 0x20) < 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004224 if (invert)
4225 return(1);
4226 else
4227 return(-1);
4228 } else {
4229 if (invert)
4230 return(-1);
4231 else
4232 return(1);
4233 }
4234 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004235 x++;
4236 y++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004237 /*
4238 * Skip contiguous blank chars of the collapsed string.
4239 */
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004240 while IS_WSP_BLANK_CH(*y)
4241 y++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004242 } else {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004243 if IS_WSP_BLANK_CH(*x) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004244 /*
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004245 * The xv character would have been replaced to 0x20.
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004246 */
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004247 if ((0x20 - *y) < 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004248 if (invert)
4249 return(1);
4250 else
4251 return(-1);
4252 } else {
4253 if (invert)
4254 return(-1);
4255 else
4256 return(1);
4257 }
4258 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004259 tmp = *x++ - *y++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004260 if (tmp < 0)
4261 return(-1);
4262 if (tmp > 0)
4263 return(1);
4264 }
4265 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004266 if (*x != 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004267 if (invert)
4268 return(-1);
4269 else
4270 return(1);
4271 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004272 if (*y != 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004273 /*
4274 * Skip trailing blank chars of the collapsed string.
4275 */
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004276 while IS_WSP_BLANK_CH(*y)
4277 y++;
4278 if (*y != 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004279 if (invert)
4280 return(1);
4281 else
4282 return(-1);
4283 }
4284 }
4285 return(0);
4286}
4287
4288
4289/**
4290 * xmlSchemaCompareReplacedStrings:
4291 * @x: a first string value
4292 * @y: a second string value
4293 *
4294 * Compare 2 string for their normalized values.
4295 *
4296 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
4297 * case of error
4298 */
4299static int
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004300xmlSchemaCompareReplacedStrings(const xmlChar *x,
4301 const xmlChar *y)
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004302{
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004303 int tmp;
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004304
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004305 while ((*x != 0) && (*y != 0)) {
4306 if IS_WSP_BLANK_CH(*y) {
4307 if (! IS_WSP_BLANK_CH(*x)) {
4308 if ((*x - 0x20) < 0)
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004309 return(-1);
4310 else
4311 return(1);
4312 }
4313 } else {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004314 if IS_WSP_BLANK_CH(*x) {
4315 if ((0x20 - *y) < 0)
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004316 return(-1);
4317 else
4318 return(1);
4319 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004320 tmp = *x - *y;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004321 if (tmp < 0)
4322 return(-1);
4323 if (tmp > 0)
4324 return(1);
4325 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004326 x++;
4327 y++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004328 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004329 if (*x != 0)
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004330 return(1);
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004331 if (*y != 0)
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004332 return(-1);
4333 return(0);
4334}
4335
4336/**
Daniel Veillardc4c21552003-03-29 10:53:38 +00004337 * xmlSchemaCompareNormStrings:
4338 * @x: a first string value
4339 * @y: a second string value
4340 *
4341 * Compare 2 string for their normalized values.
4342 *
4343 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
4344 * case of error
4345 */
4346static int
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004347xmlSchemaCompareNormStrings(const xmlChar *x,
4348 const xmlChar *y) {
Daniel Veillardc4c21552003-03-29 10:53:38 +00004349 int tmp;
Daniel Veillardc4c21552003-03-29 10:53:38 +00004350
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004351 while (IS_BLANK_CH(*x)) x++;
4352 while (IS_BLANK_CH(*y)) y++;
4353 while ((*x != 0) && (*y != 0)) {
4354 if (IS_BLANK_CH(*x)) {
4355 if (!IS_BLANK_CH(*y)) {
4356 tmp = *x - *y;
Daniel Veillardc4c21552003-03-29 10:53:38 +00004357 return(tmp);
4358 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004359 while (IS_BLANK_CH(*x)) x++;
4360 while (IS_BLANK_CH(*y)) y++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00004361 } else {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004362 tmp = *x++ - *y++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00004363 if (tmp < 0)
4364 return(-1);
4365 if (tmp > 0)
4366 return(1);
4367 }
4368 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004369 if (*x != 0) {
4370 while (IS_BLANK_CH(*x)) x++;
4371 if (*x != 0)
Daniel Veillardc4c21552003-03-29 10:53:38 +00004372 return(1);
4373 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004374 if (*y != 0) {
4375 while (IS_BLANK_CH(*y)) y++;
4376 if (*y != 0)
Daniel Veillardc4c21552003-03-29 10:53:38 +00004377 return(-1);
4378 }
4379 return(0);
4380}
4381
4382/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00004383 * xmlSchemaCompareFloats:
4384 * @x: a first float or double value
4385 * @y: a second float or double value
4386 *
4387 * Compare 2 values
4388 *
4389 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
4390 * case of error
4391 */
4392static int
4393xmlSchemaCompareFloats(xmlSchemaValPtr x, xmlSchemaValPtr y) {
4394 double d1, d2;
4395
4396 if ((x == NULL) || (y == NULL))
4397 return(-2);
4398
4399 /*
4400 * Cast everything to doubles.
4401 */
4402 if (x->type == XML_SCHEMAS_DOUBLE)
4403 d1 = x->value.d;
4404 else if (x->type == XML_SCHEMAS_FLOAT)
4405 d1 = x->value.f;
4406 else
4407 return(-2);
4408
4409 if (y->type == XML_SCHEMAS_DOUBLE)
4410 d2 = y->value.d;
4411 else if (y->type == XML_SCHEMAS_FLOAT)
4412 d2 = y->value.f;
4413 else
4414 return(-2);
4415
4416 /*
4417 * Check for special cases.
4418 */
4419 if (xmlXPathIsNaN(d1)) {
4420 if (xmlXPathIsNaN(d2))
4421 return(0);
4422 return(1);
4423 }
4424 if (xmlXPathIsNaN(d2))
4425 return(-1);
4426 if (d1 == xmlXPathPINF) {
4427 if (d2 == xmlXPathPINF)
4428 return(0);
4429 return(1);
4430 }
4431 if (d2 == xmlXPathPINF)
4432 return(-1);
4433 if (d1 == xmlXPathNINF) {
4434 if (d2 == xmlXPathNINF)
4435 return(0);
4436 return(-1);
4437 }
4438 if (d2 == xmlXPathNINF)
4439 return(1);
4440
4441 /*
4442 * basic tests, the last one we should have equality, but
4443 * portability is more important than speed and handling
4444 * NaN or Inf in a portable way is always a challenge, so ...
4445 */
4446 if (d1 < d2)
4447 return(-1);
4448 if (d1 > d2)
4449 return(1);
4450 if (d1 == d2)
4451 return(0);
4452 return(2);
4453}
4454
4455/**
Daniel Veillard4255d502002-04-16 15:50:10 +00004456 * xmlSchemaCompareValues:
4457 * @x: a first value
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004458 * @xvalue: the first value as a string (optional)
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004459 * @xwtsp: the whitespace type
Daniel Veillard4255d502002-04-16 15:50:10 +00004460 * @y: a second value
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004461 * @xvalue: the second value as a string (optional)
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004462 * @ywtsp: the whitespace type
Daniel Veillard4255d502002-04-16 15:50:10 +00004463 *
4464 * Compare 2 values
4465 *
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00004466 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, 3 if not
4467 * comparable and -2 in case of error
Daniel Veillard4255d502002-04-16 15:50:10 +00004468 */
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004469static int
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004470xmlSchemaCompareValuesInternal(xmlSchemaValType xtype,
4471 xmlSchemaValPtr x,
4472 const xmlChar *xvalue,
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004473 xmlSchemaWhitespaceValueType xws,
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004474 xmlSchemaValType ytype,
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004475 xmlSchemaValPtr y,
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004476 const xmlChar *yvalue,
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004477 xmlSchemaWhitespaceValueType yws)
4478{
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004479 switch (xtype) {
Daniel Veillard80b19092003-03-28 13:29:53 +00004480 case XML_SCHEMAS_UNKNOWN:
William M. Brack2f2a6632004-08-20 23:09:47 +00004481 case XML_SCHEMAS_ANYTYPE:
Daniel Veillard80b19092003-03-28 13:29:53 +00004482 return(-2);
4483 case XML_SCHEMAS_INTEGER:
4484 case XML_SCHEMAS_NPINTEGER:
4485 case XML_SCHEMAS_NINTEGER:
4486 case XML_SCHEMAS_NNINTEGER:
4487 case XML_SCHEMAS_PINTEGER:
4488 case XML_SCHEMAS_INT:
4489 case XML_SCHEMAS_UINT:
4490 case XML_SCHEMAS_LONG:
4491 case XML_SCHEMAS_ULONG:
4492 case XML_SCHEMAS_SHORT:
4493 case XML_SCHEMAS_USHORT:
4494 case XML_SCHEMAS_BYTE:
4495 case XML_SCHEMAS_UBYTE:
Daniel Veillard4255d502002-04-16 15:50:10 +00004496 case XML_SCHEMAS_DECIMAL:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004497 if ((x == NULL) || (y == NULL))
4498 return(-2);
4499 if (ytype == xtype)
Daniel Veillard80b19092003-03-28 13:29:53 +00004500 return(xmlSchemaCompareDecimals(x, y));
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004501 if ((ytype == XML_SCHEMAS_DECIMAL) ||
4502 (ytype == XML_SCHEMAS_INTEGER) ||
4503 (ytype == XML_SCHEMAS_NPINTEGER) ||
4504 (ytype == XML_SCHEMAS_NINTEGER) ||
4505 (ytype == XML_SCHEMAS_NNINTEGER) ||
4506 (ytype == XML_SCHEMAS_PINTEGER) ||
4507 (ytype == XML_SCHEMAS_INT) ||
4508 (ytype == XML_SCHEMAS_UINT) ||
4509 (ytype == XML_SCHEMAS_LONG) ||
4510 (ytype == XML_SCHEMAS_ULONG) ||
4511 (ytype == XML_SCHEMAS_SHORT) ||
4512 (ytype == XML_SCHEMAS_USHORT) ||
4513 (ytype == XML_SCHEMAS_BYTE) ||
4514 (ytype == XML_SCHEMAS_UBYTE))
Daniel Veillard4255d502002-04-16 15:50:10 +00004515 return(xmlSchemaCompareDecimals(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00004516 return(-2);
Daniel Veillard070803b2002-05-03 07:29:38 +00004517 case XML_SCHEMAS_DURATION:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004518 if ((x == NULL) || (y == NULL))
4519 return(-2);
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004520 if (ytype == XML_SCHEMAS_DURATION)
Daniel Veillard070803b2002-05-03 07:29:38 +00004521 return(xmlSchemaCompareDurations(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00004522 return(-2);
4523 case XML_SCHEMAS_TIME:
4524 case XML_SCHEMAS_GDAY:
4525 case XML_SCHEMAS_GMONTH:
4526 case XML_SCHEMAS_GMONTHDAY:
4527 case XML_SCHEMAS_GYEAR:
4528 case XML_SCHEMAS_GYEARMONTH:
4529 case XML_SCHEMAS_DATE:
4530 case XML_SCHEMAS_DATETIME:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004531 if ((x == NULL) || (y == NULL))
4532 return(-2);
4533 if ((ytype == XML_SCHEMAS_DATETIME) ||
4534 (ytype == XML_SCHEMAS_TIME) ||
4535 (ytype == XML_SCHEMAS_GDAY) ||
4536 (ytype == XML_SCHEMAS_GMONTH) ||
4537 (ytype == XML_SCHEMAS_GMONTHDAY) ||
4538 (ytype == XML_SCHEMAS_GYEAR) ||
4539 (ytype == XML_SCHEMAS_DATE) ||
4540 (ytype == XML_SCHEMAS_GYEARMONTH))
Daniel Veillard5a872412002-05-22 06:40:27 +00004541 return (xmlSchemaCompareDates(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00004542 return (-2);
Kasimier T. Buchcik2ee855d2005-03-07 11:14:14 +00004543 /*
4544 * Note that we will support comparison of string types against
4545 * anySimpleType as well.
4546 */
4547 case XML_SCHEMAS_ANYSIMPLETYPE:
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004548 case XML_SCHEMAS_STRING:
4549 case XML_SCHEMAS_NORMSTRING:
Daniel Veillard80b19092003-03-28 13:29:53 +00004550 case XML_SCHEMAS_TOKEN:
4551 case XML_SCHEMAS_LANGUAGE:
4552 case XML_SCHEMAS_NMTOKEN:
Daniel Veillard80b19092003-03-28 13:29:53 +00004553 case XML_SCHEMAS_NAME:
Daniel Veillard80b19092003-03-28 13:29:53 +00004554 case XML_SCHEMAS_NCNAME:
4555 case XML_SCHEMAS_ID:
4556 case XML_SCHEMAS_IDREF:
Daniel Veillard80b19092003-03-28 13:29:53 +00004557 case XML_SCHEMAS_ENTITY:
Daniel Veillard80b19092003-03-28 13:29:53 +00004558 case XML_SCHEMAS_ANYURI:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004559 {
4560 const xmlChar *xv, *yv;
4561
4562 if (x == NULL)
4563 xv = xvalue;
4564 else
4565 xv = x->value.str;
4566 if (y == NULL)
4567 yv = yvalue;
4568 else
4569 yv = y->value.str;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004570 /*
4571 * TODO: Compare those against QName.
4572 */
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004573 if (ytype == XML_SCHEMAS_QNAME) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004574 TODO
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004575 if (y == NULL)
4576 return(-2);
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004577 return (-2);
4578 }
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004579 if ((ytype == XML_SCHEMAS_ANYSIMPLETYPE) ||
4580 (ytype == XML_SCHEMAS_STRING) ||
4581 (ytype == XML_SCHEMAS_NORMSTRING) ||
4582 (ytype == XML_SCHEMAS_TOKEN) ||
4583 (ytype == XML_SCHEMAS_LANGUAGE) ||
4584 (ytype == XML_SCHEMAS_NMTOKEN) ||
4585 (ytype == XML_SCHEMAS_NAME) ||
4586 (ytype == XML_SCHEMAS_NCNAME) ||
4587 (ytype == XML_SCHEMAS_ID) ||
4588 (ytype == XML_SCHEMAS_IDREF) ||
4589 (ytype == XML_SCHEMAS_ENTITY) ||
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004590 (ytype == XML_SCHEMAS_ANYURI)) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004591
4592 if (xws == XML_SCHEMA_WHITESPACE_PRESERVE) {
4593
4594 if (yws == XML_SCHEMA_WHITESPACE_PRESERVE) {
4595 /* TODO: What about x < y or x > y. */
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004596 if (xmlStrEqual(xv, yv))
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004597 return (0);
4598 else
4599 return (2);
4600 } else if (yws == XML_SCHEMA_WHITESPACE_REPLACE)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004601 return (xmlSchemaComparePreserveReplaceStrings(xv, yv, 0));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004602 else if (yws == XML_SCHEMA_WHITESPACE_COLLAPSE)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004603 return (xmlSchemaComparePreserveCollapseStrings(xv, yv, 0));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004604
4605 } else if (xws == XML_SCHEMA_WHITESPACE_REPLACE) {
4606
4607 if (yws == XML_SCHEMA_WHITESPACE_PRESERVE)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004608 return (xmlSchemaComparePreserveReplaceStrings(yv, xv, 1));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004609 if (yws == XML_SCHEMA_WHITESPACE_REPLACE)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004610 return (xmlSchemaCompareReplacedStrings(xv, yv));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004611 if (yws == XML_SCHEMA_WHITESPACE_COLLAPSE)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004612 return (xmlSchemaCompareReplaceCollapseStrings(xv, yv, 0));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004613
4614 } else if (xws == XML_SCHEMA_WHITESPACE_COLLAPSE) {
4615
4616 if (yws == XML_SCHEMA_WHITESPACE_PRESERVE)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004617 return (xmlSchemaComparePreserveCollapseStrings(yv, xv, 1));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004618 if (yws == XML_SCHEMA_WHITESPACE_REPLACE)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004619 return (xmlSchemaCompareReplaceCollapseStrings(yv, xv, 1));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004620 if (yws == XML_SCHEMA_WHITESPACE_COLLAPSE)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004621 return (xmlSchemaCompareNormStrings(xv, yv));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004622 } else
4623 return (-2);
4624
4625 }
Daniel Veillardc4c21552003-03-29 10:53:38 +00004626 return (-2);
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004627 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004628 case XML_SCHEMAS_QNAME:
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00004629 case XML_SCHEMAS_NOTATION:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004630 if ((x == NULL) || (y == NULL))
4631 return(-2);
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00004632 if ((ytype == XML_SCHEMAS_QNAME) ||
4633 (ytype == XML_SCHEMAS_NOTATION)) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004634 if ((xmlStrEqual(x->value.qname.name, y->value.qname.name)) &&
4635 (xmlStrEqual(x->value.qname.uri, y->value.qname.uri)))
4636 return(0);
4637 return(2);
4638 }
4639 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00004640 case XML_SCHEMAS_FLOAT:
4641 case XML_SCHEMAS_DOUBLE:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004642 if ((x == NULL) || (y == NULL))
4643 return(-2);
4644 if ((ytype == XML_SCHEMAS_FLOAT) ||
4645 (ytype == XML_SCHEMAS_DOUBLE))
Daniel Veillardb6c7f412003-03-29 16:41:55 +00004646 return (xmlSchemaCompareFloats(x, y));
4647 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00004648 case XML_SCHEMAS_BOOLEAN:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004649 if ((x == NULL) || (y == NULL))
4650 return(-2);
4651 if (ytype == XML_SCHEMAS_BOOLEAN) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00004652 if (x->value.b == y->value.b)
4653 return(0);
4654 if (x->value.b == 0)
4655 return(-1);
4656 return(1);
4657 }
4658 return (-2);
Daniel Veillard560c2a42003-07-06 21:13:49 +00004659 case XML_SCHEMAS_HEXBINARY:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004660 if ((x == NULL) || (y == NULL))
4661 return(-2);
4662 if (ytype == XML_SCHEMAS_HEXBINARY) {
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004663 if (x->value.hex.total == y->value.hex.total) {
4664 int ret = xmlStrcmp(x->value.hex.str, y->value.hex.str);
4665 if (ret > 0)
4666 return(1);
4667 else if (ret == 0)
4668 return(0);
4669 }
4670 else if (x->value.hex.total > y->value.hex.total)
4671 return(1);
4672
4673 return(-1);
4674 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00004675 return (-2);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00004676 case XML_SCHEMAS_BASE64BINARY:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004677 if ((x == NULL) || (y == NULL))
4678 return(-2);
4679 if (ytype == XML_SCHEMAS_BASE64BINARY) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00004680 if (x->value.base64.total == y->value.base64.total) {
4681 int ret = xmlStrcmp(x->value.base64.str,
4682 y->value.base64.str);
4683 if (ret > 0)
4684 return(1);
4685 else if (ret == 0)
4686 return(0);
4687 }
4688 else if (x->value.base64.total > y->value.base64.total)
4689 return(1);
4690 else
4691 return(-1);
4692 }
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004693 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00004694 case XML_SCHEMAS_IDREFS:
4695 case XML_SCHEMAS_ENTITIES:
4696 case XML_SCHEMAS_NMTOKENS:
4697 TODO
4698 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00004699 }
Daniel Veillard5a872412002-05-22 06:40:27 +00004700 return -2;
Daniel Veillard4255d502002-04-16 15:50:10 +00004701}
4702
4703/**
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004704 * xmlSchemaCompareValues:
4705 * @x: a first value
4706 * @y: a second value
4707 *
4708 * Compare 2 values
4709 *
4710 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
4711 * case of error
4712 */
4713int
4714xmlSchemaCompareValues(xmlSchemaValPtr x, xmlSchemaValPtr y) {
4715 xmlSchemaWhitespaceValueType xws, yws;
4716
Daniel Veillard5e094142005-02-18 19:36:12 +00004717 if ((x == NULL) || (y == NULL))
4718 return(-2);
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004719 if (x->type == XML_SCHEMAS_STRING)
4720 xws = XML_SCHEMA_WHITESPACE_PRESERVE;
4721 else if (x->type == XML_SCHEMAS_NORMSTRING)
4722 xws = XML_SCHEMA_WHITESPACE_REPLACE;
4723 else
4724 xws = XML_SCHEMA_WHITESPACE_COLLAPSE;
4725
4726 if (y->type == XML_SCHEMAS_STRING)
4727 yws = XML_SCHEMA_WHITESPACE_PRESERVE;
4728 else if (x->type == XML_SCHEMAS_NORMSTRING)
4729 yws = XML_SCHEMA_WHITESPACE_REPLACE;
4730 else
4731 yws = XML_SCHEMA_WHITESPACE_COLLAPSE;
4732
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004733 return(xmlSchemaCompareValuesInternal(x->type, x, NULL, xws, y->type,
4734 y, NULL, yws));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004735}
4736
4737/**
4738 * xmlSchemaCompareValuesWhtsp:
4739 * @x: a first value
4740 * @xws: the whitespace value of x
4741 * @y: a second value
4742 * @yws: the whitespace value of y
4743 *
4744 * Compare 2 values
4745 *
4746 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
4747 * case of error
4748 */
4749int
4750xmlSchemaCompareValuesWhtsp(xmlSchemaValPtr x,
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004751 xmlSchemaWhitespaceValueType xws,
4752 xmlSchemaValPtr y,
4753 xmlSchemaWhitespaceValueType yws)
4754{
Kasimier T. Buchcik9dbb0ce2005-03-16 16:39:23 +00004755 if ((x == NULL) || (y == NULL))
4756 return(-2);
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004757 return(xmlSchemaCompareValuesInternal(x->type, x, NULL, xws, y->type,
4758 y, NULL, yws));
4759}
4760
4761/**
4762 * xmlSchemaCompareValuesWhtspExt:
4763 * @x: a first value
4764 * @xws: the whitespace value of x
4765 * @y: a second value
4766 * @yws: the whitespace value of y
4767 *
4768 * Compare 2 values
4769 *
4770 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
4771 * case of error
4772 */
4773static int
4774xmlSchemaCompareValuesWhtspExt(xmlSchemaValType xtype,
4775 xmlSchemaValPtr x,
4776 const xmlChar *xvalue,
4777 xmlSchemaWhitespaceValueType xws,
4778 xmlSchemaValType ytype,
4779 xmlSchemaValPtr y,
4780 const xmlChar *yvalue,
4781 xmlSchemaWhitespaceValueType yws)
4782{
4783 return(xmlSchemaCompareValuesInternal(xtype, x, xvalue, xws, ytype, y,
4784 yvalue, yws));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004785}
4786
4787/**
Daniel Veillardc4c21552003-03-29 10:53:38 +00004788 * xmlSchemaNormLen:
4789 * @value: a string
4790 *
4791 * Computes the UTF8 length of the normalized value of the string
4792 *
4793 * Returns the length or -1 in case of error.
4794 */
4795static int
4796xmlSchemaNormLen(const xmlChar *value) {
4797 const xmlChar *utf;
4798 int ret = 0;
4799
4800 if (value == NULL)
4801 return(-1);
4802 utf = value;
William M. Brack76e95df2003-10-18 16:20:14 +00004803 while (IS_BLANK_CH(*utf)) utf++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00004804 while (*utf != 0) {
4805 if (utf[0] & 0x80) {
4806 if ((utf[1] & 0xc0) != 0x80)
4807 return(-1);
4808 if ((utf[0] & 0xe0) == 0xe0) {
4809 if ((utf[2] & 0xc0) != 0x80)
4810 return(-1);
4811 if ((utf[0] & 0xf0) == 0xf0) {
4812 if ((utf[0] & 0xf8) != 0xf0 || (utf[3] & 0xc0) != 0x80)
4813 return(-1);
4814 utf += 4;
4815 } else {
4816 utf += 3;
4817 }
4818 } else {
4819 utf += 2;
4820 }
William M. Brack76e95df2003-10-18 16:20:14 +00004821 } else if (IS_BLANK_CH(*utf)) {
4822 while (IS_BLANK_CH(*utf)) utf++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00004823 if (*utf == 0)
4824 break;
4825 } else {
4826 utf++;
4827 }
4828 ret++;
4829 }
4830 return(ret);
4831}
4832
Daniel Veillard6927b102004-10-27 17:29:04 +00004833/**
4834 * xmlSchemaGetFacetValueAsULong:
4835 * @facet: an schemas type facet
4836 *
4837 * Extract the value of a facet
4838 *
4839 * Returns the value as a long
4840 */
Daniel Veillardc0826a72004-08-10 14:17:33 +00004841unsigned long
4842xmlSchemaGetFacetValueAsULong(xmlSchemaFacetPtr facet)
4843{
4844 /*
4845 * TODO: Check if this is a decimal.
4846 */
William M. Brack094dd862004-11-14 14:28:34 +00004847 if (facet == NULL)
4848 return 0;
Daniel Veillardc0826a72004-08-10 14:17:33 +00004849 return ((unsigned long) facet->val->value.decimal.lo);
4850}
4851
Daniel Veillardc4c21552003-03-29 10:53:38 +00004852/**
Daniel Veillard01fa6152004-06-29 17:04:39 +00004853 * xmlSchemaValidateListSimpleTypeFacet:
4854 * @facet: the facet to check
4855 * @value: the lexical repr of the value to validate
4856 * @actualLen: the number of list items
4857 * @expectedLen: the resulting expected number of list items
4858 *
4859 * Checks the value of a list simple type against a facet.
4860 *
4861 * Returns 0 if the value is valid, a positive error code
4862 * number otherwise and -1 in case of an internal error.
4863 */
4864int
4865xmlSchemaValidateListSimpleTypeFacet(xmlSchemaFacetPtr facet,
4866 const xmlChar *value,
4867 unsigned long actualLen,
4868 unsigned long *expectedLen)
4869{
Daniel Veillardce682bc2004-11-05 17:22:25 +00004870 if (facet == NULL)
4871 return(-1);
Daniel Veillard01fa6152004-06-29 17:04:39 +00004872 /*
4873 * TODO: Check if this will work with large numbers.
4874 * (compare value.decimal.mi and value.decimal.hi as well?).
4875 */
4876 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
4877 if (actualLen != facet->val->value.decimal.lo) {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004878 if (expectedLen != NULL)
Daniel Veillardc0826a72004-08-10 14:17:33 +00004879 *expectedLen = facet->val->value.decimal.lo;
Daniel Veillard01fa6152004-06-29 17:04:39 +00004880 return (XML_SCHEMAV_CVC_LENGTH_VALID);
4881 }
4882 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
4883 if (actualLen < facet->val->value.decimal.lo) {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004884 if (expectedLen != NULL)
Daniel Veillardc0826a72004-08-10 14:17:33 +00004885 *expectedLen = facet->val->value.decimal.lo;
Daniel Veillard01fa6152004-06-29 17:04:39 +00004886 return (XML_SCHEMAV_CVC_MINLENGTH_VALID);
4887 }
4888 } else if (facet->type == XML_SCHEMA_FACET_MAXLENGTH) {
4889 if (actualLen > facet->val->value.decimal.lo) {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004890 if (expectedLen != NULL)
Daniel Veillardc0826a72004-08-10 14:17:33 +00004891 *expectedLen = facet->val->value.decimal.lo;
Daniel Veillard01fa6152004-06-29 17:04:39 +00004892 return (XML_SCHEMAV_CVC_MAXLENGTH_VALID);
4893 }
4894 } else
4895 /*
4896 * NOTE: That we can pass NULL as xmlSchemaValPtr to
4897 * xmlSchemaValidateFacet, since the remaining facet types
4898 * are: XML_SCHEMA_FACET_PATTERN, XML_SCHEMA_FACET_ENUMERATION.
4899 */
4900 return(xmlSchemaValidateFacet(NULL, facet, value, NULL));
4901 return (0);
4902}
4903
4904/**
Daniel Veillard6927b102004-10-27 17:29:04 +00004905 * xmlSchemaValidateLengthFacet:
Daniel Veillardc0826a72004-08-10 14:17:33 +00004906 * @type: the built-in type
4907 * @facet: the facet to check
4908 * @value: the lexical repr. of the value to be validated
4909 * @val: the precomputed value
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004910 * @ws: the whitespace type of the value
4911 * @length: the actual length of the value
4912 *
4913 * Checka a value against a "length", "minLength" and "maxLength"
4914 * facet; sets @length to the computed length of @value.
4915 *
4916 * Returns 0 if the value is valid, a positive error code
4917 * otherwise and -1 in case of an internal or API error.
4918 */
4919static int
4920xmlSchemaValidateLengthFacetInternal(xmlSchemaFacetPtr facet,
4921 xmlSchemaTypeType valType,
4922 const xmlChar *value,
4923 xmlSchemaValPtr val,
4924 unsigned long *length,
4925 xmlSchemaWhitespaceValueType ws)
4926{
4927 unsigned int len = 0;
4928
4929 if ((length == NULL) || (facet == NULL))
4930 return (-1);
4931 *length = 0;
4932 if ((facet->type != XML_SCHEMA_FACET_LENGTH) &&
4933 (facet->type != XML_SCHEMA_FACET_MAXLENGTH) &&
4934 (facet->type != XML_SCHEMA_FACET_MINLENGTH))
4935 return (-1);
4936
4937 /*
4938 * TODO: length, maxLength and minLength must be of type
4939 * nonNegativeInteger only. Check if decimal is used somehow.
4940 */
4941 if ((facet->val == NULL) ||
4942 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
4943 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
4944 (facet->val->value.decimal.frac != 0)) {
4945 return(-1);
4946 }
4947 if ((val != NULL) && (val->type == XML_SCHEMAS_HEXBINARY))
4948 len = val->value.hex.total;
4949 else if ((val != NULL) && (val->type == XML_SCHEMAS_BASE64BINARY))
4950 len = val->value.base64.total;
4951 else {
4952 switch (valType) {
4953 case XML_SCHEMAS_STRING:
4954 case XML_SCHEMAS_NORMSTRING:
4955 if (ws == XML_SCHEMA_WHITESPACE_UNKNOWN) {
4956 /*
4957 * This is to ensure API compatibility with the old
4958 * xmlSchemaValidateLengthFacet(). Anyway, this was and
4959 * is not the correct handling.
4960 * TODO: Get rid of this case somehow.
4961 */
4962 if (valType == XML_SCHEMAS_STRING)
4963 len = xmlUTF8Strlen(value);
4964 else
4965 len = xmlSchemaNormLen(value);
4966 } else if (value != NULL) {
4967 if (ws == XML_SCHEMA_WHITESPACE_COLLAPSE)
4968 len = xmlSchemaNormLen(value);
4969 else
4970 /*
4971 * Should be OK for "preserve" as well.
4972 */
4973 len = xmlUTF8Strlen(value);
4974 }
4975 break;
4976 case XML_SCHEMAS_IDREF:
4977 case XML_SCHEMAS_TOKEN:
4978 case XML_SCHEMAS_LANGUAGE:
4979 case XML_SCHEMAS_NMTOKEN:
4980 case XML_SCHEMAS_NAME:
4981 case XML_SCHEMAS_NCNAME:
Kasimier T. Buchcikbd6c3f72005-05-25 17:29:36 +00004982 case XML_SCHEMAS_ID:
4983 /*
4984 * FIXME: What exactly to do with anyURI?
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004985 */
4986 case XML_SCHEMAS_ANYURI:
4987 if (value != NULL)
4988 len = xmlSchemaNormLen(value);
4989 break;
Kasimier T. Buchcikbd6c3f72005-05-25 17:29:36 +00004990 case XML_SCHEMAS_QNAME:
4991 case XML_SCHEMAS_NOTATION:
4992 /*
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00004993 * For QName and NOTATION, those facets are
4994 * deprecated and should be ignored.
Kasimier T. Buchcikbd6c3f72005-05-25 17:29:36 +00004995 */
4996 return (0);
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004997 default:
4998 TODO
4999 }
5000 }
5001 *length = (unsigned long) len;
5002 /*
5003 * TODO: Return the whole expected value, i.e. "lo", "mi" and "hi".
5004 */
5005 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
5006 if (len != facet->val->value.decimal.lo)
5007 return(XML_SCHEMAV_CVC_LENGTH_VALID);
5008 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
5009 if (len < facet->val->value.decimal.lo)
5010 return(XML_SCHEMAV_CVC_MINLENGTH_VALID);
5011 } else {
5012 if (len > facet->val->value.decimal.lo)
5013 return(XML_SCHEMAV_CVC_MAXLENGTH_VALID);
5014 }
5015
5016 return (0);
5017}
5018
5019/**
5020 * xmlSchemaValidateLengthFacet:
5021 * @type: the built-in type
5022 * @facet: the facet to check
5023 * @value: the lexical repr. of the value to be validated
5024 * @val: the precomputed value
Daniel Veillardc0826a72004-08-10 14:17:33 +00005025 * @length: the actual length of the value
5026 *
5027 * Checka a value against a "length", "minLength" and "maxLength"
5028 * facet; sets @length to the computed length of @value.
5029 *
5030 * Returns 0 if the value is valid, a positive error code
5031 * otherwise and -1 in case of an internal or API error.
5032 */
5033int
5034xmlSchemaValidateLengthFacet(xmlSchemaTypePtr type,
5035 xmlSchemaFacetPtr facet,
5036 const xmlChar *value,
5037 xmlSchemaValPtr val,
5038 unsigned long *length)
5039{
Daniel Veillardcc5e2332005-03-16 21:55:35 +00005040 if (type == NULL)
5041 return(-1);
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005042 return (xmlSchemaValidateLengthFacetInternal(facet,
5043 type->builtInType, value, val, length,
5044 XML_SCHEMA_WHITESPACE_UNKNOWN));
5045}
Daniel Veillardc0826a72004-08-10 14:17:33 +00005046
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005047/**
5048 * xmlSchemaValidateLengthFacetWhtsp:
5049 * @facet: the facet to check
5050 * @valType: the built-in type
5051 * @value: the lexical repr. of the value to be validated
5052 * @val: the precomputed value
5053 * @ws: the whitespace type of the value
5054 * @length: the actual length of the value
5055 *
5056 * Checka a value against a "length", "minLength" and "maxLength"
5057 * facet; sets @length to the computed length of @value.
5058 *
5059 * Returns 0 if the value is valid, a positive error code
5060 * otherwise and -1 in case of an internal or API error.
5061 */
5062int
5063xmlSchemaValidateLengthFacetWhtsp(xmlSchemaFacetPtr facet,
5064 xmlSchemaValType valType,
5065 const xmlChar *value,
5066 xmlSchemaValPtr val,
5067 unsigned long *length,
5068 xmlSchemaWhitespaceValueType ws)
5069{
5070 return (xmlSchemaValidateLengthFacetInternal(facet, valType, value, val,
5071 length, ws));
Daniel Veillardc0826a72004-08-10 14:17:33 +00005072}
5073
5074/**
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005075 * xmlSchemaValidateFacetInternal:
Daniel Veillard4255d502002-04-16 15:50:10 +00005076 * @facet: the facet to check
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005077 * @fws: the whitespace type of the facet's value
5078 * @valType: the built-in type of the value
Daniel Veillard4255d502002-04-16 15:50:10 +00005079 * @value: the lexical repr of the value to validate
5080 * @val: the precomputed value
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005081 * @ws: the whitespace type of the value
Daniel Veillard4255d502002-04-16 15:50:10 +00005082 *
5083 * Check a value against a facet condition
5084 *
5085 * Returns 0 if the element is schemas valid, a positive error code
5086 * number otherwise and -1 in case of internal or API error.
5087 */
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005088static int
5089xmlSchemaValidateFacetInternal(xmlSchemaFacetPtr facet,
5090 xmlSchemaWhitespaceValueType fws,
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005091 xmlSchemaValType valType,
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005092 const xmlChar *value,
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005093 xmlSchemaValPtr val,
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005094 xmlSchemaWhitespaceValueType ws)
Daniel Veillard4255d502002-04-16 15:50:10 +00005095{
5096 int ret;
5097
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005098 if (facet == NULL)
5099 return(-1);
5100
Daniel Veillard4255d502002-04-16 15:50:10 +00005101 switch (facet->type) {
5102 case XML_SCHEMA_FACET_PATTERN:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005103 /*
5104 * NOTE that for patterns, the @value needs to be the normalized
5105 * value, *not* the lexical initial value or the canonical value.
5106 */
5107 if (value == NULL)
5108 return(-1);
Daniel Veillard4255d502002-04-16 15:50:10 +00005109 ret = xmlRegexpExec(facet->regexp, value);
5110 if (ret == 1)
5111 return(0);
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005112 if (ret == 0)
Daniel Veillard01fa6152004-06-29 17:04:39 +00005113 return(XML_SCHEMAV_CVC_PATTERN_VALID);
Daniel Veillard4255d502002-04-16 15:50:10 +00005114 return(ret);
5115 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
5116 ret = xmlSchemaCompareValues(val, facet->val);
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005117 if (ret == -2)
Daniel Veillard4255d502002-04-16 15:50:10 +00005118 return(-1);
Daniel Veillard4255d502002-04-16 15:50:10 +00005119 if (ret == -1)
5120 return(0);
Daniel Veillard01fa6152004-06-29 17:04:39 +00005121 return(XML_SCHEMAV_CVC_MAXEXCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00005122 case XML_SCHEMA_FACET_MAXINCLUSIVE:
5123 ret = xmlSchemaCompareValues(val, facet->val);
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005124 if (ret == -2)
Daniel Veillard070803b2002-05-03 07:29:38 +00005125 return(-1);
Daniel Veillard070803b2002-05-03 07:29:38 +00005126 if ((ret == -1) || (ret == 0))
5127 return(0);
Daniel Veillard01fa6152004-06-29 17:04:39 +00005128 return(XML_SCHEMAV_CVC_MAXINCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00005129 case XML_SCHEMA_FACET_MINEXCLUSIVE:
5130 ret = xmlSchemaCompareValues(val, facet->val);
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005131 if (ret == -2)
Daniel Veillard070803b2002-05-03 07:29:38 +00005132 return(-1);
Daniel Veillard070803b2002-05-03 07:29:38 +00005133 if (ret == 1)
5134 return(0);
Daniel Veillard01fa6152004-06-29 17:04:39 +00005135 return(XML_SCHEMAV_CVC_MINEXCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00005136 case XML_SCHEMA_FACET_MININCLUSIVE:
5137 ret = xmlSchemaCompareValues(val, facet->val);
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005138 if (ret == -2)
Daniel Veillard070803b2002-05-03 07:29:38 +00005139 return(-1);
Daniel Veillard070803b2002-05-03 07:29:38 +00005140 if ((ret == 1) || (ret == 0))
5141 return(0);
Daniel Veillard01fa6152004-06-29 17:04:39 +00005142 return(XML_SCHEMAV_CVC_MININCLUSIVE_VALID);
Daniel Veillard8651f532002-04-17 09:06:27 +00005143 case XML_SCHEMA_FACET_WHITESPACE:
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00005144 /* TODO whitespaces */
Daniel Veillard01fa6152004-06-29 17:04:39 +00005145 /*
5146 * NOTE: Whitespace should be handled to normalize
5147 * the value to be validated against a the facets;
5148 * not to normalize the value in-between.
5149 */
Daniel Veillard8651f532002-04-17 09:06:27 +00005150 return(0);
Daniel Veillard88c58912002-04-23 07:12:20 +00005151 case XML_SCHEMA_FACET_ENUMERATION:
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005152 if (ws == XML_SCHEMA_WHITESPACE_UNKNOWN) {
5153 /*
5154 * This is to ensure API compatibility with the old
5155 * xmlSchemaValidateFacet().
5156 * TODO: Get rid of this case.
5157 */
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005158 if ((facet->value != NULL) &&
5159 (xmlStrEqual(facet->value, value)))
5160 return(0);
5161 } else {
5162 ret = xmlSchemaCompareValuesWhtspExt(facet->val->type,
5163 facet->val, facet->value, fws, valType, val,
5164 value, ws);
5165 if (ret == -2)
5166 return(-1);
5167 if (ret == 0)
5168 return(0);
5169 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00005170 return(XML_SCHEMAV_CVC_ENUMERATION_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00005171 case XML_SCHEMA_FACET_LENGTH:
Kasimier T. Buchcikaba15f72005-04-01 15:17:27 +00005172 /*
5173 * SPEC (1.3) "if {primitive type definition} is QName or NOTATION,
5174 * then any {value} is facet-valid."
5175 */
5176 if ((valType == XML_SCHEMAS_QNAME) ||
5177 (valType == XML_SCHEMAS_NOTATION))
5178 return (0);
5179 /* No break on purpose. */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00005180 case XML_SCHEMA_FACET_MAXLENGTH:
5181 case XML_SCHEMA_FACET_MINLENGTH: {
5182 unsigned int len = 0;
5183
Kasimier T. Buchcik4efd90d2005-06-09 10:32:53 +00005184 if ((valType == XML_SCHEMAS_QNAME) ||
5185 (valType == XML_SCHEMAS_NOTATION))
5186 return (0);
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005187 /*
5188 * TODO: length, maxLength and minLength must be of type
5189 * nonNegativeInteger only. Check if decimal is used somehow.
5190 */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00005191 if ((facet->val == NULL) ||
Daniel Veillarde637c4a2003-03-30 21:10:09 +00005192 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
5193 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00005194 (facet->val->value.decimal.frac != 0)) {
5195 return(-1);
5196 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00005197 if ((val != NULL) && (val->type == XML_SCHEMAS_HEXBINARY))
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00005198 len = val->value.hex.total;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00005199 else if ((val != NULL) && (val->type == XML_SCHEMAS_BASE64BINARY))
5200 len = val->value.base64.total;
5201 else {
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005202 switch (valType) {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005203 case XML_SCHEMAS_STRING:
5204 case XML_SCHEMAS_NORMSTRING:
5205 if (ws == XML_SCHEMA_WHITESPACE_UNKNOWN) {
5206 /*
5207 * This is to ensure API compatibility with the old
5208 * xmlSchemaValidateFacet(). Anyway, this was and
5209 * is not the correct handling.
5210 * TODO: Get rid of this case somehow.
5211 */
5212 if (valType == XML_SCHEMAS_STRING)
5213 len = xmlUTF8Strlen(value);
5214 else
5215 len = xmlSchemaNormLen(value);
5216 } else if (value != NULL) {
5217 if (ws == XML_SCHEMA_WHITESPACE_COLLAPSE)
5218 len = xmlSchemaNormLen(value);
5219 else
5220 /*
5221 * Should be OK for "preserve" as well.
5222 */
5223 len = xmlUTF8Strlen(value);
5224 }
5225 break;
5226 case XML_SCHEMAS_IDREF:
Daniel Veillard560c2a42003-07-06 21:13:49 +00005227 case XML_SCHEMAS_TOKEN:
5228 case XML_SCHEMAS_LANGUAGE:
5229 case XML_SCHEMAS_NMTOKEN:
5230 case XML_SCHEMAS_NAME:
5231 case XML_SCHEMAS_NCNAME:
5232 case XML_SCHEMAS_ID:
Daniel Veillard01fa6152004-06-29 17:04:39 +00005233 case XML_SCHEMAS_ANYURI:
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005234 if (value != NULL)
5235 len = xmlSchemaNormLen(value);
5236 break;
Daniel Veillard560c2a42003-07-06 21:13:49 +00005237 default:
5238 TODO
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00005239 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00005240 }
5241 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00005242 if (len != facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00005243 return(XML_SCHEMAV_CVC_LENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00005244 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
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_MINLENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00005247 } else {
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_MAXLENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00005250 }
5251 break;
5252 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00005253 case XML_SCHEMA_FACET_TOTALDIGITS:
5254 case XML_SCHEMA_FACET_FRACTIONDIGITS:
5255
5256 if ((facet->val == NULL) ||
5257 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
5258 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
5259 (facet->val->value.decimal.frac != 0)) {
5260 return(-1);
5261 }
5262 if ((val == NULL) ||
5263 ((val->type != XML_SCHEMAS_DECIMAL) &&
5264 (val->type != XML_SCHEMAS_INTEGER) &&
5265 (val->type != XML_SCHEMAS_NPINTEGER) &&
5266 (val->type != XML_SCHEMAS_NINTEGER) &&
5267 (val->type != XML_SCHEMAS_NNINTEGER) &&
5268 (val->type != XML_SCHEMAS_PINTEGER) &&
5269 (val->type != XML_SCHEMAS_INT) &&
5270 (val->type != XML_SCHEMAS_UINT) &&
5271 (val->type != XML_SCHEMAS_LONG) &&
5272 (val->type != XML_SCHEMAS_ULONG) &&
5273 (val->type != XML_SCHEMAS_SHORT) &&
5274 (val->type != XML_SCHEMAS_USHORT) &&
5275 (val->type != XML_SCHEMAS_BYTE) &&
5276 (val->type != XML_SCHEMAS_UBYTE))) {
5277 return(-1);
5278 }
5279 if (facet->type == XML_SCHEMA_FACET_TOTALDIGITS) {
5280 if (val->value.decimal.total > facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00005281 return(XML_SCHEMAV_CVC_TOTALDIGITS_VALID);
Daniel Veillard560c2a42003-07-06 21:13:49 +00005282
5283 } else if (facet->type == XML_SCHEMA_FACET_FRACTIONDIGITS) {
5284 if (val->value.decimal.frac > facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00005285 return(XML_SCHEMAV_CVC_FRACTIONDIGITS_VALID);
Daniel Veillard560c2a42003-07-06 21:13:49 +00005286 }
5287 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00005288 default:
5289 TODO
5290 }
5291 return(0);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00005292
Daniel Veillard4255d502002-04-16 15:50:10 +00005293}
5294
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00005295/**
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005296 * xmlSchemaValidateFacet:
5297 * @base: the base type
5298 * @facet: the facet to check
5299 * @value: the lexical repr of the value to validate
5300 * @val: the precomputed value
5301 *
5302 * Check a value against a facet condition
5303 *
5304 * Returns 0 if the element is schemas valid, a positive error code
5305 * number otherwise and -1 in case of internal or API error.
5306 */
5307int
Kasimier T. Buchcik9dbb0ce2005-03-16 16:39:23 +00005308xmlSchemaValidateFacet(xmlSchemaTypePtr base,
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005309 xmlSchemaFacetPtr facet,
5310 const xmlChar *value,
5311 xmlSchemaValPtr val)
5312{
5313 /*
5314 * This tries to ensure API compatibility regarding the old
5315 * xmlSchemaValidateFacet() and the new xmlSchemaValidateFacetInternal() and
5316 * xmlSchemaValidateFacetWhtsp().
5317 */
Kasimier T. Buchcik9dbb0ce2005-03-16 16:39:23 +00005318 if (val != NULL)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005319 return(xmlSchemaValidateFacetInternal(facet,
Kasimier T. Buchcik9dbb0ce2005-03-16 16:39:23 +00005320 XML_SCHEMA_WHITESPACE_UNKNOWN, val->type, value, val,
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005321 XML_SCHEMA_WHITESPACE_UNKNOWN));
Kasimier T. Buchcik9dbb0ce2005-03-16 16:39:23 +00005322 else if (base != NULL)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005323 return(xmlSchemaValidateFacetInternal(facet,
Kasimier T. Buchcik9dbb0ce2005-03-16 16:39:23 +00005324 XML_SCHEMA_WHITESPACE_UNKNOWN, base->builtInType, value, val,
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005325 XML_SCHEMA_WHITESPACE_UNKNOWN));
Kasimier T. Buchcik9dbb0ce2005-03-16 16:39:23 +00005326 return(-1);
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005327}
5328
5329/**
5330 * xmlSchemaValidateFacetWhtsp:
5331 * @facet: the facet to check
5332 * @fws: the whitespace type of the facet's value
5333 * @valType: the built-in type of the value
5334 * @value: the lexical (or normalized for pattern) repr of the value to validate
5335 * @val: the precomputed value
5336 * @ws: the whitespace type of the value
5337 *
5338 * Check a value against a facet condition. This takes value normalization
5339 * according to the specified whitespace types into account.
5340 * Note that @value needs to be the *normalized* value if the facet
5341 * is of type "pattern".
5342 *
5343 * Returns 0 if the element is schemas valid, a positive error code
5344 * number otherwise and -1 in case of internal or API error.
5345 */
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005346int
5347xmlSchemaValidateFacetWhtsp(xmlSchemaFacetPtr facet,
5348 xmlSchemaWhitespaceValueType fws,
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005349 xmlSchemaValType valType,
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005350 const xmlChar *value,
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005351 xmlSchemaValPtr val,
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005352 xmlSchemaWhitespaceValueType ws)
5353{
5354 return(xmlSchemaValidateFacetInternal(facet, fws, valType,
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005355 value, val, ws));
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005356}
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005357
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00005358#if 0
5359#ifndef DBL_DIG
5360#define DBL_DIG 16
5361#endif
5362#ifndef DBL_EPSILON
5363#define DBL_EPSILON 1E-9
5364#endif
5365
5366#define INTEGER_DIGITS DBL_DIG
5367#define FRACTION_DIGITS (DBL_DIG + 1)
5368#define EXPONENT_DIGITS (3 + 2)
5369
5370/**
5371 * xmlXPathFormatNumber:
5372 * @number: number to format
5373 * @buffer: output buffer
5374 * @buffersize: size of output buffer
5375 *
5376 * Convert the number into a string representation.
5377 */
5378static void
5379xmlSchemaFormatFloat(double number, char buffer[], int buffersize)
5380{
5381 switch (xmlXPathIsInf(number)) {
5382 case 1:
5383 if (buffersize > (int)sizeof("INF"))
5384 snprintf(buffer, buffersize, "INF");
5385 break;
5386 case -1:
5387 if (buffersize > (int)sizeof("-INF"))
5388 snprintf(buffer, buffersize, "-INF");
5389 break;
5390 default:
5391 if (xmlXPathIsNaN(number)) {
5392 if (buffersize > (int)sizeof("NaN"))
5393 snprintf(buffer, buffersize, "NaN");
5394 } else if (number == 0) {
5395 snprintf(buffer, buffersize, "0.0E0");
5396 } else {
5397 /* 3 is sign, decimal point, and terminating zero */
5398 char work[DBL_DIG + EXPONENT_DIGITS + 3];
5399 int integer_place, fraction_place;
5400 char *ptr;
5401 char *after_fraction;
5402 double absolute_value;
5403 int size;
5404
5405 absolute_value = fabs(number);
5406
5407 /*
5408 * Result is in work, and after_fraction points
5409 * just past the fractional part.
5410 * Use scientific notation
5411 */
5412 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
5413 fraction_place = DBL_DIG - 1;
5414 snprintf(work, sizeof(work),"%*.*e",
5415 integer_place, fraction_place, number);
5416 after_fraction = strchr(work + DBL_DIG, 'e');
5417 /* Remove fractional trailing zeroes */
5418 ptr = after_fraction;
5419 while (*(--ptr) == '0')
5420 ;
5421 if (*ptr != '.')
5422 ptr++;
5423 while ((*ptr++ = *after_fraction++) != 0);
5424
5425 /* Finally copy result back to caller */
5426 size = strlen(work) + 1;
5427 if (size > buffersize) {
5428 work[buffersize - 1] = 0;
5429 size = buffersize;
5430 }
5431 memmove(buffer, work, size);
5432 }
5433 break;
5434 }
5435}
5436#endif
5437
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005438/**
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00005439 * xmlSchemaGetCanonValue:
5440 * @val: the precomputed value
5441 * @retValue: the returned value
5442 *
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005443 * Get a the cononical lexical representation of the value.
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00005444 * The caller has to FREE the returned retValue.
5445 *
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005446 * WARNING: Some value types are not supported yet, resulting
5447 * in a @retValue of "???".
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00005448 *
5449 * TODO: XML Schema 1.0 does not define canonical representations
5450 * for: duration, gYearMonth, gYear, gMonthDay, gMonth, gDay,
5451 * anyURI, QName, NOTATION. This will be fixed in XML Schema 1.1.
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00005452 *
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00005453 *
5454 * Returns 0 if the value could be built, 1 if the value type is
5455 * not supported yet and -1 in case of API errors.
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00005456 */
5457int
Daniel Veillardb5839c32005-02-19 18:27:14 +00005458xmlSchemaGetCanonValue(xmlSchemaValPtr val, const xmlChar **retValue)
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00005459{
Daniel Veillardb5839c32005-02-19 18:27:14 +00005460 if ((retValue == NULL) || (val == NULL))
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00005461 return (-1);
5462 *retValue = NULL;
5463 switch (val->type) {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005464 case XML_SCHEMAS_STRING:
5465 if (val->value.str == NULL)
5466 *retValue = BAD_CAST xmlStrdup(BAD_CAST "");
5467 else
5468 *retValue =
5469 BAD_CAST xmlStrdup((const xmlChar *) val->value.str);
5470 break;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00005471 case XML_SCHEMAS_NORMSTRING:
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005472 if (val->value.str == NULL)
5473 *retValue = BAD_CAST xmlStrdup(BAD_CAST "");
5474 else {
5475 *retValue = xmlSchemaWhiteSpaceReplace(
5476 (const xmlChar *) val->value.str);
5477 if ((*retValue) == NULL)
5478 *retValue = BAD_CAST xmlStrdup(
5479 (const xmlChar *) val->value.str);
5480 }
5481 break;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00005482 case XML_SCHEMAS_TOKEN:
5483 case XML_SCHEMAS_LANGUAGE:
5484 case XML_SCHEMAS_NMTOKEN:
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005485 case XML_SCHEMAS_NAME:
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00005486 case XML_SCHEMAS_NCNAME:
5487 case XML_SCHEMAS_ID:
5488 case XML_SCHEMAS_IDREF:
5489 case XML_SCHEMAS_ENTITY:
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00005490 case XML_SCHEMAS_NOTATION: /* Unclear */
5491 case XML_SCHEMAS_ANYURI: /* Unclear */
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00005492 if (val->value.str == NULL)
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005493 return (-1);
Kasimier T. Buchcikaba15f72005-04-01 15:17:27 +00005494 *retValue =
5495 BAD_CAST xmlSchemaCollapseString(BAD_CAST val->value.str);
5496 if (*retValue == NULL)
5497 *retValue =
5498 BAD_CAST xmlStrdup((const xmlChar *) val->value.str);
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005499 break;
5500 case XML_SCHEMAS_QNAME:
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00005501 /* TODO: Unclear in XML Schema 1.0. */
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005502 if (val->value.qname.uri == NULL) {
5503 *retValue = BAD_CAST xmlStrdup(BAD_CAST val->value.qname.name);
5504 return (0);
5505 } else {
5506 *retValue = BAD_CAST xmlStrdup(BAD_CAST "{");
5507 *retValue = BAD_CAST xmlStrcat((xmlChar *) (*retValue),
5508 BAD_CAST val->value.qname.uri);
5509 *retValue = BAD_CAST xmlStrcat((xmlChar *) (*retValue),
5510 BAD_CAST "}");
5511 *retValue = BAD_CAST xmlStrcat((xmlChar *) (*retValue),
5512 BAD_CAST val->value.qname.uri);
5513 }
5514 break;
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00005515 case XML_SCHEMAS_DECIMAL:
5516 /*
5517 * TODO: Lookout for a more simple implementation.
5518 */
5519 if ((val->value.decimal.total == 1) &&
5520 (val->value.decimal.lo == 0)) {
5521 *retValue = xmlStrdup(BAD_CAST "0.0");
5522 } else {
5523 xmlSchemaValDecimal dec = val->value.decimal;
5524 int bufsize;
5525 char *buf = NULL, *offs;
5526
5527 /* Add room for the decimal point as well. */
5528 bufsize = dec.total + 2;
5529 if (dec.sign)
5530 bufsize++;
5531 /* Add room for leading/trailing zero. */
5532 if ((dec.frac == 0) || (dec.frac == dec.total))
5533 bufsize++;
5534 buf = xmlMalloc(bufsize);
5535 offs = buf;
5536 if (dec.sign)
5537 *offs++ = '-';
5538 if (dec.frac == dec.total) {
5539 *offs++ = '0';
5540 *offs++ = '.';
5541 }
5542 if (dec.hi != 0)
5543 snprintf(offs, bufsize - (offs - buf),
5544 "%lu%lu%lu", dec.hi, dec.mi, dec.lo);
5545 else if (dec.mi != 0)
5546 snprintf(offs, bufsize - (offs - buf),
5547 "%lu%lu", dec.mi, dec.lo);
5548 else
5549 snprintf(offs, bufsize - (offs - buf),
5550 "%lu", dec.lo);
5551
5552 if (dec.frac != 0) {
5553 if (dec.frac != dec.total) {
5554 int diff = dec.total - dec.frac;
5555 /*
5556 * Insert the decimal point.
5557 */
5558 memmove(offs + diff + 1, offs + diff, dec.frac +1);
5559 offs[diff] = '.';
5560 } else {
5561 unsigned int i = 0;
5562 /*
5563 * Insert missing zeroes behind the decimal point.
5564 */
5565 while (*(offs + i) != 0)
5566 i++;
5567 if (i < dec.total) {
5568 memmove(offs + (dec.total - i), offs, i +1);
5569 memset(offs, '0', dec.total - i);
5570 }
5571 }
5572 } else {
5573 /*
5574 * Append decimal point and zero.
5575 */
5576 offs = buf + bufsize - 1;
5577 *offs-- = 0;
5578 *offs-- = '0';
5579 *offs-- = '.';
5580 }
5581 *retValue = BAD_CAST buf;
5582 }
5583 break;
5584 case XML_SCHEMAS_INTEGER:
5585 case XML_SCHEMAS_PINTEGER:
5586 case XML_SCHEMAS_NPINTEGER:
5587 case XML_SCHEMAS_NINTEGER:
5588 case XML_SCHEMAS_NNINTEGER:
5589 case XML_SCHEMAS_LONG:
5590 case XML_SCHEMAS_BYTE:
5591 case XML_SCHEMAS_SHORT:
5592 case XML_SCHEMAS_INT:
5593 case XML_SCHEMAS_UINT:
5594 case XML_SCHEMAS_ULONG:
5595 case XML_SCHEMAS_USHORT:
5596 case XML_SCHEMAS_UBYTE:
5597 if ((val->value.decimal.total == 1) &&
5598 (val->value.decimal.lo == 0))
5599 *retValue = xmlStrdup(BAD_CAST "0");
5600 else {
5601 xmlSchemaValDecimal dec = val->value.decimal;
5602 int bufsize = dec.total + 1;
5603
5604 /* Add room for the decimal point as well. */
5605 if (dec.sign)
5606 bufsize++;
5607 *retValue = xmlMalloc(bufsize);
5608 if (dec.hi != 0) {
5609 if (dec.sign)
5610 snprintf((char *) *retValue, bufsize,
5611 "-%lu%lu%lu", dec.hi, dec.mi, dec.lo);
5612 else
5613 snprintf((char *) *retValue, bufsize,
5614 "%lu%lu%lu", dec.hi, dec.mi, dec.lo);
5615 } else if (dec.mi != 0) {
5616 if (dec.sign)
5617 snprintf((char *) *retValue, bufsize,
5618 "-%lu%lu", dec.mi, dec.lo);
5619 else
5620 snprintf((char *) *retValue, bufsize,
5621 "%lu%lu", dec.mi, dec.lo);
5622 } else {
5623 if (dec.sign)
5624 snprintf((char *) *retValue, bufsize, "-%lu", dec.lo);
5625 else
5626 snprintf((char *) *retValue, bufsize, "%lu", dec.lo);
5627 }
5628 }
5629 break;
5630 case XML_SCHEMAS_BOOLEAN:
5631 if (val->value.b)
5632 *retValue = BAD_CAST xmlStrdup(BAD_CAST "true");
5633 else
5634 *retValue = BAD_CAST xmlStrdup(BAD_CAST "false");
5635 break;
5636 case XML_SCHEMAS_DURATION: {
5637 char buf[100];
5638 unsigned long year;
5639 unsigned long mon, day, hour = 0, min = 0;
5640 double sec = 0, left;
5641
5642 /* TODO: Unclear in XML Schema 1.0 */
5643 /*
5644 * TODO: This results in a normalized output of the value
5645 * - which is NOT conformant to the spec -
5646 * since the exact values of each property are not
5647 * recoverable. Think about extending the structure to
5648 * provide a field for every property.
5649 */
5650 year = (unsigned long) FQUOTIENT(labs(val->value.dur.mon), 12);
5651 mon = labs(val->value.dur.mon) - 12 * year;
5652
5653 day = (unsigned long) FQUOTIENT(fabs(val->value.dur.sec), 86400);
5654 left = fabs(val->value.dur.sec) - day * 86400;
5655 if (left > 0) {
5656 hour = (unsigned long) FQUOTIENT(left, 3600);
5657 left = left - (hour * 3600);
5658 if (left > 0) {
5659 min = (unsigned long) FQUOTIENT(left, 60);
5660 sec = left - (min * 60);
5661 }
5662 }
5663 if ((val->value.dur.mon < 0) || (val->value.dur.sec < 0))
5664 snprintf(buf, 100, "P%luY%luM%luDT%luH%luM%.14gS",
5665 year, mon, day, hour, min, sec);
5666 else
5667 snprintf(buf, 100, "-P%luY%luM%luDT%luH%luM%.14gS",
5668 year, mon, day, hour, min, sec);
5669 *retValue = BAD_CAST xmlStrdup(BAD_CAST buf);
5670 }
5671 break;
5672 case XML_SCHEMAS_GYEAR: {
5673 char buf[30];
5674 /* TODO: Unclear in XML Schema 1.0 */
5675 /* TODO: What to do with the timezone? */
5676 snprintf(buf, 30, "%04ld", val->value.date.year);
5677 *retValue = BAD_CAST xmlStrdup(BAD_CAST buf);
5678 }
5679 break;
5680 case XML_SCHEMAS_GMONTH: {
5681 /* TODO: Unclear in XML Schema 1.0 */
5682 /* TODO: What to do with the timezone? */
5683 *retValue = xmlMalloc(5);
5684 snprintf((char *) *retValue, 6, "--%02u",
5685 val->value.date.mon);
5686 }
5687 break;
5688 case XML_SCHEMAS_GDAY: {
5689 /* TODO: Unclear in XML Schema 1.0 */
5690 /* TODO: What to do with the timezone? */
5691 *retValue = xmlMalloc(6);
5692 snprintf((char *) *retValue, 6, "---%02u",
5693 val->value.date.day);
5694 }
5695 break;
5696 case XML_SCHEMAS_GMONTHDAY: {
5697 /* TODO: Unclear in XML Schema 1.0 */
5698 /* TODO: What to do with the timezone? */
5699 *retValue = xmlMalloc(8);
5700 snprintf((char *) *retValue, 8, "--%02u-%02u",
5701 val->value.date.mon, val->value.date.day);
5702 }
5703 break;
5704 case XML_SCHEMAS_GYEARMONTH: {
5705 char buf[35];
5706 /* TODO: Unclear in XML Schema 1.0 */
5707 /* TODO: What to do with the timezone? */
5708 if (val->value.date.year < 0)
5709 snprintf(buf, 35, "-%04ld-%02u",
5710 labs(val->value.date.year),
5711 val->value.date.mon);
5712 else
5713 snprintf(buf, 35, "%04ld-%02u",
5714 val->value.date.year, val->value.date.mon);
5715 *retValue = BAD_CAST xmlStrdup(BAD_CAST buf);
5716 }
5717 break;
5718 case XML_SCHEMAS_TIME:
5719 {
5720 char buf[30];
5721
5722 if (val->value.date.tz_flag) {
5723 xmlSchemaValPtr norm;
5724
5725 norm = xmlSchemaDateNormalize(val, 0);
5726 if (norm == NULL)
5727 return (-1);
5728 /*
5729 * TODO: Check if "%.14g" is portable.
5730 */
5731 snprintf(buf, 30,
5732 "%02u:%02u:%02.14gZ",
5733 norm->value.date.hour,
5734 norm->value.date.min,
5735 norm->value.date.sec);
5736 xmlSchemaFreeValue(norm);
5737 } else {
5738 snprintf(buf, 30,
5739 "%02u:%02u:%02.14g",
5740 val->value.date.hour,
5741 val->value.date.min,
5742 val->value.date.sec);
5743 }
5744 *retValue = BAD_CAST xmlStrdup(BAD_CAST buf);
5745 }
5746 break;
5747 case XML_SCHEMAS_DATE:
5748 {
5749 char buf[30];
5750
5751 if (val->value.date.tz_flag) {
5752 xmlSchemaValPtr norm;
5753
5754 norm = xmlSchemaDateNormalize(val, 0);
5755 if (norm == NULL)
5756 return (-1);
5757 /*
5758 * TODO: Append the canonical value of the
5759 * recoverable timezone and not "Z".
5760 */
5761 snprintf(buf, 30,
5762 "%04ld:%02u:%02uZ",
5763 norm->value.date.year, norm->value.date.mon,
5764 norm->value.date.day);
5765 xmlSchemaFreeValue(norm);
5766 } else {
5767 snprintf(buf, 30,
5768 "%04ld:%02u:%02u",
5769 val->value.date.year, val->value.date.mon,
5770 val->value.date.day);
5771 }
5772 *retValue = BAD_CAST xmlStrdup(BAD_CAST buf);
5773 }
5774 break;
5775 case XML_SCHEMAS_DATETIME:
5776 {
5777 char buf[50];
5778
5779 if (val->value.date.tz_flag) {
5780 xmlSchemaValPtr norm;
5781
5782 norm = xmlSchemaDateNormalize(val, 0);
5783 if (norm == NULL)
5784 return (-1);
5785 /*
5786 * TODO: Check if "%.14g" is portable.
5787 */
5788 snprintf(buf, 50,
5789 "%04ld:%02u:%02uT%02u:%02u:%02.14gZ",
5790 norm->value.date.year, norm->value.date.mon,
5791 norm->value.date.day, norm->value.date.hour,
5792 norm->value.date.min, norm->value.date.sec);
5793 xmlSchemaFreeValue(norm);
5794 } else {
5795 snprintf(buf, 50,
5796 "%04ld:%02u:%02uT%02u:%02u:%02.14g",
5797 val->value.date.year, val->value.date.mon,
5798 val->value.date.day, val->value.date.hour,
5799 val->value.date.min, val->value.date.sec);
5800 }
5801 *retValue = BAD_CAST xmlStrdup(BAD_CAST buf);
5802 }
5803 break;
5804 case XML_SCHEMAS_HEXBINARY:
5805 *retValue = BAD_CAST xmlStrdup(BAD_CAST val->value.hex.str);
5806 break;
5807 case XML_SCHEMAS_BASE64BINARY:
5808 /*
5809 * TODO: Is the following spec piece implemented?:
5810 * SPEC: "Note: For some values the canonical form defined
5811 * above does not conform to [RFC 2045], which requires breaking
5812 * with linefeeds at appropriate intervals."
5813 */
5814 *retValue = BAD_CAST xmlStrdup(BAD_CAST val->value.base64.str);
5815 break;
5816 case XML_SCHEMAS_FLOAT: {
5817 char buf[30];
5818 /*
5819 * |m| < 16777216, -149 <= e <= 104.
5820 * TODO: Handle, NaN, INF, -INF. The format is not
5821 * yet conformant. The c type float does not cover
5822 * the whole range.
5823 */
5824 snprintf(buf, 30, "%01.14e", val->value.f);
5825 *retValue = BAD_CAST xmlStrdup(BAD_CAST buf);
5826 }
5827 break;
5828 case XML_SCHEMAS_DOUBLE: {
5829 char buf[40];
5830 /* |m| < 9007199254740992, -1075 <= e <= 970 */
5831 /*
5832 * TODO: Handle, NaN, INF, -INF. The format is not
5833 * yet conformant. The c type float does not cover
5834 * the whole range.
5835 */
5836 snprintf(buf, 40, "%01.14e", val->value.d);
5837 *retValue = BAD_CAST xmlStrdup(BAD_CAST buf);
5838 }
5839 break;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00005840 default:
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005841 *retValue = BAD_CAST xmlStrdup(BAD_CAST "???");
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00005842 return (1);
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00005843 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005844 return (0);
5845}
5846
Daniel Veillardbda59572005-04-01 17:15:17 +00005847/**
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00005848 * xmlSchemaGetCanonValueWhtsp:
5849 * @val: the precomputed value
5850 * @retValue: the returned value
5851 * @ws: the whitespace type of the value
5852 *
5853 * Get a the cononical representation of the value.
5854 * The caller has to free the returned @retValue.
5855 *
5856 * Returns 0 if the value could be built, 1 if the value type is
5857 * not supported yet and -1 in case of API errors.
5858 */
5859int
5860xmlSchemaGetCanonValueWhtsp(xmlSchemaValPtr val,
5861 const xmlChar **retValue,
5862 xmlSchemaWhitespaceValueType ws)
5863{
5864 if ((retValue == NULL) || (val == NULL))
5865 return (-1);
5866 if ((ws == XML_SCHEMA_WHITESPACE_UNKNOWN) ||
5867 (ws > XML_SCHEMA_WHITESPACE_COLLAPSE))
5868 return (-1);
5869
5870 *retValue = NULL;
5871 switch (val->type) {
5872 case XML_SCHEMAS_STRING:
5873 if (val->value.str == NULL)
5874 *retValue = BAD_CAST xmlStrdup(BAD_CAST "");
5875 else if (ws == XML_SCHEMA_WHITESPACE_COLLAPSE)
5876 *retValue = xmlSchemaCollapseString(val->value.str);
5877 else if (ws == XML_SCHEMA_WHITESPACE_REPLACE)
5878 *retValue = xmlSchemaWhiteSpaceReplace(val->value.str);
5879 if ((*retValue) == NULL)
5880 *retValue = BAD_CAST xmlStrdup(val->value.str);
5881 break;
5882 case XML_SCHEMAS_NORMSTRING:
5883 if (val->value.str == NULL)
5884 *retValue = BAD_CAST xmlStrdup(BAD_CAST "");
5885 else {
5886 if (ws == XML_SCHEMA_WHITESPACE_COLLAPSE)
5887 *retValue = xmlSchemaCollapseString(val->value.str);
5888 else
5889 *retValue = xmlSchemaWhiteSpaceReplace(val->value.str);
5890 if ((*retValue) == NULL)
5891 *retValue = BAD_CAST xmlStrdup(val->value.str);
5892 }
5893 break;
5894 default:
5895 return (xmlSchemaGetCanonValue(val, retValue));
5896 }
5897 return (0);
5898}
5899
5900/**
Daniel Veillardbda59572005-04-01 17:15:17 +00005901 * xmlSchemaGetValType:
5902 * @val: a schemas value
5903 *
5904 * Accessor for the type of a value
5905 *
5906 * Returns the xmlSchemaValType of the value
5907 */
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005908xmlSchemaValType
5909xmlSchemaGetValType(xmlSchemaValPtr val)
5910{
Daniel Veillardbda59572005-04-01 17:15:17 +00005911 if (val == NULL)
5912 return(XML_SCHEMAS_UNKNOWN);
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005913 return (val->type);
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00005914}
5915
Daniel Veillard5d4644e2005-04-01 13:11:58 +00005916#define bottom_xmlschemastypes
5917#include "elfgcchack.h"
Daniel Veillard4255d502002-04-16 15:50:10 +00005918#endif /* LIBXML_SCHEMAS_ENABLED */