blob: a1cdf7f8c5666b81559cb29e5f2f0d865c6f0ef6 [file] [log] [blame]
Daniel Veillard4255d502002-04-16 15:50:10 +00001/*
2 * schemastypes.c : implementation of the XML Schema Datatypes
3 * definition and validity checking
4 *
5 * See Copyright for the status of this software.
6 *
7 * Daniel Veillard <veillard@redhat.com>
8 */
9
10#define IN_LIBXML
11#include "libxml.h"
12
13#ifdef LIBXML_SCHEMAS_ENABLED
14
15#include <string.h>
16#include <libxml/xmlmemory.h>
17#include <libxml/parser.h>
18#include <libxml/parserInternals.h>
19#include <libxml/hash.h>
20#include <libxml/valid.h>
Daniel Veillard96a4b252003-02-06 08:22:32 +000021#include <libxml/xpath.h>
22#include <libxml/uri.h>
Daniel Veillard4255d502002-04-16 15:50:10 +000023
24#include <libxml/xmlschemas.h>
25#include <libxml/schemasInternals.h>
26#include <libxml/xmlschemastypes.h>
27
Daniel Veillard070803b2002-05-03 07:29:38 +000028#ifdef HAVE_MATH_H
29#include <math.h>
30#endif
31
Daniel Veillard4255d502002-04-16 15:50:10 +000032#define DEBUG
33
Daniel Veillardd0cf7f62004-11-09 16:17:02 +000034#ifndef LIBXML_XPATH_ENABLED
35extern double xmlXPathNAN;
36extern double xmlXPathPINF;
37extern double xmlXPathNINF;
38#endif
39
Daniel Veillard4255d502002-04-16 15:50:10 +000040#define TODO \
41 xmlGenericError(xmlGenericErrorContext, \
42 "Unimplemented block at %s:%d\n", \
43 __FILE__, __LINE__);
44
45#define XML_SCHEMAS_NAMESPACE_NAME \
46 (const xmlChar *)"http://www.w3.org/2001/XMLSchema"
47
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +000048#define IS_WSP_REPLACE_CH(c) ((((c) == 0x9) || ((c) == 0xa)) || \
49 ((c) == 0xd))
50
51#define IS_WSP_SPACE_CH(c) ((c) == 0x20)
52
Daniel Veillard070803b2002-05-03 07:29:38 +000053/* Date value */
54typedef struct _xmlSchemaValDate xmlSchemaValDate;
55typedef xmlSchemaValDate *xmlSchemaValDatePtr;
56struct _xmlSchemaValDate {
57 long year;
58 unsigned int mon :4; /* 1 <= mon <= 12 */
59 unsigned int day :5; /* 1 <= day <= 31 */
60 unsigned int hour :5; /* 0 <= hour <= 23 */
61 unsigned int min :6; /* 0 <= min <= 59 */
62 double sec;
Daniel Veillarda77cf712003-05-09 23:09:55 +000063 unsigned int tz_flag :1; /* is tzo explicitely set? */
Daniel Veillard070803b2002-05-03 07:29:38 +000064 int tzo :11; /* -1440 <= tzo <= 1440 */
65};
66
67/* Duration value */
68typedef struct _xmlSchemaValDuration xmlSchemaValDuration;
69typedef xmlSchemaValDuration *xmlSchemaValDurationPtr;
70struct _xmlSchemaValDuration {
71 long mon; /* mon stores years also */
72 long day;
73 double sec; /* sec stores min and hour also */
74};
75
Daniel Veillard4255d502002-04-16 15:50:10 +000076typedef struct _xmlSchemaValDecimal xmlSchemaValDecimal;
77typedef xmlSchemaValDecimal *xmlSchemaValDecimalPtr;
78struct _xmlSchemaValDecimal {
79 /* would use long long but not portable */
Daniel Veillarde637c4a2003-03-30 21:10:09 +000080 unsigned long lo;
81 unsigned long mi;
82 unsigned long hi;
Daniel Veillard4255d502002-04-16 15:50:10 +000083 unsigned int extra;
Daniel Veillard5a872412002-05-22 06:40:27 +000084 unsigned int sign:1;
William M. Brackc1939562003-08-05 15:52:22 +000085 unsigned int frac:7;
86 unsigned int total:8;
Daniel Veillard4255d502002-04-16 15:50:10 +000087};
88
Daniel Veillarde637c4a2003-03-30 21:10:09 +000089typedef struct _xmlSchemaValQName xmlSchemaValQName;
90typedef xmlSchemaValQName *xmlSchemaValQNamePtr;
91struct _xmlSchemaValQName {
92 xmlChar *name;
93 xmlChar *uri;
94};
95
Daniel Veillard70bcb0e2003-08-08 14:00:28 +000096typedef struct _xmlSchemaValHex xmlSchemaValHex;
97typedef xmlSchemaValHex *xmlSchemaValHexPtr;
98struct _xmlSchemaValHex {
99 xmlChar *str;
100 unsigned int total;
101};
102
Daniel Veillard1ac24d32003-08-27 14:15:15 +0000103typedef struct _xmlSchemaValBase64 xmlSchemaValBase64;
104typedef xmlSchemaValBase64 *xmlSchemaValBase64Ptr;
105struct _xmlSchemaValBase64 {
106 xmlChar *str;
107 unsigned int total;
108};
109
Daniel Veillard4255d502002-04-16 15:50:10 +0000110struct _xmlSchemaVal {
111 xmlSchemaValType type;
112 union {
Daniel Veillard5a872412002-05-22 06:40:27 +0000113 xmlSchemaValDecimal decimal;
Daniel Veillard070803b2002-05-03 07:29:38 +0000114 xmlSchemaValDate date;
115 xmlSchemaValDuration dur;
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000116 xmlSchemaValQName qname;
Daniel Veillard70bcb0e2003-08-08 14:00:28 +0000117 xmlSchemaValHex hex;
Daniel Veillard1ac24d32003-08-27 14:15:15 +0000118 xmlSchemaValBase64 base64;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000119 float f;
120 double d;
Daniel Veillardc5a70f22003-02-06 23:41:59 +0000121 int b;
Daniel Veillardc4c21552003-03-29 10:53:38 +0000122 xmlChar *str;
Daniel Veillard4255d502002-04-16 15:50:10 +0000123 } value;
124};
125
126static int xmlSchemaTypesInitialized = 0;
127static xmlHashTablePtr xmlSchemaTypesBank = NULL;
128
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000129/*
130 * Basic types
131 */
Daniel Veillard4255d502002-04-16 15:50:10 +0000132static xmlSchemaTypePtr xmlSchemaTypeStringDef = NULL;
133static xmlSchemaTypePtr xmlSchemaTypeAnyTypeDef = NULL;
134static xmlSchemaTypePtr xmlSchemaTypeAnySimpleTypeDef = NULL;
135static xmlSchemaTypePtr xmlSchemaTypeDecimalDef = NULL;
Daniel Veillard070803b2002-05-03 07:29:38 +0000136static xmlSchemaTypePtr xmlSchemaTypeDatetimeDef = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +0000137static xmlSchemaTypePtr xmlSchemaTypeDateDef = NULL;
Daniel Veillard070803b2002-05-03 07:29:38 +0000138static xmlSchemaTypePtr xmlSchemaTypeTimeDef = NULL;
139static xmlSchemaTypePtr xmlSchemaTypeGYearDef = NULL;
140static xmlSchemaTypePtr xmlSchemaTypeGYearMonthDef = NULL;
141static xmlSchemaTypePtr xmlSchemaTypeGDayDef = NULL;
142static xmlSchemaTypePtr xmlSchemaTypeGMonthDayDef = NULL;
143static xmlSchemaTypePtr xmlSchemaTypeGMonthDef = NULL;
144static xmlSchemaTypePtr xmlSchemaTypeDurationDef = NULL;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000145static xmlSchemaTypePtr xmlSchemaTypeFloatDef = NULL;
Daniel Veillardc5a70f22003-02-06 23:41:59 +0000146static xmlSchemaTypePtr xmlSchemaTypeBooleanDef = NULL;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000147static xmlSchemaTypePtr xmlSchemaTypeDoubleDef = NULL;
Daniel Veillard560c2a42003-07-06 21:13:49 +0000148static xmlSchemaTypePtr xmlSchemaTypeHexBinaryDef = NULL;
Daniel Veillard1ac24d32003-08-27 14:15:15 +0000149static xmlSchemaTypePtr xmlSchemaTypeBase64BinaryDef = NULL;
Daniel Veillarde5b110b2003-02-04 14:43:39 +0000150static xmlSchemaTypePtr xmlSchemaTypeAnyURIDef = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +0000151
152/*
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000153 * Derived types
154 */
155static xmlSchemaTypePtr xmlSchemaTypePositiveIntegerDef = NULL;
156static xmlSchemaTypePtr xmlSchemaTypeNonPositiveIntegerDef = NULL;
157static xmlSchemaTypePtr xmlSchemaTypeNegativeIntegerDef = NULL;
158static xmlSchemaTypePtr xmlSchemaTypeNonNegativeIntegerDef = NULL;
159static xmlSchemaTypePtr xmlSchemaTypeIntegerDef = NULL;
160static xmlSchemaTypePtr xmlSchemaTypeLongDef = NULL;
161static xmlSchemaTypePtr xmlSchemaTypeIntDef = NULL;
162static xmlSchemaTypePtr xmlSchemaTypeShortDef = NULL;
163static xmlSchemaTypePtr xmlSchemaTypeByteDef = NULL;
164static xmlSchemaTypePtr xmlSchemaTypeUnsignedLongDef = NULL;
165static xmlSchemaTypePtr xmlSchemaTypeUnsignedIntDef = NULL;
166static xmlSchemaTypePtr xmlSchemaTypeUnsignedShortDef = NULL;
167static xmlSchemaTypePtr xmlSchemaTypeUnsignedByteDef = NULL;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000168static xmlSchemaTypePtr xmlSchemaTypeNormStringDef = NULL;
169static xmlSchemaTypePtr xmlSchemaTypeTokenDef = NULL;
170static xmlSchemaTypePtr xmlSchemaTypeLanguageDef = NULL;
171static xmlSchemaTypePtr xmlSchemaTypeNameDef = NULL;
172static xmlSchemaTypePtr xmlSchemaTypeQNameDef = NULL;
Daniel Veillarde5b110b2003-02-04 14:43:39 +0000173static xmlSchemaTypePtr xmlSchemaTypeNCNameDef = NULL;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000174static xmlSchemaTypePtr xmlSchemaTypeIdDef = NULL;
175static xmlSchemaTypePtr xmlSchemaTypeIdrefDef = NULL;
176static xmlSchemaTypePtr xmlSchemaTypeIdrefsDef = NULL;
Daniel Veillarda1a9d042003-03-18 16:53:17 +0000177static xmlSchemaTypePtr xmlSchemaTypeEntityDef = NULL;
178static xmlSchemaTypePtr xmlSchemaTypeEntitiesDef = NULL;
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000179static xmlSchemaTypePtr xmlSchemaTypeNotationDef = NULL;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000180static xmlSchemaTypePtr xmlSchemaTypeNmtokenDef = NULL;
181static xmlSchemaTypePtr xmlSchemaTypeNmtokensDef = NULL;
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000182
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000183/************************************************************************
184 * *
185 * Datatype error handlers *
186 * *
187 ************************************************************************/
188/**
189 * xmlSchemaTypeErrMemory:
190 * @extra: extra informations
191 *
192 * Handle an out of memory condition
193 */
194static void
195xmlSchemaTypeErrMemory(xmlNodePtr node, const char *extra)
196{
197 __xmlSimpleError(XML_FROM_DATATYPE, XML_ERR_NO_MEMORY, node, NULL, extra);
198}
199
200/************************************************************************
201 * *
202 * Base types support *
203 * *
204 ************************************************************************/
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000205/*
Daniel Veillard4255d502002-04-16 15:50:10 +0000206 * xmlSchemaInitBasicType:
207 * @name: the type name
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000208 * @type: the value type associated
Daniel Veillard4255d502002-04-16 15:50:10 +0000209 *
Daniel Veillard01fa6152004-06-29 17:04:39 +0000210 * Initialize one primitive built-in type
Daniel Veillard4255d502002-04-16 15:50:10 +0000211 */
212static xmlSchemaTypePtr
Daniel Veillard01fa6152004-06-29 17:04:39 +0000213xmlSchemaInitBasicType(const char *name, xmlSchemaValType type,
214 xmlSchemaTypePtr baseType) {
Daniel Veillard4255d502002-04-16 15:50:10 +0000215 xmlSchemaTypePtr ret;
216
217 ret = (xmlSchemaTypePtr) xmlMalloc(sizeof(xmlSchemaType));
218 if (ret == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000219 xmlSchemaTypeErrMemory(NULL, "could not initialize basic types");
Daniel Veillard4255d502002-04-16 15:50:10 +0000220 return(NULL);
221 }
222 memset(ret, 0, sizeof(xmlSchemaType));
Daniel Veillardbe9c6322003-11-22 20:37:51 +0000223 ret->name = (const xmlChar *)name;
Daniel Veillard4255d502002-04-16 15:50:10 +0000224 ret->type = XML_SCHEMA_TYPE_BASIC;
Daniel Veillard01fa6152004-06-29 17:04:39 +0000225 ret->baseType = baseType;
226 /*
227 * Hack to reflect the variety.
228 */
229 if ((type == XML_SCHEMAS_IDREFS) ||
230 (type == XML_SCHEMAS_NMTOKENS) ||
231 (type == XML_SCHEMAS_ENTITIES))
232 ret->flags |= XML_SCHEMAS_TYPE_VARIETY_LIST;
William M. Brack2f2a6632004-08-20 23:09:47 +0000233 else if ((type != XML_SCHEMAS_ANYTYPE) &&
234 (type != XML_SCHEMAS_ANYSIMPLETYPE))
Daniel Veillard01fa6152004-06-29 17:04:39 +0000235 ret->flags |= XML_SCHEMAS_TYPE_VARIETY_ATOMIC;
Daniel Veillard4255d502002-04-16 15:50:10 +0000236 ret->contentType = XML_SCHEMA_CONTENT_BASIC;
Daniel Veillard01fa6152004-06-29 17:04:39 +0000237 switch (type) {
238 case XML_SCHEMAS_STRING:
239 case XML_SCHEMAS_DECIMAL:
240 case XML_SCHEMAS_DATE:
241 case XML_SCHEMAS_DATETIME:
242 case XML_SCHEMAS_TIME:
243 case XML_SCHEMAS_GYEAR:
244 case XML_SCHEMAS_GYEARMONTH:
245 case XML_SCHEMAS_GMONTH:
246 case XML_SCHEMAS_GMONTHDAY:
247 case XML_SCHEMAS_GDAY:
248 case XML_SCHEMAS_DURATION:
249 case XML_SCHEMAS_FLOAT:
250 case XML_SCHEMAS_DOUBLE:
251 case XML_SCHEMAS_BOOLEAN:
252 case XML_SCHEMAS_ANYURI:
253 case XML_SCHEMAS_HEXBINARY:
254 case XML_SCHEMAS_BASE64BINARY:
255 case XML_SCHEMAS_QNAME:
256 case XML_SCHEMAS_NOTATION:
257 ret->flags |= XML_SCHEMAS_TYPE_BUILTIN_PRIMITIVE;
William M. Brack96d2eff2004-06-30 11:48:47 +0000258 default:
259 break;
Daniel Veillard01fa6152004-06-29 17:04:39 +0000260 }
261
Daniel Veillard4255d502002-04-16 15:50:10 +0000262 xmlHashAddEntry2(xmlSchemaTypesBank, ret->name,
263 XML_SCHEMAS_NAMESPACE_NAME, ret);
Daniel Veillard01fa6152004-06-29 17:04:39 +0000264 ret->builtInType = type;
Daniel Veillard4255d502002-04-16 15:50:10 +0000265 return(ret);
266}
267
268/*
269 * xmlSchemaInitTypes:
270 *
271 * Initialize the default XML Schemas type library
272 */
273void
Daniel Veillard6560a422003-03-27 21:25:38 +0000274xmlSchemaInitTypes(void)
275{
Daniel Veillard4255d502002-04-16 15:50:10 +0000276 if (xmlSchemaTypesInitialized != 0)
Daniel Veillard6560a422003-03-27 21:25:38 +0000277 return;
Daniel Veillard4255d502002-04-16 15:50:10 +0000278 xmlSchemaTypesBank = xmlHashCreate(40);
Daniel Veillard6560a422003-03-27 21:25:38 +0000279
Daniel Veillard01fa6152004-06-29 17:04:39 +0000280
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000281 /*
Daniel Veillard01fa6152004-06-29 17:04:39 +0000282 * 3.4.7 Built-in Complex Type Definition
283 */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000284 xmlSchemaTypeAnyTypeDef = xmlSchemaInitBasicType("anyType",
William M. Brack2f2a6632004-08-20 23:09:47 +0000285 XML_SCHEMAS_ANYTYPE,
Daniel Veillard01fa6152004-06-29 17:04:39 +0000286 NULL);
287 xmlSchemaTypeAnyTypeDef->baseType = xmlSchemaTypeAnyTypeDef;
288 xmlSchemaTypeAnyTypeDef->contentType = XML_SCHEMA_CONTENT_MIXED;
289 {
290 xmlSchemaWildcardPtr wild;
291
292 wild = (xmlSchemaWildcardPtr) xmlMalloc(sizeof(xmlSchemaWildcard));
293 if (wild == NULL) {
William M. Brack2f2a6632004-08-20 23:09:47 +0000294 xmlSchemaTypeErrMemory(NULL, "could not create an attribute wildcard on anyType");
Daniel Veillard01fa6152004-06-29 17:04:39 +0000295 return;
296 }
297 memset(wild, 0, sizeof(xmlSchemaWildcard));
298 wild->any = 1;
299 wild->processContents = XML_SCHEMAS_ANY_LAX;
300 wild->minOccurs = 1;
301 wild->maxOccurs = 1;
302 xmlSchemaTypeAnyTypeDef->attributeWildcard = wild;
303 }
304 xmlSchemaTypeAnySimpleTypeDef = xmlSchemaInitBasicType("anySimpleType",
William M. Brack2f2a6632004-08-20 23:09:47 +0000305 XML_SCHEMAS_ANYSIMPLETYPE,
Daniel Veillard01fa6152004-06-29 17:04:39 +0000306 xmlSchemaTypeAnyTypeDef);
307 /*
308 * primitive datatypes
309 */
310 xmlSchemaTypeStringDef = xmlSchemaInitBasicType("string",
311 XML_SCHEMAS_STRING,
312 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000313 xmlSchemaTypeDecimalDef = xmlSchemaInitBasicType("decimal",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000314 XML_SCHEMAS_DECIMAL,
315 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000316 xmlSchemaTypeDateDef = xmlSchemaInitBasicType("date",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000317 XML_SCHEMAS_DATE,
318 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000319 xmlSchemaTypeDatetimeDef = xmlSchemaInitBasicType("dateTime",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000320 XML_SCHEMAS_DATETIME,
321 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000322 xmlSchemaTypeTimeDef = xmlSchemaInitBasicType("time",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000323 XML_SCHEMAS_TIME,
324 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000325 xmlSchemaTypeGYearDef = xmlSchemaInitBasicType("gYear",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000326 XML_SCHEMAS_GYEAR,
327 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000328 xmlSchemaTypeGYearMonthDef = xmlSchemaInitBasicType("gYearMonth",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000329 XML_SCHEMAS_GYEARMONTH,
330 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000331 xmlSchemaTypeGMonthDef = xmlSchemaInitBasicType("gMonth",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000332 XML_SCHEMAS_GMONTH,
333 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000334 xmlSchemaTypeGMonthDayDef = xmlSchemaInitBasicType("gMonthDay",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000335 XML_SCHEMAS_GMONTHDAY,
336 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000337 xmlSchemaTypeGDayDef = xmlSchemaInitBasicType("gDay",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000338 XML_SCHEMAS_GDAY,
339 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000340 xmlSchemaTypeDurationDef = xmlSchemaInitBasicType("duration",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000341 XML_SCHEMAS_DURATION,
342 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000343 xmlSchemaTypeFloatDef = xmlSchemaInitBasicType("float",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000344 XML_SCHEMAS_FLOAT,
345 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000346 xmlSchemaTypeDoubleDef = xmlSchemaInitBasicType("double",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000347 XML_SCHEMAS_DOUBLE,
348 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000349 xmlSchemaTypeBooleanDef = xmlSchemaInitBasicType("boolean",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000350 XML_SCHEMAS_BOOLEAN,
351 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000352 xmlSchemaTypeAnyURIDef = xmlSchemaInitBasicType("anyURI",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000353 XML_SCHEMAS_ANYURI,
354 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard560c2a42003-07-06 21:13:49 +0000355 xmlSchemaTypeHexBinaryDef = xmlSchemaInitBasicType("hexBinary",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000356 XML_SCHEMAS_HEXBINARY,
357 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard1ac24d32003-08-27 14:15:15 +0000358 xmlSchemaTypeBase64BinaryDef
Daniel Veillard01fa6152004-06-29 17:04:39 +0000359 = xmlSchemaInitBasicType("base64Binary", XML_SCHEMAS_BASE64BINARY,
360 xmlSchemaTypeAnySimpleTypeDef);
361 xmlSchemaTypeNotationDef = xmlSchemaInitBasicType("NOTATION",
362 XML_SCHEMAS_NOTATION,
363 xmlSchemaTypeAnySimpleTypeDef);
364 xmlSchemaTypeQNameDef = xmlSchemaInitBasicType("QName",
365 XML_SCHEMAS_QNAME,
366 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard4255d502002-04-16 15:50:10 +0000367
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000368 /*
369 * derived datatypes
370 */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000371 xmlSchemaTypeIntegerDef = xmlSchemaInitBasicType("integer",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000372 XML_SCHEMAS_INTEGER,
373 xmlSchemaTypeDecimalDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000374 xmlSchemaTypeNonPositiveIntegerDef =
375 xmlSchemaInitBasicType("nonPositiveInteger",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000376 XML_SCHEMAS_NPINTEGER,
377 xmlSchemaTypeIntegerDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000378 xmlSchemaTypeNegativeIntegerDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000379 xmlSchemaInitBasicType("negativeInteger", XML_SCHEMAS_NINTEGER,
380 xmlSchemaTypeNonPositiveIntegerDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000381 xmlSchemaTypeLongDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000382 xmlSchemaInitBasicType("long", XML_SCHEMAS_LONG,
383 xmlSchemaTypeIntegerDef);
384 xmlSchemaTypeIntDef = xmlSchemaInitBasicType("int", XML_SCHEMAS_INT,
385 xmlSchemaTypeLongDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000386 xmlSchemaTypeShortDef = xmlSchemaInitBasicType("short",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000387 XML_SCHEMAS_SHORT,
388 xmlSchemaTypeIntDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000389 xmlSchemaTypeByteDef = xmlSchemaInitBasicType("byte",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000390 XML_SCHEMAS_BYTE,
391 xmlSchemaTypeShortDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000392 xmlSchemaTypeNonNegativeIntegerDef =
393 xmlSchemaInitBasicType("nonNegativeInteger",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000394 XML_SCHEMAS_NNINTEGER,
395 xmlSchemaTypeIntegerDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000396 xmlSchemaTypeUnsignedLongDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000397 xmlSchemaInitBasicType("unsignedLong", XML_SCHEMAS_ULONG,
398 xmlSchemaTypeNonNegativeIntegerDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000399 xmlSchemaTypeUnsignedIntDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000400 xmlSchemaInitBasicType("unsignedInt", XML_SCHEMAS_UINT,
401 xmlSchemaTypeUnsignedLongDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000402 xmlSchemaTypeUnsignedShortDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000403 xmlSchemaInitBasicType("unsignedShort", XML_SCHEMAS_USHORT,
404 xmlSchemaTypeUnsignedIntDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000405 xmlSchemaTypeUnsignedByteDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000406 xmlSchemaInitBasicType("unsignedByte", XML_SCHEMAS_UBYTE,
407 xmlSchemaTypeUnsignedShortDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000408 xmlSchemaTypePositiveIntegerDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000409 xmlSchemaInitBasicType("positiveInteger", XML_SCHEMAS_PINTEGER,
410 xmlSchemaTypeNonNegativeIntegerDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000411 xmlSchemaTypeNormStringDef = xmlSchemaInitBasicType("normalizedString",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000412 XML_SCHEMAS_NORMSTRING,
413 xmlSchemaTypeStringDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000414 xmlSchemaTypeTokenDef = xmlSchemaInitBasicType("token",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000415 XML_SCHEMAS_TOKEN,
416 xmlSchemaTypeNormStringDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000417 xmlSchemaTypeLanguageDef = xmlSchemaInitBasicType("language",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000418 XML_SCHEMAS_LANGUAGE,
419 xmlSchemaTypeTokenDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000420 xmlSchemaTypeNameDef = xmlSchemaInitBasicType("Name",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000421 XML_SCHEMAS_NAME,
422 xmlSchemaTypeTokenDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000423 xmlSchemaTypeNmtokenDef = xmlSchemaInitBasicType("NMTOKEN",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000424 XML_SCHEMAS_NMTOKEN,
425 xmlSchemaTypeTokenDef);
426 xmlSchemaTypeNCNameDef = xmlSchemaInitBasicType("NCName",
427 XML_SCHEMAS_NCNAME,
428 xmlSchemaTypeNameDef);
429 xmlSchemaTypeIdDef = xmlSchemaInitBasicType("ID", XML_SCHEMAS_ID,
430 xmlSchemaTypeNCNameDef);
431 xmlSchemaTypeIdrefDef = xmlSchemaInitBasicType("IDREF",
432 XML_SCHEMAS_IDREF,
433 xmlSchemaTypeNCNameDef);
434 xmlSchemaTypeIdrefsDef = xmlSchemaInitBasicType("IDREFS",
435 XML_SCHEMAS_IDREFS,
436 xmlSchemaTypeIdrefDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000437 xmlSchemaTypeNmtokensDef = xmlSchemaInitBasicType("NMTOKENS",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000438 XML_SCHEMAS_NMTOKENS,
439 xmlSchemaTypeNmtokenDef);
440 xmlSchemaTypeEntityDef = xmlSchemaInitBasicType("ENTITY",
441 XML_SCHEMAS_ENTITY,
442 xmlSchemaTypeNCNameDef);
443 xmlSchemaTypeEntitiesDef = xmlSchemaInitBasicType("ENTITIES",
444 XML_SCHEMAS_ENTITIES,
445 xmlSchemaTypeNCNameDef);
Daniel Veillard4255d502002-04-16 15:50:10 +0000446 xmlSchemaTypesInitialized = 1;
447}
448
449/**
450 * xmlSchemaCleanupTypes:
451 *
452 * Cleanup the default XML Schemas type library
453 */
454void
455xmlSchemaCleanupTypes(void) {
456 if (xmlSchemaTypesInitialized == 0)
457 return;
Daniel Veillard01fa6152004-06-29 17:04:39 +0000458 xmlSchemaFreeWildcard(xmlSchemaTypeAnyTypeDef->attributeWildcard);
Daniel Veillard4255d502002-04-16 15:50:10 +0000459 xmlHashFree(xmlSchemaTypesBank, (xmlHashDeallocator) xmlSchemaFreeType);
460 xmlSchemaTypesInitialized = 0;
461}
462
463/**
Daniel Veillard6927b102004-10-27 17:29:04 +0000464 * xmlSchemaIsBuiltInTypeFacet:
Daniel Veillard01fa6152004-06-29 17:04:39 +0000465 * @type: the built-in type
466 * @facetType: the facet type
467 *
468 * Evaluates if a specific facet can be
469 * used in conjunction with a type.
470 *
471 * Returns 1 if the facet can be used with the given built-in type,
472 * 0 otherwise and -1 in case the type is not a built-in type.
473 */
474int
475xmlSchemaIsBuiltInTypeFacet(xmlSchemaTypePtr type, int facetType)
476{
Daniel Veillardce682bc2004-11-05 17:22:25 +0000477 if (type == NULL)
478 return (-1);
Daniel Veillard01fa6152004-06-29 17:04:39 +0000479 if (type->type != XML_SCHEMA_TYPE_BASIC)
480 return (-1);
481 switch (type->builtInType) {
482 case XML_SCHEMAS_BOOLEAN:
483 if ((facetType == XML_SCHEMA_FACET_PATTERN) ||
484 (facetType == XML_SCHEMA_FACET_WHITESPACE))
485 return (1);
486 else
487 return (0);
488 case XML_SCHEMAS_STRING:
489 case XML_SCHEMAS_NOTATION:
490 case XML_SCHEMAS_QNAME:
491 case XML_SCHEMAS_ANYURI:
492 case XML_SCHEMAS_BASE64BINARY:
493 case XML_SCHEMAS_HEXBINARY:
494 if ((facetType == XML_SCHEMA_FACET_LENGTH) ||
495 (facetType == XML_SCHEMA_FACET_MINLENGTH) ||
496 (facetType == XML_SCHEMA_FACET_MAXLENGTH) ||
497 (facetType == XML_SCHEMA_FACET_PATTERN) ||
498 (facetType == XML_SCHEMA_FACET_ENUMERATION) ||
499 (facetType == XML_SCHEMA_FACET_WHITESPACE))
500 return (1);
501 else
502 return (0);
503 case XML_SCHEMAS_DECIMAL:
504 if ((facetType == XML_SCHEMA_FACET_TOTALDIGITS) ||
505 (facetType == XML_SCHEMA_FACET_FRACTIONDIGITS) ||
506 (facetType == XML_SCHEMA_FACET_PATTERN) ||
507 (facetType == XML_SCHEMA_FACET_WHITESPACE) ||
508 (facetType == XML_SCHEMA_FACET_ENUMERATION) ||
509 (facetType == XML_SCHEMA_FACET_MAXINCLUSIVE) ||
510 (facetType == XML_SCHEMA_FACET_MAXEXCLUSIVE) ||
511 (facetType == XML_SCHEMA_FACET_MININCLUSIVE) ||
512 (facetType == XML_SCHEMA_FACET_MINEXCLUSIVE))
513 return (1);
514 else
515 return (0);
516 case XML_SCHEMAS_TIME:
517 case XML_SCHEMAS_GDAY:
518 case XML_SCHEMAS_GMONTH:
519 case XML_SCHEMAS_GMONTHDAY:
520 case XML_SCHEMAS_GYEAR:
521 case XML_SCHEMAS_GYEARMONTH:
522 case XML_SCHEMAS_DATE:
523 case XML_SCHEMAS_DATETIME:
524 case XML_SCHEMAS_DURATION:
525 case XML_SCHEMAS_FLOAT:
526 case XML_SCHEMAS_DOUBLE:
527 if ((facetType == XML_SCHEMA_FACET_PATTERN) ||
528 (facetType == XML_SCHEMA_FACET_ENUMERATION) ||
529 (facetType == XML_SCHEMA_FACET_WHITESPACE) ||
530 (facetType == XML_SCHEMA_FACET_MAXINCLUSIVE) ||
531 (facetType == XML_SCHEMA_FACET_MAXEXCLUSIVE) ||
532 (facetType == XML_SCHEMA_FACET_MININCLUSIVE) ||
533 (facetType == XML_SCHEMA_FACET_MINEXCLUSIVE))
534 return (1);
535 else
536 return (0);
537 default:
Daniel Veillardc7e3cc42004-09-28 12:33:52 +0000538 break;
Daniel Veillard01fa6152004-06-29 17:04:39 +0000539 }
540 return (0);
541}
542
543/**
544 * xmlSchemaGetBuiltInType:
545 * @type: the type of the built in type
546 *
547 * Gives you the type struct for a built-in
548 * type by its type id.
549 *
550 * Returns the type if found, NULL otherwise.
551 */
552xmlSchemaTypePtr
553xmlSchemaGetBuiltInType(xmlSchemaValType type)
554{
555 if (xmlSchemaTypesInitialized == 0)
556 xmlSchemaInitTypes();
557 switch (type) {
558
559 case XML_SCHEMAS_ANYSIMPLETYPE:
560 return (xmlSchemaTypeAnySimpleTypeDef);
561 case XML_SCHEMAS_STRING:
562 return (xmlSchemaTypeStringDef);
563 case XML_SCHEMAS_NORMSTRING:
564 return (xmlSchemaTypeNormStringDef);
565 case XML_SCHEMAS_DECIMAL:
566 return (xmlSchemaTypeDecimalDef);
567 case XML_SCHEMAS_TIME:
568 return (xmlSchemaTypeTimeDef);
569 case XML_SCHEMAS_GDAY:
570 return (xmlSchemaTypeGDayDef);
571 case XML_SCHEMAS_GMONTH:
572 return (xmlSchemaTypeGMonthDef);
573 case XML_SCHEMAS_GMONTHDAY:
574 return (xmlSchemaTypeGMonthDayDef);
575 case XML_SCHEMAS_GYEAR:
576 return (xmlSchemaTypeGYearDef);
577 case XML_SCHEMAS_GYEARMONTH:
578 return (xmlSchemaTypeGYearMonthDef);
579 case XML_SCHEMAS_DATE:
580 return (xmlSchemaTypeDateDef);
581 case XML_SCHEMAS_DATETIME:
582 return (xmlSchemaTypeDatetimeDef);
583 case XML_SCHEMAS_DURATION:
584 return (xmlSchemaTypeDurationDef);
585 case XML_SCHEMAS_FLOAT:
586 return (xmlSchemaTypeFloatDef);
587 case XML_SCHEMAS_DOUBLE:
588 return (xmlSchemaTypeDoubleDef);
589 case XML_SCHEMAS_BOOLEAN:
590 return (xmlSchemaTypeBooleanDef);
591 case XML_SCHEMAS_TOKEN:
592 return (xmlSchemaTypeTokenDef);
593 case XML_SCHEMAS_LANGUAGE:
594 return (xmlSchemaTypeLanguageDef);
595 case XML_SCHEMAS_NMTOKEN:
596 return (xmlSchemaTypeNmtokenDef);
597 case XML_SCHEMAS_NMTOKENS:
598 return (xmlSchemaTypeNmtokensDef);
599 case XML_SCHEMAS_NAME:
600 return (xmlSchemaTypeNameDef);
601 case XML_SCHEMAS_QNAME:
602 return (xmlSchemaTypeQNameDef);
603 case XML_SCHEMAS_NCNAME:
604 return (xmlSchemaTypeNCNameDef);
605 case XML_SCHEMAS_ID:
606 return (xmlSchemaTypeIdDef);
607 case XML_SCHEMAS_IDREF:
608 return (xmlSchemaTypeIdrefDef);
609 case XML_SCHEMAS_IDREFS:
610 return (xmlSchemaTypeIdrefsDef);
611 case XML_SCHEMAS_ENTITY:
612 return (xmlSchemaTypeEntityDef);
613 case XML_SCHEMAS_ENTITIES:
614 return (xmlSchemaTypeEntitiesDef);
615 case XML_SCHEMAS_NOTATION:
616 return (xmlSchemaTypeNotationDef);
617 case XML_SCHEMAS_ANYURI:
618 return (xmlSchemaTypeAnyURIDef);
619 case XML_SCHEMAS_INTEGER:
620 return (xmlSchemaTypeIntegerDef);
621 case XML_SCHEMAS_NPINTEGER:
622 return (xmlSchemaTypeNonPositiveIntegerDef);
623 case XML_SCHEMAS_NINTEGER:
624 return (xmlSchemaTypeNegativeIntegerDef);
625 case XML_SCHEMAS_NNINTEGER:
626 return (xmlSchemaTypeNonNegativeIntegerDef);
627 case XML_SCHEMAS_PINTEGER:
628 return (xmlSchemaTypePositiveIntegerDef);
629 case XML_SCHEMAS_INT:
630 return (xmlSchemaTypeIntDef);
631 case XML_SCHEMAS_UINT:
632 return (xmlSchemaTypeUnsignedIntDef);
633 case XML_SCHEMAS_LONG:
634 return (xmlSchemaTypeLongDef);
635 case XML_SCHEMAS_ULONG:
636 return (xmlSchemaTypeUnsignedLongDef);
637 case XML_SCHEMAS_SHORT:
638 return (xmlSchemaTypeShortDef);
639 case XML_SCHEMAS_USHORT:
640 return (xmlSchemaTypeUnsignedShortDef);
641 case XML_SCHEMAS_BYTE:
642 return (xmlSchemaTypeByteDef);
643 case XML_SCHEMAS_UBYTE:
644 return (xmlSchemaTypeUnsignedByteDef);
645 case XML_SCHEMAS_HEXBINARY:
646 return (xmlSchemaTypeHexBinaryDef);
647 case XML_SCHEMAS_BASE64BINARY:
648 return (xmlSchemaTypeBase64BinaryDef);
649 case XML_SCHEMAS_ANYTYPE:
650 return (xmlSchemaTypeAnyTypeDef);
651 default:
652 return (NULL);
653 }
654}
655
656/**
Daniel Veillard4255d502002-04-16 15:50:10 +0000657 * xmlSchemaNewValue:
658 * @type: the value type
659 *
660 * Allocate a new simple type value
661 *
662 * Returns a pointer to the new value or NULL in case of error
663 */
664static xmlSchemaValPtr
665xmlSchemaNewValue(xmlSchemaValType type) {
666 xmlSchemaValPtr value;
667
668 value = (xmlSchemaValPtr) xmlMalloc(sizeof(xmlSchemaVal));
669 if (value == NULL) {
670 return(NULL);
671 }
672 memset(value, 0, sizeof(xmlSchemaVal));
673 value->type = type;
674 return(value);
675}
676
677/**
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +0000678 * xmlSchemaNewStringValue:
679 * @type: the value type
Daniel Veillardb5839c32005-02-19 18:27:14 +0000680 * @value: the value
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +0000681 *
682 * Allocate a new simple type value. The type can be
Kasimier T. Buchcik2ee855d2005-03-07 11:14:14 +0000683 * of XML_SCHEMAS_STRING.
684 * WARNING: This one is intended to be expanded for other
685 * string based types. We need this for anySimpleType as well.
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +0000686 *
687 * Returns a pointer to the new value or NULL in case of error
688 */
689xmlSchemaValPtr
690xmlSchemaNewStringValue(xmlSchemaValType type,
691 const xmlChar *value)
692{
693 xmlSchemaValPtr val;
694
695 if (type != XML_SCHEMAS_STRING)
696 return(NULL);
697 val = (xmlSchemaValPtr) xmlMalloc(sizeof(xmlSchemaVal));
698 if (val == NULL) {
699 return(NULL);
700 }
701 memset(val, 0, sizeof(xmlSchemaVal));
702 val->type = type;
703 val->value.str = (xmlChar *) value;
704 return(val);
705}
706
Kasimier T. Buchcikb06b4de2005-02-17 19:00:23 +0000707/**
708 * xmlSchemaNewNOTATIONValue:
Daniel Veillardb5839c32005-02-19 18:27:14 +0000709 * @name: the notation name
710 * @ns: the notation namespace name or NULL
Kasimier T. Buchcikb06b4de2005-02-17 19:00:23 +0000711 *
712 * Allocate a new NOTATION value.
713 *
714 * Returns a pointer to the new value or NULL in case of error
715 */
716xmlSchemaValPtr
717xmlSchemaNewNOTATIONValue(const xmlChar *name,
718 const xmlChar *ns)
719{
720 xmlSchemaValPtr val;
721
722 val = xmlSchemaNewValue(XML_SCHEMAS_NOTATION);
723 if (val == NULL)
724 return (NULL);
725
William M. Brack12d37ab2005-02-21 13:54:07 +0000726 val->value.qname.name = (xmlChar *)name;
Kasimier T. Buchcikb06b4de2005-02-17 19:00:23 +0000727 if (ns != NULL)
William M. Brack12d37ab2005-02-21 13:54:07 +0000728 val->value.qname.uri = (xmlChar *)ns;
Kasimier T. Buchcikb06b4de2005-02-17 19:00:23 +0000729 return(val);
730}
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +0000731
732/**
Daniel Veillard4255d502002-04-16 15:50:10 +0000733 * xmlSchemaFreeValue:
734 * @value: the value to free
735 *
736 * Cleanup the default XML Schemas type library
737 */
738void
739xmlSchemaFreeValue(xmlSchemaValPtr value) {
740 if (value == NULL)
741 return;
Daniel Veillardc4c21552003-03-29 10:53:38 +0000742 switch (value->type) {
743 case XML_SCHEMAS_STRING:
744 case XML_SCHEMAS_NORMSTRING:
745 case XML_SCHEMAS_TOKEN:
746 case XML_SCHEMAS_LANGUAGE:
747 case XML_SCHEMAS_NMTOKEN:
748 case XML_SCHEMAS_NMTOKENS:
749 case XML_SCHEMAS_NAME:
Daniel Veillardc4c21552003-03-29 10:53:38 +0000750 case XML_SCHEMAS_NCNAME:
751 case XML_SCHEMAS_ID:
752 case XML_SCHEMAS_IDREF:
753 case XML_SCHEMAS_IDREFS:
754 case XML_SCHEMAS_ENTITY:
Kasimier T. Buchcikb06b4de2005-02-17 19:00:23 +0000755 case XML_SCHEMAS_ENTITIES:
Daniel Veillardc4c21552003-03-29 10:53:38 +0000756 case XML_SCHEMAS_ANYURI:
757 if (value->value.str != NULL)
758 xmlFree(value->value.str);
759 break;
Kasimier T. Buchcikb06b4de2005-02-17 19:00:23 +0000760 case XML_SCHEMAS_NOTATION:
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000761 case XML_SCHEMAS_QNAME:
762 if (value->value.qname.uri != NULL)
763 xmlFree(value->value.qname.uri);
764 if (value->value.qname.name != NULL)
765 xmlFree(value->value.qname.name);
766 break;
Daniel Veillard70bcb0e2003-08-08 14:00:28 +0000767 case XML_SCHEMAS_HEXBINARY:
768 if (value->value.hex.str != NULL)
769 xmlFree(value->value.hex.str);
770 break;
Daniel Veillard1ac24d32003-08-27 14:15:15 +0000771 case XML_SCHEMAS_BASE64BINARY:
772 if (value->value.base64.str != NULL)
773 xmlFree(value->value.base64.str);
774 break;
Daniel Veillardc4c21552003-03-29 10:53:38 +0000775 default:
776 break;
777 }
Daniel Veillard4255d502002-04-16 15:50:10 +0000778 xmlFree(value);
779}
780
781/**
782 * xmlSchemaGetPredefinedType:
783 * @name: the type name
784 * @ns: the URI of the namespace usually "http://www.w3.org/2001/XMLSchema"
785 *
786 * Lookup a type in the default XML Schemas type library
787 *
788 * Returns the type if found, NULL otherwise
789 */
790xmlSchemaTypePtr
791xmlSchemaGetPredefinedType(const xmlChar *name, const xmlChar *ns) {
792 if (xmlSchemaTypesInitialized == 0)
793 xmlSchemaInitTypes();
794 if (name == NULL)
795 return(NULL);
796 return((xmlSchemaTypePtr) xmlHashLookup2(xmlSchemaTypesBank, name, ns));
797}
Daniel Veillard070803b2002-05-03 07:29:38 +0000798
Daniel Veillard01fa6152004-06-29 17:04:39 +0000799/**
800 * xmlSchemaGetBuiltInListSimpleTypeItemType:
801 * @type: the built-in simple type.
802 *
Daniel Veillard6927b102004-10-27 17:29:04 +0000803 * Lookup function
804 *
Daniel Veillardc0826a72004-08-10 14:17:33 +0000805 * Returns the item type of @type as defined by the built-in datatype
806 * hierarchy of XML Schema Part 2: Datatypes, or NULL in case of an error.
Daniel Veillard01fa6152004-06-29 17:04:39 +0000807 */
808xmlSchemaTypePtr
809xmlSchemaGetBuiltInListSimpleTypeItemType(xmlSchemaTypePtr type)
810{
Daniel Veillard42595322004-11-08 10:52:06 +0000811 if ((type == NULL) || (type->type != XML_SCHEMA_TYPE_BASIC))
Daniel Veillard01fa6152004-06-29 17:04:39 +0000812 return (NULL);
813 switch (type->builtInType) {
814 case XML_SCHEMAS_NMTOKENS:
815 return (xmlSchemaTypeNmtokenDef );
816 case XML_SCHEMAS_IDREFS:
817 return (xmlSchemaTypeIdrefDef);
818 case XML_SCHEMAS_ENTITIES:
819 return (xmlSchemaTypeEntityDef);
820 default:
821 return (NULL);
822 }
823}
824
Daniel Veillard070803b2002-05-03 07:29:38 +0000825/****************************************************************
826 * *
827 * Convenience macros and functions *
828 * *
829 ****************************************************************/
830
831#define IS_TZO_CHAR(c) \
832 ((c == 0) || (c == 'Z') || (c == '+') || (c == '-'))
833
834#define VALID_YEAR(yr) (yr != 0)
835#define VALID_MONTH(mon) ((mon >= 1) && (mon <= 12))
836/* VALID_DAY should only be used when month is unknown */
837#define VALID_DAY(day) ((day >= 1) && (day <= 31))
838#define VALID_HOUR(hr) ((hr >= 0) && (hr <= 23))
839#define VALID_MIN(min) ((min >= 0) && (min <= 59))
840#define VALID_SEC(sec) ((sec >= 0) && (sec < 60))
841#define VALID_TZO(tzo) ((tzo > -1440) && (tzo < 1440))
842#define IS_LEAP(y) \
843 (((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0))
844
Daniel Veillardebe25d42004-03-25 09:35:49 +0000845static const unsigned int daysInMonth[12] =
Daniel Veillard070803b2002-05-03 07:29:38 +0000846 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
Daniel Veillardebe25d42004-03-25 09:35:49 +0000847static const unsigned int daysInMonthLeap[12] =
Daniel Veillard070803b2002-05-03 07:29:38 +0000848 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
849
Daniel Veillard5a872412002-05-22 06:40:27 +0000850#define MAX_DAYINMONTH(yr,mon) \
851 (IS_LEAP(yr) ? daysInMonthLeap[mon - 1] : daysInMonth[mon - 1])
852
Daniel Veillard070803b2002-05-03 07:29:38 +0000853#define VALID_MDAY(dt) \
854 (IS_LEAP(dt->year) ? \
855 (dt->day <= daysInMonthLeap[dt->mon - 1]) : \
856 (dt->day <= daysInMonth[dt->mon - 1]))
857
858#define VALID_DATE(dt) \
859 (VALID_YEAR(dt->year) && VALID_MONTH(dt->mon) && VALID_MDAY(dt))
860
861#define VALID_TIME(dt) \
862 (VALID_HOUR(dt->hour) && VALID_MIN(dt->min) && \
863 VALID_SEC(dt->sec) && VALID_TZO(dt->tzo))
864
865#define VALID_DATETIME(dt) \
866 (VALID_DATE(dt) && VALID_TIME(dt))
867
868#define SECS_PER_MIN (60)
869#define SECS_PER_HOUR (60 * SECS_PER_MIN)
870#define SECS_PER_DAY (24 * SECS_PER_HOUR)
871
Daniel Veillard5a872412002-05-22 06:40:27 +0000872static const long dayInYearByMonth[12] =
873 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
874static const long dayInLeapYearByMonth[12] =
875 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 };
876
877#define DAY_IN_YEAR(day, month, year) \
878 ((IS_LEAP(year) ? \
879 dayInLeapYearByMonth[month - 1] : \
880 dayInYearByMonth[month - 1]) + day)
881
882#ifdef DEBUG
883#define DEBUG_DATE(dt) \
884 xmlGenericError(xmlGenericErrorContext, \
885 "type=%o %04ld-%02u-%02uT%02u:%02u:%03f", \
886 dt->type,dt->value.date.year,dt->value.date.mon, \
887 dt->value.date.day,dt->value.date.hour,dt->value.date.min, \
888 dt->value.date.sec); \
889 if (dt->value.date.tz_flag) \
890 if (dt->value.date.tzo != 0) \
891 xmlGenericError(xmlGenericErrorContext, \
892 "%+05d\n",dt->value.date.tzo); \
893 else \
894 xmlGenericError(xmlGenericErrorContext, "Z\n"); \
895 else \
896 xmlGenericError(xmlGenericErrorContext,"\n")
897#else
898#define DEBUG_DATE(dt)
899#endif
900
Daniel Veillard070803b2002-05-03 07:29:38 +0000901/**
902 * _xmlSchemaParseGYear:
903 * @dt: pointer to a date structure
904 * @str: pointer to the string to analyze
905 *
906 * Parses a xs:gYear without time zone and fills in the appropriate
907 * field of the @dt structure. @str is updated to point just after the
908 * xs:gYear. It is supposed that @dt->year is big enough to contain
909 * the year.
910 *
911 * Returns 0 or the error code
912 */
913static int
914_xmlSchemaParseGYear (xmlSchemaValDatePtr dt, const xmlChar **str) {
915 const xmlChar *cur = *str, *firstChar;
916 int isneg = 0, digcnt = 0;
917
918 if (((*cur < '0') || (*cur > '9')) &&
919 (*cur != '-') && (*cur != '+'))
920 return -1;
921
922 if (*cur == '-') {
923 isneg = 1;
924 cur++;
925 }
926
927 firstChar = cur;
928
929 while ((*cur >= '0') && (*cur <= '9')) {
930 dt->year = dt->year * 10 + (*cur - '0');
931 cur++;
932 digcnt++;
933 }
934
935 /* year must be at least 4 digits (CCYY); over 4
936 * digits cannot have a leading zero. */
937 if ((digcnt < 4) || ((digcnt > 4) && (*firstChar == '0')))
938 return 1;
939
940 if (isneg)
941 dt->year = - dt->year;
942
943 if (!VALID_YEAR(dt->year))
944 return 2;
945
946 *str = cur;
947 return 0;
948}
949
950/**
951 * PARSE_2_DIGITS:
952 * @num: the integer to fill in
953 * @cur: an #xmlChar *
954 * @invalid: an integer
955 *
956 * Parses a 2-digits integer and updates @num with the value. @cur is
957 * updated to point just after the integer.
958 * In case of error, @invalid is set to %TRUE, values of @num and
959 * @cur are undefined.
960 */
961#define PARSE_2_DIGITS(num, cur, invalid) \
962 if ((cur[0] < '0') || (cur[0] > '9') || \
963 (cur[1] < '0') || (cur[1] > '9')) \
964 invalid = 1; \
965 else \
966 num = (cur[0] - '0') * 10 + (cur[1] - '0'); \
967 cur += 2;
968
969/**
970 * PARSE_FLOAT:
971 * @num: the double to fill in
972 * @cur: an #xmlChar *
973 * @invalid: an integer
974 *
975 * Parses a float and updates @num with the value. @cur is
976 * updated to point just after the float. The float must have a
977 * 2-digits integer part and may or may not have a decimal part.
978 * In case of error, @invalid is set to %TRUE, values of @num and
979 * @cur are undefined.
980 */
981#define PARSE_FLOAT(num, cur, invalid) \
982 PARSE_2_DIGITS(num, cur, invalid); \
983 if (!invalid && (*cur == '.')) { \
984 double mult = 1; \
985 cur++; \
986 if ((*cur < '0') || (*cur > '9')) \
987 invalid = 1; \
988 while ((*cur >= '0') && (*cur <= '9')) { \
989 mult /= 10; \
990 num += (*cur - '0') * mult; \
991 cur++; \
992 } \
993 }
994
995/**
996 * _xmlSchemaParseGMonth:
997 * @dt: pointer to a date structure
998 * @str: pointer to the string to analyze
999 *
1000 * Parses a xs:gMonth without time zone and fills in the appropriate
1001 * field of the @dt structure. @str is updated to point just after the
1002 * xs:gMonth.
1003 *
1004 * Returns 0 or the error code
1005 */
1006static int
1007_xmlSchemaParseGMonth (xmlSchemaValDatePtr dt, const xmlChar **str) {
1008 const xmlChar *cur = *str;
1009 int ret = 0;
1010
1011 PARSE_2_DIGITS(dt->mon, cur, ret);
1012 if (ret != 0)
1013 return ret;
1014
1015 if (!VALID_MONTH(dt->mon))
1016 return 2;
1017
1018 *str = cur;
1019 return 0;
1020}
1021
1022/**
1023 * _xmlSchemaParseGDay:
1024 * @dt: pointer to a date structure
1025 * @str: pointer to the string to analyze
1026 *
1027 * Parses a xs:gDay without time zone and fills in the appropriate
1028 * field of the @dt structure. @str is updated to point just after the
1029 * xs:gDay.
1030 *
1031 * Returns 0 or the error code
1032 */
1033static int
1034_xmlSchemaParseGDay (xmlSchemaValDatePtr dt, const xmlChar **str) {
1035 const xmlChar *cur = *str;
1036 int ret = 0;
1037
1038 PARSE_2_DIGITS(dt->day, cur, ret);
1039 if (ret != 0)
1040 return ret;
1041
1042 if (!VALID_DAY(dt->day))
1043 return 2;
1044
1045 *str = cur;
1046 return 0;
1047}
1048
1049/**
1050 * _xmlSchemaParseTime:
1051 * @dt: pointer to a date structure
1052 * @str: pointer to the string to analyze
1053 *
1054 * Parses a xs:time without time zone and fills in the appropriate
1055 * fields of the @dt structure. @str is updated to point just after the
1056 * xs:time.
1057 * In case of error, values of @dt fields are undefined.
1058 *
1059 * Returns 0 or the error code
1060 */
1061static int
1062_xmlSchemaParseTime (xmlSchemaValDatePtr dt, const xmlChar **str) {
1063 const xmlChar *cur = *str;
1064 unsigned int hour = 0; /* use temp var in case str is not xs:time */
1065 int ret = 0;
1066
1067 PARSE_2_DIGITS(hour, cur, ret);
1068 if (ret != 0)
1069 return ret;
1070
1071 if (*cur != ':')
1072 return 1;
1073 cur++;
1074
1075 /* the ':' insures this string is xs:time */
1076 dt->hour = hour;
1077
1078 PARSE_2_DIGITS(dt->min, cur, ret);
1079 if (ret != 0)
1080 return ret;
1081
1082 if (*cur != ':')
1083 return 1;
1084 cur++;
1085
1086 PARSE_FLOAT(dt->sec, cur, ret);
1087 if (ret != 0)
1088 return ret;
1089
1090 if (!VALID_TIME(dt))
1091 return 2;
1092
1093 *str = cur;
1094 return 0;
1095}
1096
1097/**
1098 * _xmlSchemaParseTimeZone:
1099 * @dt: pointer to a date structure
1100 * @str: pointer to the string to analyze
1101 *
1102 * Parses a time zone without time zone and fills in the appropriate
1103 * field of the @dt structure. @str is updated to point just after the
1104 * time zone.
1105 *
1106 * Returns 0 or the error code
1107 */
1108static int
1109_xmlSchemaParseTimeZone (xmlSchemaValDatePtr dt, const xmlChar **str) {
1110 const xmlChar *cur = *str;
1111 int ret = 0;
1112
1113 if (str == NULL)
1114 return -1;
1115
1116 switch (*cur) {
1117 case 0:
1118 dt->tz_flag = 0;
1119 dt->tzo = 0;
1120 break;
1121
1122 case 'Z':
1123 dt->tz_flag = 1;
1124 dt->tzo = 0;
1125 cur++;
1126 break;
1127
1128 case '+':
1129 case '-': {
1130 int isneg = 0, tmp = 0;
1131 isneg = (*cur == '-');
1132
1133 cur++;
1134
1135 PARSE_2_DIGITS(tmp, cur, ret);
1136 if (ret != 0)
1137 return ret;
1138 if (!VALID_HOUR(tmp))
1139 return 2;
1140
1141 if (*cur != ':')
1142 return 1;
1143 cur++;
1144
1145 dt->tzo = tmp * 60;
1146
1147 PARSE_2_DIGITS(tmp, cur, ret);
1148 if (ret != 0)
1149 return ret;
1150 if (!VALID_MIN(tmp))
1151 return 2;
1152
1153 dt->tzo += tmp;
1154 if (isneg)
1155 dt->tzo = - dt->tzo;
1156
1157 if (!VALID_TZO(dt->tzo))
1158 return 2;
1159
Daniel Veillard5a872412002-05-22 06:40:27 +00001160 dt->tz_flag = 1;
Daniel Veillard070803b2002-05-03 07:29:38 +00001161 break;
1162 }
1163 default:
1164 return 1;
1165 }
1166
1167 *str = cur;
1168 return 0;
1169}
1170
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001171/**
1172 * _xmlSchemaBase64Decode:
1173 * @ch: a character
1174 *
1175 * Converts a base64 encoded character to its base 64 value.
1176 *
1177 * Returns 0-63 (value), 64 (pad), or -1 (not recognized)
1178 */
1179static int
1180_xmlSchemaBase64Decode (const xmlChar ch) {
1181 if (('A' <= ch) && (ch <= 'Z')) return ch - 'A';
1182 if (('a' <= ch) && (ch <= 'z')) return ch - 'a' + 26;
1183 if (('0' <= ch) && (ch <= '9')) return ch - '0' + 52;
1184 if ('+' == ch) return 62;
1185 if ('/' == ch) return 63;
1186 if ('=' == ch) return 64;
1187 return -1;
1188}
1189
Daniel Veillard070803b2002-05-03 07:29:38 +00001190/****************************************************************
1191 * *
1192 * XML Schema Dates/Times Datatypes Handling *
1193 * *
1194 ****************************************************************/
1195
1196/**
1197 * PARSE_DIGITS:
1198 * @num: the integer to fill in
1199 * @cur: an #xmlChar *
1200 * @num_type: an integer flag
1201 *
1202 * Parses a digits integer and updates @num with the value. @cur is
1203 * updated to point just after the integer.
1204 * In case of error, @num_type is set to -1, values of @num and
1205 * @cur are undefined.
1206 */
1207#define PARSE_DIGITS(num, cur, num_type) \
1208 if ((*cur < '0') || (*cur > '9')) \
1209 num_type = -1; \
1210 else \
1211 while ((*cur >= '0') && (*cur <= '9')) { \
1212 num = num * 10 + (*cur - '0'); \
1213 cur++; \
1214 }
1215
1216/**
1217 * PARSE_NUM:
1218 * @num: the double to fill in
1219 * @cur: an #xmlChar *
1220 * @num_type: an integer flag
1221 *
1222 * Parses a float or integer and updates @num with the value. @cur is
1223 * updated to point just after the number. If the number is a float,
1224 * then it must have an integer part and a decimal part; @num_type will
1225 * be set to 1. If there is no decimal part, @num_type is set to zero.
1226 * In case of error, @num_type is set to -1, values of @num and
1227 * @cur are undefined.
1228 */
1229#define PARSE_NUM(num, cur, num_type) \
1230 num = 0; \
1231 PARSE_DIGITS(num, cur, num_type); \
1232 if (!num_type && (*cur == '.')) { \
1233 double mult = 1; \
1234 cur++; \
1235 if ((*cur < '0') || (*cur > '9')) \
1236 num_type = -1; \
1237 else \
1238 num_type = 1; \
1239 while ((*cur >= '0') && (*cur <= '9')) { \
1240 mult /= 10; \
1241 num += (*cur - '0') * mult; \
1242 cur++; \
1243 } \
1244 }
1245
1246/**
Daniel Veillard5a872412002-05-22 06:40:27 +00001247 * xmlSchemaValidateDates:
Daniel Veillard455cc072003-03-31 10:13:23 +00001248 * @type: the expected type or XML_SCHEMAS_UNKNOWN
Daniel Veillard070803b2002-05-03 07:29:38 +00001249 * @dateTime: string to analyze
1250 * @val: the return computed value
1251 *
1252 * Check that @dateTime conforms to the lexical space of one of the date types.
1253 * if true a value is computed and returned in @val.
1254 *
1255 * Returns 0 if this validates, a positive error code number otherwise
1256 * and -1 in case of internal or API error.
1257 */
1258static int
Daniel Veillard455cc072003-03-31 10:13:23 +00001259xmlSchemaValidateDates (xmlSchemaValType type,
Daniel Veillard118aed72002-09-24 14:13:13 +00001260 const xmlChar *dateTime, xmlSchemaValPtr *val) {
Daniel Veillard070803b2002-05-03 07:29:38 +00001261 xmlSchemaValPtr dt;
1262 int ret;
1263 const xmlChar *cur = dateTime;
1264
1265#define RETURN_TYPE_IF_VALID(t) \
1266 if (IS_TZO_CHAR(*cur)) { \
1267 ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur); \
1268 if (ret == 0) { \
1269 if (*cur != 0) \
1270 goto error; \
1271 dt->type = t; \
Daniel Veillard455cc072003-03-31 10:13:23 +00001272 goto done; \
Daniel Veillard070803b2002-05-03 07:29:38 +00001273 } \
1274 }
1275
1276 if (dateTime == NULL)
1277 return -1;
1278
1279 if ((*cur != '-') && (*cur < '0') && (*cur > '9'))
1280 return 1;
1281
1282 dt = xmlSchemaNewValue(XML_SCHEMAS_UNKNOWN);
1283 if (dt == NULL)
1284 return -1;
1285
1286 if ((cur[0] == '-') && (cur[1] == '-')) {
1287 /*
1288 * It's an incomplete date (xs:gMonthDay, xs:gMonth or
1289 * xs:gDay)
1290 */
1291 cur += 2;
1292
1293 /* is it an xs:gDay? */
1294 if (*cur == '-') {
Daniel Veillard455cc072003-03-31 10:13:23 +00001295 if (type == XML_SCHEMAS_GMONTH)
1296 goto error;
Daniel Veillard070803b2002-05-03 07:29:38 +00001297 ++cur;
1298 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
1299 if (ret != 0)
1300 goto error;
1301
1302 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GDAY);
1303
1304 goto error;
1305 }
1306
1307 /*
1308 * it should be an xs:gMonthDay or xs:gMonth
1309 */
1310 ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
1311 if (ret != 0)
1312 goto error;
1313
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001314 /*
1315 * a '-' char could indicate this type is xs:gMonthDay or
1316 * a negative time zone offset. Check for xs:gMonthDay first.
1317 * Also the first three char's of a negative tzo (-MM:SS) can
1318 * appear to be a valid day; so even if the day portion
1319 * of the xs:gMonthDay verifies, we must insure it was not
1320 * a tzo.
1321 */
1322 if (*cur == '-') {
1323 const xmlChar *rewnd = cur;
1324 cur++;
Daniel Veillard070803b2002-05-03 07:29:38 +00001325
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001326 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
1327 if ((ret == 0) && ((*cur == 0) || (*cur != ':'))) {
1328
1329 /*
1330 * we can use the VALID_MDAY macro to validate the month
1331 * and day because the leap year test will flag year zero
1332 * as a leap year (even though zero is an invalid year).
1333 */
1334 if (VALID_MDAY((&(dt->value.date)))) {
1335
1336 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTHDAY);
1337
1338 goto error;
1339 }
1340 }
1341
1342 /*
1343 * not xs:gMonthDay so rewind and check if just xs:gMonth
1344 * with an optional time zone.
1345 */
1346 cur = rewnd;
1347 }
1348
1349 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTH);
Daniel Veillard070803b2002-05-03 07:29:38 +00001350
1351 goto error;
1352 }
1353
1354 /*
1355 * It's a right-truncated date or an xs:time.
1356 * Try to parse an xs:time then fallback on right-truncated dates.
1357 */
1358 if ((*cur >= '0') && (*cur <= '9')) {
1359 ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
1360 if (ret == 0) {
1361 /* it's an xs:time */
1362 RETURN_TYPE_IF_VALID(XML_SCHEMAS_TIME);
1363 }
1364 }
1365
1366 /* fallback on date parsing */
1367 cur = dateTime;
1368
1369 ret = _xmlSchemaParseGYear(&(dt->value.date), &cur);
1370 if (ret != 0)
1371 goto error;
1372
1373 /* is it an xs:gYear? */
1374 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEAR);
1375
1376 if (*cur != '-')
1377 goto error;
1378 cur++;
1379
1380 ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
1381 if (ret != 0)
1382 goto error;
1383
1384 /* is it an xs:gYearMonth? */
1385 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEARMONTH);
1386
1387 if (*cur != '-')
1388 goto error;
1389 cur++;
1390
1391 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
1392 if ((ret != 0) || !VALID_DATE((&(dt->value.date))))
1393 goto error;
1394
1395 /* is it an xs:date? */
1396 RETURN_TYPE_IF_VALID(XML_SCHEMAS_DATE);
1397
1398 if (*cur != 'T')
1399 goto error;
1400 cur++;
1401
1402 /* it should be an xs:dateTime */
1403 ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
1404 if (ret != 0)
1405 goto error;
1406
1407 ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur);
1408 if ((ret != 0) || (*cur != 0) || !VALID_DATETIME((&(dt->value.date))))
1409 goto error;
1410
Daniel Veillard455cc072003-03-31 10:13:23 +00001411
Daniel Veillard070803b2002-05-03 07:29:38 +00001412 dt->type = XML_SCHEMAS_DATETIME;
1413
Daniel Veillard455cc072003-03-31 10:13:23 +00001414done:
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001415#if 1
1416 if ((type != XML_SCHEMAS_UNKNOWN) && (type != dt->type))
1417 goto error;
1418#else
1419 /*
1420 * insure the parsed type is equal to or less significant (right
1421 * truncated) than the desired type.
1422 */
1423 if ((type != XML_SCHEMAS_UNKNOWN) && (type != dt->type)) {
1424
1425 /* time only matches time */
1426 if ((type == XML_SCHEMAS_TIME) && (dt->type == XML_SCHEMAS_TIME))
1427 goto error;
1428
1429 if ((type == XML_SCHEMAS_DATETIME) &&
1430 ((dt->type != XML_SCHEMAS_DATE) ||
1431 (dt->type != XML_SCHEMAS_GYEARMONTH) ||
1432 (dt->type != XML_SCHEMAS_GYEAR)))
1433 goto error;
1434
1435 if ((type == XML_SCHEMAS_DATE) &&
1436 ((dt->type != XML_SCHEMAS_GYEAR) ||
1437 (dt->type != XML_SCHEMAS_GYEARMONTH)))
1438 goto error;
1439
1440 if ((type == XML_SCHEMAS_GYEARMONTH) && (dt->type != XML_SCHEMAS_GYEAR))
1441 goto error;
1442
1443 if ((type == XML_SCHEMAS_GMONTHDAY) && (dt->type != XML_SCHEMAS_GMONTH))
1444 goto error;
1445 }
Daniel Veillard455cc072003-03-31 10:13:23 +00001446#endif
1447
Daniel Veillard070803b2002-05-03 07:29:38 +00001448 if (val != NULL)
1449 *val = dt;
Daniel Veillard80b19092003-03-28 13:29:53 +00001450 else
1451 xmlSchemaFreeValue(dt);
Daniel Veillard070803b2002-05-03 07:29:38 +00001452
1453 return 0;
1454
1455error:
1456 if (dt != NULL)
1457 xmlSchemaFreeValue(dt);
1458 return 1;
1459}
1460
1461/**
Daniel Veillard5a872412002-05-22 06:40:27 +00001462 * xmlSchemaValidateDuration:
Daniel Veillard070803b2002-05-03 07:29:38 +00001463 * @type: the predefined type
1464 * @duration: string to analyze
1465 * @val: the return computed value
1466 *
1467 * Check that @duration conforms to the lexical space of the duration type.
1468 * if true a value is computed and returned in @val.
1469 *
1470 * Returns 0 if this validates, a positive error code number otherwise
1471 * and -1 in case of internal or API error.
1472 */
1473static int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00001474xmlSchemaValidateDuration (xmlSchemaTypePtr type ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +00001475 const xmlChar *duration, xmlSchemaValPtr *val) {
Daniel Veillard070803b2002-05-03 07:29:38 +00001476 const xmlChar *cur = duration;
1477 xmlSchemaValPtr dur;
1478 int isneg = 0;
1479 unsigned int seq = 0;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001480 double num;
1481 int num_type = 0; /* -1 = invalid, 0 = int, 1 = floating */
1482 const xmlChar desig[] = {'Y', 'M', 'D', 'H', 'M', 'S'};
1483 const double multi[] = { 0.0, 0.0, 86400.0, 3600.0, 60.0, 1.0, 0.0};
Daniel Veillard070803b2002-05-03 07:29:38 +00001484
1485 if (duration == NULL)
1486 return -1;
1487
1488 if (*cur == '-') {
1489 isneg = 1;
1490 cur++;
1491 }
1492
1493 /* duration must start with 'P' (after sign) */
1494 if (*cur++ != 'P')
1495 return 1;
1496
Daniel Veillard80b19092003-03-28 13:29:53 +00001497 if (*cur == 0)
1498 return 1;
1499
Daniel Veillard070803b2002-05-03 07:29:38 +00001500 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
1501 if (dur == NULL)
1502 return -1;
1503
1504 while (*cur != 0) {
Daniel Veillard070803b2002-05-03 07:29:38 +00001505
1506 /* input string should be empty or invalid date/time item */
1507 if (seq >= sizeof(desig))
1508 goto error;
1509
1510 /* T designator must be present for time items */
1511 if (*cur == 'T') {
1512 if (seq <= 3) {
1513 seq = 3;
1514 cur++;
1515 } else
1516 return 1;
1517 } else if (seq == 3)
1518 goto error;
1519
1520 /* parse the number portion of the item */
1521 PARSE_NUM(num, cur, num_type);
1522
1523 if ((num_type == -1) || (*cur == 0))
1524 goto error;
1525
1526 /* update duration based on item type */
1527 while (seq < sizeof(desig)) {
1528 if (*cur == desig[seq]) {
1529
1530 /* verify numeric type; only seconds can be float */
1531 if ((num_type != 0) && (seq < (sizeof(desig)-1)))
1532 goto error;
1533
1534 switch (seq) {
1535 case 0:
1536 dur->value.dur.mon = (long)num * 12;
1537 break;
1538 case 1:
1539 dur->value.dur.mon += (long)num;
1540 break;
1541 default:
1542 /* convert to seconds using multiplier */
1543 dur->value.dur.sec += num * multi[seq];
1544 seq++;
1545 break;
1546 }
1547
1548 break; /* exit loop */
1549 }
1550 /* no date designators found? */
1551 if (++seq == 3)
1552 goto error;
1553 }
1554 cur++;
1555 }
1556
1557 if (isneg) {
1558 dur->value.dur.mon = -dur->value.dur.mon;
1559 dur->value.dur.day = -dur->value.dur.day;
1560 dur->value.dur.sec = -dur->value.dur.sec;
1561 }
1562
1563 if (val != NULL)
1564 *val = dur;
Daniel Veillard80b19092003-03-28 13:29:53 +00001565 else
1566 xmlSchemaFreeValue(dur);
Daniel Veillard070803b2002-05-03 07:29:38 +00001567
1568 return 0;
1569
1570error:
1571 if (dur != NULL)
1572 xmlSchemaFreeValue(dur);
1573 return 1;
1574}
1575
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001576/**
1577 * xmlSchemaStrip:
1578 * @value: a value
1579 *
1580 * Removes the leading and ending spaces of a string
1581 *
1582 * Returns the new string or NULL if no change was required.
1583 */
1584static xmlChar *
1585xmlSchemaStrip(const xmlChar *value) {
1586 const xmlChar *start = value, *end, *f;
1587
1588 if (value == NULL) return(NULL);
William M. Brack76e95df2003-10-18 16:20:14 +00001589 while ((*start != 0) && (IS_BLANK_CH(*start))) start++;
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001590 end = start;
1591 while (*end != 0) end++;
1592 f = end;
1593 end--;
William M. Brack76e95df2003-10-18 16:20:14 +00001594 while ((end > start) && (IS_BLANK_CH(*end))) end--;
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001595 end++;
1596 if ((start == value) && (f == end)) return(NULL);
1597 return(xmlStrndup(start, end - start));
1598}
Daniel Veillard96a4b252003-02-06 08:22:32 +00001599
1600/**
Kasimier T. Buchcik91feaf82004-11-12 14:04:58 +00001601 * xmlSchemaWhiteSpaceReplace:
1602 * @value: a value
1603 *
1604 * Replaces 0xd, 0x9 and 0xa with a space.
1605 *
1606 * Returns the new string or NULL if no change was required.
1607 */
1608xmlChar *
1609xmlSchemaWhiteSpaceReplace(const xmlChar *value) {
1610 const xmlChar *cur = value;
1611 xmlChar *ret = NULL, *mcur;
1612
1613 if (value == NULL)
1614 return(NULL);
1615
1616 while ((*cur != 0) &&
1617 (((*cur) != 0xd) && ((*cur) != 0x9) && ((*cur) != 0xa))) {
1618 cur++;
1619 }
1620 if (*cur == 0)
1621 return (NULL);
1622 ret = xmlStrdup(value);
1623 /* TODO FIXME: I guess gcc will bark at this. */
1624 mcur = (xmlChar *) (ret + (cur - value));
1625 do {
1626 if ( ((*mcur) == 0xd) || ((*mcur) == 0x9) || ((*mcur) == 0xa) )
1627 *mcur = ' ';
1628 mcur++;
1629 } while (*mcur != 0);
1630 return(ret);
1631}
1632
1633/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001634 * xmlSchemaCollapseString:
1635 * @value: a value
1636 *
1637 * Removes and normalize white spaces in the string
1638 *
1639 * Returns the new string or NULL if no change was required.
1640 */
Daniel Veillard01fa6152004-06-29 17:04:39 +00001641xmlChar *
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001642xmlSchemaCollapseString(const xmlChar *value) {
1643 const xmlChar *start = value, *end, *f;
1644 xmlChar *g;
1645 int col = 0;
1646
1647 if (value == NULL) return(NULL);
William M. Brack76e95df2003-10-18 16:20:14 +00001648 while ((*start != 0) && (IS_BLANK_CH(*start))) start++;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001649 end = start;
1650 while (*end != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00001651 if ((*end == ' ') && (IS_BLANK_CH(end[1]))) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001652 col = end - start;
1653 break;
1654 } else if ((*end == 0xa) || (*end == 0x9) || (*end == 0xd)) {
1655 col = end - start;
1656 break;
1657 }
1658 end++;
1659 }
1660 if (col == 0) {
1661 f = end;
1662 end--;
William M. Brack76e95df2003-10-18 16:20:14 +00001663 while ((end > start) && (IS_BLANK_CH(*end))) end--;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001664 end++;
1665 if ((start == value) && (f == end)) return(NULL);
1666 return(xmlStrndup(start, end - start));
1667 }
1668 start = xmlStrdup(start);
1669 if (start == NULL) return(NULL);
1670 g = (xmlChar *) (start + col);
1671 end = g;
1672 while (*end != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00001673 if (IS_BLANK_CH(*end)) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001674 end++;
William M. Brack76e95df2003-10-18 16:20:14 +00001675 while (IS_BLANK_CH(*end)) end++;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001676 if (*end != 0)
1677 *g++ = ' ';
1678 } else
1679 *g++ = *end++;
1680 }
1681 *g = 0;
1682 return((xmlChar *) start);
1683}
1684
1685/**
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001686 * xmlSchemaValAtomicListNode:
1687 * @type: the predefined atomic type for a token in the list
1688 * @value: the list value to check
1689 * @ret: the return computed value
1690 * @node: the node containing the value
1691 *
1692 * Check that a value conforms to the lexical space of the predefined
1693 * list type. if true a value is computed and returned in @ret.
1694 *
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001695 * Returns the number of items if this validates, a negative error code
1696 * number otherwise
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001697 */
1698static int
1699xmlSchemaValAtomicListNode(xmlSchemaTypePtr type, const xmlChar *value,
1700 xmlSchemaValPtr *ret, xmlNodePtr node) {
1701 xmlChar *val, *cur, *endval;
1702 int nb_values = 0;
Daniel Veillard580ced82003-03-21 21:22:48 +00001703 int tmp = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001704
1705 if (value == NULL) {
1706 return(-1);
1707 }
1708 val = xmlStrdup(value);
1709 if (val == NULL) {
1710 return(-1);
1711 }
Daniel Veillard6fc5db02005-01-16 00:05:58 +00001712 if (ret != NULL) {
1713 *ret = NULL;
1714 }
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001715 cur = val;
1716 /*
1717 * Split the list
1718 */
William M. Brack76e95df2003-10-18 16:20:14 +00001719 while (IS_BLANK_CH(*cur)) *cur++ = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001720 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00001721 if (IS_BLANK_CH(*cur)) {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001722 *cur = 0;
1723 cur++;
William M. Brack76e95df2003-10-18 16:20:14 +00001724 while (IS_BLANK_CH(*cur)) *cur++ = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001725 } else {
1726 nb_values++;
1727 cur++;
William M. Brack76e95df2003-10-18 16:20:14 +00001728 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001729 }
1730 }
1731 if (nb_values == 0) {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001732 xmlFree(val);
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001733 return(nb_values);
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001734 }
1735 endval = cur;
1736 cur = val;
1737 while ((*cur == 0) && (cur != endval)) cur++;
1738 while (cur != endval) {
1739 tmp = xmlSchemaValPredefTypeNode(type, cur, NULL, node);
1740 if (tmp != 0)
1741 break;
1742 while (*cur != 0) cur++;
1743 while ((*cur == 0) && (cur != endval)) cur++;
1744 }
Daniel Veillard6fc5db02005-01-16 00:05:58 +00001745 /* TODO what return value ? c.f. bug #158628
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001746 if (ret != NULL) {
1747 TODO
Daniel Veillard6fc5db02005-01-16 00:05:58 +00001748 } */
1749 xmlFree(val);
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001750 if (tmp == 0)
1751 return(nb_values);
1752 return(-1);
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001753}
1754
1755/**
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001756 * xmlSchemaParseUInt:
1757 * @str: pointer to the string R/W
1758 * @llo: pointer to the low result
1759 * @lmi: pointer to the mid result
1760 * @lhi: pointer to the high result
1761 *
1762 * Parse an unsigned long into 3 fields.
1763 *
1764 * Returns the number of chars parsed or -1 if overflow of the capacity
1765 */
1766static int
1767xmlSchemaParseUInt(const xmlChar **str, unsigned long *llo,
1768 unsigned long *lmi, unsigned long *lhi) {
1769 unsigned long lo = 0, mi = 0, hi = 0;
1770 const xmlChar *tmp, *cur = *str;
1771 int ret = 0, i = 0;
1772
1773 while (*cur == '0') {
1774 ret++;
1775 cur++;
1776 }
1777 tmp = cur;
1778 while ((*tmp != 0) && (*tmp >= '0') && (*tmp <= '9')) {
1779 i++;tmp++;ret++;
1780 }
1781 if (i > 24) {
1782 *str = tmp;
1783 return(-1);
1784 }
1785 while (i > 16) {
1786 hi = hi * 10 + (*cur++ - '0');
1787 i--;
1788 }
1789 while (i > 8) {
1790 mi = mi * 10 + (*cur++ - '0');
1791 i--;
1792 }
1793 while (i > 0) {
1794 lo = lo * 10 + (*cur++ - '0');
1795 i--;
1796 }
1797
1798 *str = cur;
1799 *llo = lo;
1800 *lmi = mi;
1801 *lhi = hi;
1802 return(ret);
1803}
1804
1805/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001806 * xmlSchemaValAtomicType:
1807 * @type: the predefined type
1808 * @value: the value to check
1809 * @val: the return computed value
1810 * @node: the node containing the value
1811 * flags: flags to control the vlidation
1812 *
1813 * Check that a value conforms to the lexical space of the atomic type.
1814 * if true a value is computed and returned in @val.
Daniel Veillard01fa6152004-06-29 17:04:39 +00001815 * This checks the value space for list types as well (IDREFS, NMTOKENS).
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001816 *
1817 * Returns 0 if this validates, a positive error code number otherwise
1818 * and -1 in case of internal or API error.
1819 */
1820static int
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001821xmlSchemaValAtomicType(xmlSchemaTypePtr type, const xmlChar * value,
1822 xmlSchemaValPtr * val, xmlNodePtr node, int flags)
1823{
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001824 xmlSchemaValPtr v;
1825 xmlChar *norm = NULL;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001826 int ret = 0;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001827
1828 if (xmlSchemaTypesInitialized == 0)
Daniel Veillard01fa6152004-06-29 17:04:39 +00001829 xmlSchemaInitTypes();
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001830 if (type == NULL)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001831 return (-1);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001832
Daniel Veillardeebd6332004-08-26 10:30:44 +00001833 /*
1834 * validating a non existant text node is similar to validating
1835 * an empty one.
1836 */
1837 if (value == NULL)
1838 value = BAD_CAST "";
1839
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001840 if (val != NULL)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001841 *val = NULL;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001842 if ((flags == 0) && (value != NULL)) {
Kasimier T. Buchcik91feaf82004-11-12 14:04:58 +00001843
Daniel Veillard01fa6152004-06-29 17:04:39 +00001844 if ((type->builtInType != XML_SCHEMAS_STRING) &&
Kasimier T. Buchcik91feaf82004-11-12 14:04:58 +00001845 (type->builtInType != XML_SCHEMAS_ANYTYPE) &&
1846 (type->builtInType != XML_SCHEMAS_ANYSIMPLETYPE)) {
1847 if (type->builtInType == XML_SCHEMAS_NORMSTRING)
1848 norm = xmlSchemaWhiteSpaceReplace(value);
1849 else
1850 norm = xmlSchemaCollapseString(value);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001851 if (norm != NULL)
1852 value = norm;
1853 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001854 }
1855
Daniel Veillard01fa6152004-06-29 17:04:39 +00001856 switch (type->builtInType) {
William M. Brack2f2a6632004-08-20 23:09:47 +00001857 case XML_SCHEMAS_UNKNOWN:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001858 goto error;
William M. Brack2f2a6632004-08-20 23:09:47 +00001859 case XML_SCHEMAS_ANYTYPE:
1860 case XML_SCHEMAS_ANYSIMPLETYPE:
1861 goto return0;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001862 case XML_SCHEMAS_STRING:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001863 goto return0;
Daniel Veillard1516d5b2004-01-22 07:27:45 +00001864 case XML_SCHEMAS_NORMSTRING:{
1865 const xmlChar *cur = value;
1866
1867 while (*cur != 0) {
1868 if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) {
1869 goto return1;
1870 } else {
1871 cur++;
1872 }
1873 }
1874 if (val != NULL) {
1875 v = xmlSchemaNewValue(XML_SCHEMAS_NORMSTRING);
1876 if (v != NULL) {
1877 v->value.str = xmlStrdup(value);
1878 *val = v;
1879 } else {
1880 goto error;
1881 }
1882 }
1883 goto return0;
1884 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001885 case XML_SCHEMAS_DECIMAL:{
William M. Brack273670f2005-03-11 15:55:14 +00001886 const xmlChar *cur = value;
1887 unsigned int len, neg = 0;
1888 xmlChar cval[25];
1889 xmlChar *cptr = cval;
1890 int dec = -1;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001891
1892 if (cur == NULL)
1893 goto return1;
William M. Brack273670f2005-03-11 15:55:14 +00001894 /* First we handle an optional sign */
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001895 if (*cur == '+')
1896 cur++;
1897 else if (*cur == '-') {
1898 neg = 1;
1899 cur++;
1900 }
William M. Brack273670f2005-03-11 15:55:14 +00001901 /*
1902 * Next we "pre-parse" the number, in preparation for calling
1903 * the common routine xmlSchemaParseUInt. We get rid of any
1904 * leading zeroes (because we have reserved only 25 chars),
1905 * and note the position of any decimal point.
1906 */
1907 len = 0;
1908 while (len < 24) {
1909 if ((*cur >= '0') && (*cur <= '9')) {
1910 *cptr++ = *cur;
1911 len++;
1912 } else if (*cur == '.') {
1913 if (dec != -1)
1914 goto return1; /* multiple decimal points */
1915 if (!len) { /* num starts with '.' */
1916 *cptr++ = '0';
1917 len++;
1918 }
1919 dec = len++;
1920 } else
1921 break;
1922 cur++;
1923 }
1924 if (*cur != 0)
1925 goto return1; /* error if any extraneous chars */
1926
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001927 if (val != NULL) {
1928 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
1929 if (v != NULL) {
William M. Brack273670f2005-03-11 15:55:14 +00001930 /*
1931 * If a mixed decimal, get rid of trailing zeroes
1932 */
1933 if (dec) {
1934 while ((cptr > cval) && (*(cptr-1) == '0')) {
1935 cptr--;
1936 len--;
1937 }
1938 }
1939 *cptr = 0; /* Terminate our (preparsed) string */
1940 cptr = cval;
1941 /*
1942 * Now evaluate the significant digits of the number
1943 */
1944 xmlSchemaParseUInt((const xmlChar **)&cptr,
1945 &v->value.decimal.lo,
1946 &v->value.decimal.mi,
1947 &v->value.decimal.hi);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001948 v->value.decimal.sign = neg;
William M. Brack273670f2005-03-11 15:55:14 +00001949 if (dec == -1) {
1950 v->value.decimal.frac = 0;
1951 v->value.decimal.total = len;
1952 } else {
1953 v->value.decimal.frac = len - dec - 1;
1954 v->value.decimal.total = len - 1;
1955 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001956 *val = v;
1957 }
1958 }
1959 goto return0;
1960 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001961 case XML_SCHEMAS_TIME:
1962 case XML_SCHEMAS_GDAY:
1963 case XML_SCHEMAS_GMONTH:
1964 case XML_SCHEMAS_GMONTHDAY:
1965 case XML_SCHEMAS_GYEAR:
1966 case XML_SCHEMAS_GYEARMONTH:
1967 case XML_SCHEMAS_DATE:
1968 case XML_SCHEMAS_DATETIME:
Daniel Veillard01fa6152004-06-29 17:04:39 +00001969 ret = xmlSchemaValidateDates(type->builtInType, value, val);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001970 break;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001971 case XML_SCHEMAS_DURATION:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001972 ret = xmlSchemaValidateDuration(type, value, val);
1973 break;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001974 case XML_SCHEMAS_FLOAT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001975 case XML_SCHEMAS_DOUBLE:{
1976 const xmlChar *cur = value;
1977 int neg = 0;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001978
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001979 if (cur == NULL)
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00001980 goto return1;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001981 if ((cur[0] == 'N') && (cur[1] == 'a') && (cur[2] == 'N')) {
1982 cur += 3;
1983 if (*cur != 0)
1984 goto return1;
1985 if (val != NULL) {
1986 if (type == xmlSchemaTypeFloatDef) {
1987 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1988 if (v != NULL) {
1989 v->value.f = (float) xmlXPathNAN;
1990 } else {
1991 xmlSchemaFreeValue(v);
1992 goto error;
1993 }
1994 } else {
1995 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1996 if (v != NULL) {
1997 v->value.d = xmlXPathNAN;
1998 } else {
1999 xmlSchemaFreeValue(v);
2000 goto error;
2001 }
2002 }
2003 *val = v;
2004 }
2005 goto return0;
2006 }
2007 if (*cur == '-') {
2008 neg = 1;
2009 cur++;
2010 }
2011 if ((cur[0] == 'I') && (cur[1] == 'N') && (cur[2] == 'F')) {
2012 cur += 3;
2013 if (*cur != 0)
2014 goto return1;
2015 if (val != NULL) {
2016 if (type == xmlSchemaTypeFloatDef) {
2017 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
2018 if (v != NULL) {
2019 if (neg)
2020 v->value.f = (float) xmlXPathNINF;
2021 else
2022 v->value.f = (float) xmlXPathPINF;
2023 } else {
2024 xmlSchemaFreeValue(v);
2025 goto error;
2026 }
2027 } else {
2028 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
2029 if (v != NULL) {
2030 if (neg)
2031 v->value.d = xmlXPathNINF;
2032 else
2033 v->value.d = xmlXPathPINF;
2034 } else {
2035 xmlSchemaFreeValue(v);
2036 goto error;
2037 }
2038 }
2039 *val = v;
2040 }
2041 goto return0;
2042 }
2043 if ((neg == 0) && (*cur == '+'))
2044 cur++;
2045 if ((cur[0] == 0) || (cur[0] == '+') || (cur[0] == '-'))
2046 goto return1;
2047 while ((*cur >= '0') && (*cur <= '9')) {
2048 cur++;
2049 }
2050 if (*cur == '.') {
2051 cur++;
2052 while ((*cur >= '0') && (*cur <= '9'))
2053 cur++;
2054 }
2055 if ((*cur == 'e') || (*cur == 'E')) {
2056 cur++;
2057 if ((*cur == '-') || (*cur == '+'))
2058 cur++;
2059 while ((*cur >= '0') && (*cur <= '9'))
2060 cur++;
2061 }
2062 if (*cur != 0)
2063 goto return1;
2064 if (val != NULL) {
2065 if (type == xmlSchemaTypeFloatDef) {
2066 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
2067 if (v != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002068 if (sscanf((const char *) value, "%f",
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002069 &(v->value.f)) == 1) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00002070 *val = v;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002071 } else {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002072 xmlSchemaFreeValue(v);
2073 goto return1;
2074 }
2075 } else {
2076 goto error;
2077 }
2078 } else {
2079 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
2080 if (v != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002081 if (sscanf((const char *) value, "%lf",
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002082 &(v->value.d)) == 1) {
2083 *val = v;
2084 } else {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002085 xmlSchemaFreeValue(v);
2086 goto return1;
2087 }
2088 } else {
2089 goto error;
2090 }
2091 }
2092 }
2093 goto return0;
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00002094 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002095 case XML_SCHEMAS_BOOLEAN:{
2096 const xmlChar *cur = value;
2097
2098 if ((cur[0] == '0') && (cur[1] == 0))
2099 ret = 0;
2100 else if ((cur[0] == '1') && (cur[1] == 0))
2101 ret = 1;
2102 else if ((cur[0] == 't') && (cur[1] == 'r')
2103 && (cur[2] == 'u') && (cur[3] == 'e')
2104 && (cur[4] == 0))
2105 ret = 1;
2106 else if ((cur[0] == 'f') && (cur[1] == 'a')
2107 && (cur[2] == 'l') && (cur[3] == 's')
2108 && (cur[4] == 'e') && (cur[5] == 0))
2109 ret = 0;
2110 else
2111 goto return1;
2112 if (val != NULL) {
2113 v = xmlSchemaNewValue(XML_SCHEMAS_BOOLEAN);
2114 if (v != NULL) {
2115 v->value.b = ret;
2116 *val = v;
2117 } else {
2118 goto error;
2119 }
2120 }
2121 goto return0;
2122 }
2123 case XML_SCHEMAS_TOKEN:{
2124 const xmlChar *cur = value;
2125
William M. Brack76e95df2003-10-18 16:20:14 +00002126 if (IS_BLANK_CH(*cur))
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002127 goto return1;
2128
2129 while (*cur != 0) {
2130 if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) {
2131 goto return1;
2132 } else if (*cur == ' ') {
2133 cur++;
2134 if (*cur == 0)
2135 goto return1;
2136 if (*cur == ' ')
2137 goto return1;
2138 } else {
2139 cur++;
2140 }
2141 }
2142 if (val != NULL) {
2143 v = xmlSchemaNewValue(XML_SCHEMAS_TOKEN);
2144 if (v != NULL) {
2145 v->value.str = xmlStrdup(value);
2146 *val = v;
2147 } else {
2148 goto error;
2149 }
2150 }
2151 goto return0;
2152 }
2153 case XML_SCHEMAS_LANGUAGE:
2154 if (xmlCheckLanguageID(value) == 1) {
2155 if (val != NULL) {
2156 v = xmlSchemaNewValue(XML_SCHEMAS_LANGUAGE);
2157 if (v != NULL) {
2158 v->value.str = xmlStrdup(value);
2159 *val = v;
2160 } else {
2161 goto error;
2162 }
2163 }
2164 goto return0;
2165 }
2166 goto return1;
2167 case XML_SCHEMAS_NMTOKEN:
2168 if (xmlValidateNMToken(value, 1) == 0) {
2169 if (val != NULL) {
2170 v = xmlSchemaNewValue(XML_SCHEMAS_NMTOKEN);
2171 if (v != NULL) {
2172 v->value.str = xmlStrdup(value);
2173 *val = v;
2174 } else {
2175 goto error;
2176 }
2177 }
2178 goto return0;
2179 }
2180 goto return1;
2181 case XML_SCHEMAS_NMTOKENS:
2182 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeNmtokenDef,
2183 value, val, node);
2184 if (ret > 0)
2185 ret = 0;
2186 else
2187 ret = 1;
2188 goto done;
2189 case XML_SCHEMAS_NAME:
2190 ret = xmlValidateName(value, 1);
Daniel Veillarddf292f72005-01-16 19:00:15 +00002191 if ((ret == 0) && (val != NULL) && (value != NULL)) {
2192 v = xmlSchemaNewValue(XML_SCHEMAS_NAME);
2193 if (v != NULL) {
2194 const xmlChar *start = value, *end;
2195 while (IS_BLANK_CH(*start)) start++;
2196 end = start;
2197 while ((*end != 0) && (!IS_BLANK_CH(*end))) end++;
2198 v->value.str = xmlStrndup(start, end - start);
2199 *val = v;
2200 } else {
2201 goto error;
2202 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002203 }
2204 goto done;
2205 case XML_SCHEMAS_QNAME:{
2206 xmlChar *uri = NULL;
2207 xmlChar *local = NULL;
2208
2209 ret = xmlValidateQName(value, 1);
2210 if ((ret == 0) && (node != NULL)) {
2211 xmlChar *prefix;
2212
2213 local = xmlSplitQName2(value, &prefix);
2214 if (prefix != NULL) {
2215 xmlNsPtr ns;
2216
2217 ns = xmlSearchNs(node->doc, node, prefix);
2218 if (ns == NULL)
2219 ret = 1;
2220 else if (val != NULL)
2221 uri = xmlStrdup(ns->href);
2222 }
2223 if ((local != NULL) && ((val == NULL) || (ret != 0)))
2224 xmlFree(local);
2225 if (prefix != NULL)
2226 xmlFree(prefix);
2227 }
2228 if ((ret == 0) && (val != NULL)) {
2229 v = xmlSchemaNewValue(XML_SCHEMAS_QNAME);
2230 if (v != NULL) {
2231 if (local != NULL)
2232 v->value.qname.name = local;
2233 else
2234 v->value.qname.name = xmlStrdup(value);
2235 if (uri != NULL)
2236 v->value.qname.uri = uri;
2237
2238 *val = v;
2239 } else {
2240 if (local != NULL)
2241 xmlFree(local);
2242 if (uri != NULL)
2243 xmlFree(uri);
2244 goto error;
2245 }
2246 }
2247 goto done;
2248 }
2249 case XML_SCHEMAS_NCNAME:
2250 ret = xmlValidateNCName(value, 1);
2251 if ((ret == 0) && (val != NULL)) {
2252 v = xmlSchemaNewValue(XML_SCHEMAS_NCNAME);
2253 if (v != NULL) {
2254 v->value.str = xmlStrdup(value);
2255 *val = v;
2256 } else {
2257 goto error;
2258 }
2259 }
2260 goto done;
2261 case XML_SCHEMAS_ID:
2262 ret = xmlValidateNCName(value, 1);
2263 if ((ret == 0) && (val != NULL)) {
2264 v = xmlSchemaNewValue(XML_SCHEMAS_ID);
2265 if (v != NULL) {
2266 v->value.str = xmlStrdup(value);
2267 *val = v;
2268 } else {
2269 goto error;
2270 }
2271 }
2272 if ((ret == 0) && (node != NULL) &&
2273 (node->type == XML_ATTRIBUTE_NODE)) {
2274 xmlAttrPtr attr = (xmlAttrPtr) node;
2275
2276 /*
2277 * NOTE: the IDness might have already be declared in the DTD
2278 */
2279 if (attr->atype != XML_ATTRIBUTE_ID) {
2280 xmlIDPtr res;
2281 xmlChar *strip;
2282
2283 strip = xmlSchemaStrip(value);
2284 if (strip != NULL) {
2285 res = xmlAddID(NULL, node->doc, strip, attr);
2286 xmlFree(strip);
2287 } else
2288 res = xmlAddID(NULL, node->doc, value, attr);
2289 if (res == NULL) {
2290 ret = 2;
2291 } else {
2292 attr->atype = XML_ATTRIBUTE_ID;
2293 }
2294 }
2295 }
2296 goto done;
2297 case XML_SCHEMAS_IDREF:
2298 ret = xmlValidateNCName(value, 1);
2299 if ((ret == 0) && (val != NULL)) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00002300 v = xmlSchemaNewValue(XML_SCHEMAS_IDREF);
2301 if (v == NULL)
2302 goto error;
2303 v->value.str = xmlStrdup(value);
2304 *val = v;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002305 }
2306 if ((ret == 0) && (node != NULL) &&
2307 (node->type == XML_ATTRIBUTE_NODE)) {
2308 xmlAttrPtr attr = (xmlAttrPtr) node;
2309 xmlChar *strip;
2310
2311 strip = xmlSchemaStrip(value);
2312 if (strip != NULL) {
2313 xmlAddRef(NULL, node->doc, strip, attr);
2314 xmlFree(strip);
2315 } else
2316 xmlAddRef(NULL, node->doc, value, attr);
2317 attr->atype = XML_ATTRIBUTE_IDREF;
2318 }
2319 goto done;
2320 case XML_SCHEMAS_IDREFS:
2321 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeIdrefDef,
2322 value, val, node);
2323 if (ret < 0)
2324 ret = 2;
2325 else
2326 ret = 0;
2327 if ((ret == 0) && (node != NULL) &&
2328 (node->type == XML_ATTRIBUTE_NODE)) {
2329 xmlAttrPtr attr = (xmlAttrPtr) node;
2330
2331 attr->atype = XML_ATTRIBUTE_IDREFS;
2332 }
2333 goto done;
2334 case XML_SCHEMAS_ENTITY:{
2335 xmlChar *strip;
2336
2337 ret = xmlValidateNCName(value, 1);
2338 if ((node == NULL) || (node->doc == NULL))
2339 ret = 3;
2340 if (ret == 0) {
2341 xmlEntityPtr ent;
2342
2343 strip = xmlSchemaStrip(value);
2344 if (strip != NULL) {
2345 ent = xmlGetDocEntity(node->doc, strip);
2346 xmlFree(strip);
2347 } else {
2348 ent = xmlGetDocEntity(node->doc, value);
2349 }
2350 if ((ent == NULL) ||
2351 (ent->etype !=
2352 XML_EXTERNAL_GENERAL_UNPARSED_ENTITY))
2353 ret = 4;
2354 }
2355 if ((ret == 0) && (val != NULL)) {
2356 TODO;
2357 }
2358 if ((ret == 0) && (node != NULL) &&
2359 (node->type == XML_ATTRIBUTE_NODE)) {
2360 xmlAttrPtr attr = (xmlAttrPtr) node;
2361
2362 attr->atype = XML_ATTRIBUTE_ENTITY;
2363 }
2364 goto done;
2365 }
2366 case XML_SCHEMAS_ENTITIES:
2367 if ((node == NULL) || (node->doc == NULL))
2368 goto return3;
2369 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeEntityDef,
2370 value, val, node);
2371 if (ret <= 0)
2372 ret = 1;
2373 else
2374 ret = 0;
2375 if ((ret == 0) && (node != NULL) &&
2376 (node->type == XML_ATTRIBUTE_NODE)) {
2377 xmlAttrPtr attr = (xmlAttrPtr) node;
2378
2379 attr->atype = XML_ATTRIBUTE_ENTITIES;
2380 }
2381 goto done;
2382 case XML_SCHEMAS_NOTATION:{
2383 xmlChar *uri = NULL;
2384 xmlChar *local = NULL;
2385
2386 ret = xmlValidateQName(value, 1);
2387 if ((ret == 0) && (node != NULL)) {
2388 xmlChar *prefix;
2389
2390 local = xmlSplitQName2(value, &prefix);
2391 if (prefix != NULL) {
2392 xmlNsPtr ns;
2393
2394 ns = xmlSearchNs(node->doc, node, prefix);
2395 if (ns == NULL)
2396 ret = 1;
2397 else if (val != NULL)
2398 uri = xmlStrdup(ns->href);
2399 }
2400 if ((local != NULL) && ((val == NULL) || (ret != 0)))
2401 xmlFree(local);
2402 if (prefix != NULL)
2403 xmlFree(prefix);
2404 }
2405 if ((node == NULL) || (node->doc == NULL))
2406 ret = 3;
2407 if (ret == 0) {
2408 ret = xmlValidateNotationUse(NULL, node->doc, value);
2409 if (ret == 1)
2410 ret = 0;
2411 else
2412 ret = 1;
2413 }
2414 if ((ret == 0) && (val != NULL)) {
2415 v = xmlSchemaNewValue(XML_SCHEMAS_NOTATION);
2416 if (v != NULL) {
2417 if (local != NULL)
2418 v->value.qname.name = local;
2419 else
2420 v->value.qname.name = xmlStrdup(value);
2421 if (uri != NULL)
2422 v->value.qname.uri = uri;
2423
2424 *val = v;
2425 } else {
2426 if (local != NULL)
2427 xmlFree(local);
2428 if (uri != NULL)
2429 xmlFree(uri);
2430 goto error;
2431 }
2432 }
2433 goto done;
2434 }
2435 case XML_SCHEMAS_ANYURI:{
Daniel Veillard11c466a2004-03-14 12:20:15 +00002436 if (*value != 0) {
2437 xmlURIPtr uri = xmlParseURI((const char *) value);
2438 if (uri == NULL)
2439 goto return1;
2440 xmlFreeURI(uri);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002441 }
Daniel Veillard11c466a2004-03-14 12:20:15 +00002442
2443 if (val != NULL) {
2444 v = xmlSchemaNewValue(XML_SCHEMAS_ANYURI);
2445 if (v == NULL)
2446 goto error;
2447 v->value.str = xmlStrdup(value);
2448 *val = v;
2449 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002450 goto return0;
2451 }
2452 case XML_SCHEMAS_HEXBINARY:{
2453 const xmlChar *cur = value;
2454 xmlChar *base;
2455 int total, i = 0;
2456
Daniel Veillardf34a20e2004-08-31 08:42:17 +00002457 if (cur == NULL)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002458 goto return1;
2459
2460 while (((*cur >= '0') && (*cur <= '9')) ||
2461 ((*cur >= 'A') && (*cur <= 'F')) ||
2462 ((*cur >= 'a') && (*cur <= 'f'))) {
2463 i++;
2464 cur++;
2465 }
2466
2467 if (*cur != 0)
2468 goto return1;
2469 if ((i % 2) != 0)
2470 goto return1;
2471
2472 if (val != NULL) {
2473
2474 v = xmlSchemaNewValue(XML_SCHEMAS_HEXBINARY);
2475 if (v == NULL)
2476 goto error;
2477
2478 cur = xmlStrdup(value);
2479 if (cur == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002480 xmlSchemaTypeErrMemory(node, "allocating hexbin data");
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002481 xmlFree(v);
2482 goto return1;
2483 }
2484
2485 total = i / 2; /* number of octets */
2486
2487 base = (xmlChar *) cur;
2488 while (i-- > 0) {
2489 if (*base >= 'a')
2490 *base = *base - ('a' - 'A');
2491 base++;
2492 }
2493
2494 v->value.hex.str = (xmlChar *) cur;
2495 v->value.hex.total = total;
2496 *val = v;
2497 }
2498 goto return0;
2499 }
2500 case XML_SCHEMAS_BASE64BINARY:{
2501 /* ISSUE:
2502 *
2503 * Ignore all stray characters? (yes, currently)
2504 * Worry about long lines? (no, currently)
2505 *
2506 * rfc2045.txt:
2507 *
2508 * "The encoded output stream must be represented in lines of
2509 * no more than 76 characters each. All line breaks or other
2510 * characters not found in Table 1 must be ignored by decoding
2511 * software. In base64 data, characters other than those in
2512 * Table 1, line breaks, and other white space probably
2513 * indicate a transmission error, about which a warning
2514 * message or even a message rejection might be appropriate
2515 * under some circumstances." */
2516 const xmlChar *cur = value;
2517 xmlChar *base;
2518 int total, i = 0, pad = 0;
2519
2520 if (cur == NULL)
2521 goto return1;
2522
2523 for (; *cur; ++cur) {
2524 int decc;
2525
2526 decc = _xmlSchemaBase64Decode(*cur);
2527 if (decc < 0) ;
2528 else if (decc < 64)
2529 i++;
2530 else
2531 break;
2532 }
2533 for (; *cur; ++cur) {
2534 int decc;
2535
2536 decc = _xmlSchemaBase64Decode(*cur);
2537 if (decc < 0) ;
2538 else if (decc < 64)
2539 goto return1;
2540 if (decc == 64)
2541 pad++;
2542 }
2543
2544 /* rfc2045.txt: "Special processing is performed if fewer than
2545 * 24 bits are available at the end of the data being encoded.
2546 * A full encoding quantum is always completed at the end of a
2547 * body. When fewer than 24 input bits are available in an
2548 * input group, zero bits are added (on the right) to form an
2549 * integral number of 6-bit groups. Padding at the end of the
2550 * data is performed using the "=" character. Since all
2551 * base64 input is an integral number of octets, only the
2552 * following cases can arise: (1) the final quantum of
2553 * encoding input is an integral multiple of 24 bits; here,
2554 * the final unit of encoded output will be an integral
2555 * multiple ofindent: Standard input:701: Warning:old style
2556 * assignment ambiguity in "=*". Assuming "= *" 4 characters
2557 * with no "=" padding, (2) the final
2558 * quantum of encoding input is exactly 8 bits; here, the
2559 * final unit of encoded output will be two characters
2560 * followed by two "=" padding characters, or (3) the final
2561 * quantum of encoding input is exactly 16 bits; here, the
2562 * final unit of encoded output will be three characters
2563 * followed by one "=" padding character." */
2564
2565 total = 3 * (i / 4);
2566 if (pad == 0) {
2567 if (i % 4 != 0)
2568 goto return1;
2569 } else if (pad == 1) {
2570 int decc;
2571
2572 if (i % 4 != 3)
2573 goto return1;
2574 for (decc = _xmlSchemaBase64Decode(*cur);
2575 (decc < 0) || (decc > 63);
2576 decc = _xmlSchemaBase64Decode(*cur))
2577 --cur;
2578 /* 16bits in 24bits means 2 pad bits: nnnnnn nnmmmm mmmm00*/
2579 /* 00111100 -> 0x3c */
2580 if (decc & ~0x3c)
2581 goto return1;
2582 total += 2;
2583 } else if (pad == 2) {
2584 int decc;
2585
2586 if (i % 4 != 2)
2587 goto return1;
2588 for (decc = _xmlSchemaBase64Decode(*cur);
2589 (decc < 0) || (decc > 63);
2590 decc = _xmlSchemaBase64Decode(*cur))
2591 --cur;
2592 /* 8bits in 12bits means 4 pad bits: nnnnnn nn0000 */
2593 /* 00110000 -> 0x30 */
2594 if (decc & ~0x30)
2595 goto return1;
2596 total += 1;
2597 } else
2598 goto return1;
2599
2600 if (val != NULL) {
2601 v = xmlSchemaNewValue(XML_SCHEMAS_BASE64BINARY);
2602 if (v == NULL)
2603 goto error;
2604 base =
2605 (xmlChar *) xmlMallocAtomic((i + pad + 1) *
2606 sizeof(xmlChar));
2607 if (base == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002608 xmlSchemaTypeErrMemory(node, "allocating base64 data");
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002609 xmlFree(v);
2610 goto return1;
2611 }
2612 v->value.base64.str = base;
2613 for (cur = value; *cur; ++cur)
2614 if (_xmlSchemaBase64Decode(*cur) >= 0) {
2615 *base = *cur;
2616 ++base;
2617 }
2618 *base = 0;
2619 v->value.base64.total = total;
2620 *val = v;
2621 }
2622 goto return0;
2623 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002624 case XML_SCHEMAS_INTEGER:
2625 case XML_SCHEMAS_PINTEGER:
2626 case XML_SCHEMAS_NPINTEGER:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002627 case XML_SCHEMAS_NINTEGER:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002628 case XML_SCHEMAS_NNINTEGER:{
2629 const xmlChar *cur = value;
2630 unsigned long lo, mi, hi;
2631 int sign = 0;
2632
2633 if (cur == NULL)
2634 goto return1;
2635 if (*cur == '-') {
2636 sign = 1;
2637 cur++;
2638 } else if (*cur == '+')
2639 cur++;
2640 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2641 if (ret == 0)
2642 goto return1;
2643 if (*cur != 0)
2644 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002645 if (type->builtInType == XML_SCHEMAS_NPINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002646 if ((sign == 0) &&
2647 ((hi != 0) || (mi != 0) || (lo != 0)))
2648 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002649 } else if (type->builtInType == XML_SCHEMAS_PINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002650 if (sign == 1)
2651 goto return1;
2652 if ((hi == 0) && (mi == 0) && (lo == 0))
2653 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002654 } else if (type->builtInType == XML_SCHEMAS_NINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002655 if (sign == 0)
2656 goto return1;
2657 if ((hi == 0) && (mi == 0) && (lo == 0))
2658 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002659 } else if (type->builtInType == XML_SCHEMAS_NNINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002660 if ((sign == 1) &&
2661 ((hi != 0) || (mi != 0) || (lo != 0)))
2662 goto return1;
2663 }
2664 /*
2665 * We can store a value only if no overflow occured
2666 */
2667 if ((ret > 0) && (val != NULL)) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00002668 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002669 if (v != NULL) {
2670 v->value.decimal.lo = lo;
2671 v->value.decimal.mi = lo;
2672 v->value.decimal.hi = lo;
2673 v->value.decimal.sign = sign;
2674 v->value.decimal.frac = 0;
2675 v->value.decimal.total = cur - value;
2676 *val = v;
2677 }
2678 }
2679 goto return0;
2680 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002681 case XML_SCHEMAS_LONG:
2682 case XML_SCHEMAS_BYTE:
2683 case XML_SCHEMAS_SHORT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002684 case XML_SCHEMAS_INT:{
2685 const xmlChar *cur = value;
2686 unsigned long lo, mi, hi;
2687 int total = 0;
2688 int sign = 0;
2689
2690 if (cur == NULL)
2691 goto return1;
2692 if (*cur == '-') {
2693 sign = 1;
2694 cur++;
2695 } else if (*cur == '+')
2696 cur++;
2697 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2698 if (ret <= 0)
2699 goto return1;
2700 if (*cur != 0)
2701 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002702 if (type->builtInType == XML_SCHEMAS_LONG) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002703 if (hi >= 922) {
2704 if (hi > 922)
2705 goto return1;
2706 if (mi >= 33720368) {
2707 if (mi > 33720368)
2708 goto return1;
2709 if ((sign == 0) && (lo > 54775807))
2710 goto return1;
2711 if ((sign == 1) && (lo > 54775808))
2712 goto return1;
2713 }
2714 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002715 } else if (type->builtInType == XML_SCHEMAS_INT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002716 if (hi != 0)
2717 goto return1;
2718 if (mi >= 21) {
2719 if (mi > 21)
2720 goto return1;
2721 if ((sign == 0) && (lo > 47483647))
2722 goto return1;
2723 if ((sign == 1) && (lo > 47483648))
2724 goto return1;
2725 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002726 } else if (type->builtInType == XML_SCHEMAS_SHORT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002727 if ((mi != 0) || (hi != 0))
2728 goto return1;
2729 if ((sign == 1) && (lo > 32768))
2730 goto return1;
2731 if ((sign == 0) && (lo > 32767))
2732 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002733 } else if (type->builtInType == XML_SCHEMAS_BYTE) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002734 if ((mi != 0) || (hi != 0))
2735 goto return1;
2736 if ((sign == 1) && (lo > 128))
2737 goto return1;
2738 if ((sign == 0) && (lo > 127))
2739 goto return1;
2740 }
2741 if (val != NULL) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00002742 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002743 if (v != NULL) {
2744 v->value.decimal.lo = lo;
2745 v->value.decimal.mi = lo;
2746 v->value.decimal.hi = lo;
2747 v->value.decimal.sign = sign;
2748 v->value.decimal.frac = 0;
2749 v->value.decimal.total = total;
2750 *val = v;
2751 }
2752 }
2753 goto return0;
2754 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002755 case XML_SCHEMAS_UINT:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002756 case XML_SCHEMAS_ULONG:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002757 case XML_SCHEMAS_USHORT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002758 case XML_SCHEMAS_UBYTE:{
2759 const xmlChar *cur = value;
2760 unsigned long lo, mi, hi;
2761 int total = 0;
2762
2763 if (cur == NULL)
2764 goto return1;
2765 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2766 if (ret <= 0)
2767 goto return1;
2768 if (*cur != 0)
2769 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002770 if (type->builtInType == XML_SCHEMAS_ULONG) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002771 if (hi >= 1844) {
2772 if (hi > 1844)
2773 goto return1;
2774 if (mi >= 67440737) {
2775 if (mi > 67440737)
2776 goto return1;
2777 if (lo > 9551615)
2778 goto return1;
2779 }
2780 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002781 } else if (type->builtInType == XML_SCHEMAS_UINT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002782 if (hi != 0)
2783 goto return1;
2784 if (mi >= 42) {
2785 if (mi > 42)
2786 goto return1;
2787 if (lo > 94967295)
2788 goto return1;
2789 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002790 } else if (type->builtInType == XML_SCHEMAS_USHORT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002791 if ((mi != 0) || (hi != 0))
2792 goto return1;
2793 if (lo > 65535)
2794 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002795 } else if (type->builtInType == XML_SCHEMAS_UBYTE) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002796 if ((mi != 0) || (hi != 0))
2797 goto return1;
2798 if (lo > 255)
2799 goto return1;
2800 }
2801 if (val != NULL) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00002802 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002803 if (v != NULL) {
2804 v->value.decimal.lo = lo;
2805 v->value.decimal.mi = mi;
2806 v->value.decimal.hi = hi;
2807 v->value.decimal.sign = 0;
2808 v->value.decimal.frac = 0;
2809 v->value.decimal.total = total;
2810 *val = v;
2811 }
2812 }
2813 goto return0;
2814 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002815 }
2816
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002817 done:
2818 if (norm != NULL)
2819 xmlFree(norm);
2820 return (ret);
2821 return3:
2822 if (norm != NULL)
2823 xmlFree(norm);
2824 return (3);
2825 return1:
2826 if (norm != NULL)
2827 xmlFree(norm);
2828 return (1);
2829 return0:
2830 if (norm != NULL)
2831 xmlFree(norm);
2832 return (0);
2833 error:
2834 if (norm != NULL)
2835 xmlFree(norm);
2836 return (-1);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002837}
2838
2839/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002840 * xmlSchemaValPredefTypeNode:
Daniel Veillard4255d502002-04-16 15:50:10 +00002841 * @type: the predefined type
2842 * @value: the value to check
2843 * @val: the return computed value
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002844 * @node: the node containing the value
Daniel Veillard4255d502002-04-16 15:50:10 +00002845 *
2846 * Check that a value conforms to the lexical space of the predefined type.
2847 * if true a value is computed and returned in @val.
2848 *
2849 * Returns 0 if this validates, a positive error code number otherwise
2850 * and -1 in case of internal or API error.
2851 */
2852int
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002853xmlSchemaValPredefTypeNode(xmlSchemaTypePtr type, const xmlChar *value,
2854 xmlSchemaValPtr *val, xmlNodePtr node) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002855 return(xmlSchemaValAtomicType(type, value, val, node, 0));
Daniel Veillard4255d502002-04-16 15:50:10 +00002856}
2857
2858/**
Daniel Veillardc0826a72004-08-10 14:17:33 +00002859 * xmlSchemaValPredefTypeNodeNoNorm:
2860 * @type: the predefined type
2861 * @value: the value to check
2862 * @val: the return computed value
2863 * @node: the node containing the value
2864 *
2865 * Check that a value conforms to the lexical space of the predefined type.
2866 * if true a value is computed and returned in @val.
2867 * This one does apply any normalization to the value.
2868 *
2869 * Returns 0 if this validates, a positive error code number otherwise
2870 * and -1 in case of internal or API error.
2871 */
2872int
2873xmlSchemaValPredefTypeNodeNoNorm(xmlSchemaTypePtr type, const xmlChar *value,
2874 xmlSchemaValPtr *val, xmlNodePtr node) {
2875 return(xmlSchemaValAtomicType(type, value, val, node, 1));
2876}
2877
2878/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002879 * xmlSchemaValidatePredefinedType:
2880 * @type: the predefined type
2881 * @value: the value to check
2882 * @val: the return computed value
2883 *
2884 * Check that a value conforms to the lexical space of the predefined type.
2885 * if true a value is computed and returned in @val.
2886 *
2887 * Returns 0 if this validates, a positive error code number otherwise
2888 * and -1 in case of internal or API error.
2889 */
2890int
2891xmlSchemaValidatePredefinedType(xmlSchemaTypePtr type, const xmlChar *value,
2892 xmlSchemaValPtr *val) {
2893 return(xmlSchemaValPredefTypeNode(type, value, val, NULL));
2894}
2895
2896/**
Daniel Veillard4255d502002-04-16 15:50:10 +00002897 * xmlSchemaCompareDecimals:
2898 * @x: a first decimal value
2899 * @y: a second decimal value
2900 *
2901 * Compare 2 decimals
2902 *
2903 * Returns -1 if x < y, 0 if x == y, 1 if x > y and -2 in case of error
2904 */
2905static int
2906xmlSchemaCompareDecimals(xmlSchemaValPtr x, xmlSchemaValPtr y)
2907{
2908 xmlSchemaValPtr swp;
William M. Brack273670f2005-03-11 15:55:14 +00002909 int order = 1, integx, integy, dlen;
2910 unsigned long hi, mi, lo;
Daniel Veillard4255d502002-04-16 15:50:10 +00002911
William M. Brack273670f2005-03-11 15:55:14 +00002912 /*
2913 * First test: If x is -ve and not zero
2914 */
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002915 if ((x->value.decimal.sign) &&
2916 ((x->value.decimal.lo != 0) ||
2917 (x->value.decimal.mi != 0) ||
2918 (x->value.decimal.hi != 0))) {
William M. Brack273670f2005-03-11 15:55:14 +00002919 /*
2920 * Then if y is -ve and not zero reverse the compare
2921 */
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002922 if ((y->value.decimal.sign) &&
2923 ((y->value.decimal.lo != 0) ||
2924 (y->value.decimal.mi != 0) ||
2925 (y->value.decimal.hi != 0)))
Daniel Veillard80b19092003-03-28 13:29:53 +00002926 order = -1;
William M. Brack273670f2005-03-11 15:55:14 +00002927 /*
2928 * Otherwise (y >= 0) we have the answer
2929 */
Daniel Veillard80b19092003-03-28 13:29:53 +00002930 else
2931 return (-1);
William M. Brack273670f2005-03-11 15:55:14 +00002932 /*
2933 * If x is not -ve and y is -ve we have the answer
2934 */
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002935 } else if ((y->value.decimal.sign) &&
2936 ((y->value.decimal.lo != 0) ||
2937 (y->value.decimal.mi != 0) ||
2938 (y->value.decimal.hi != 0))) {
Daniel Veillard4255d502002-04-16 15:50:10 +00002939 return (1);
Daniel Veillard80b19092003-03-28 13:29:53 +00002940 }
William M. Brack273670f2005-03-11 15:55:14 +00002941 /*
2942 * If it's not simply determined by a difference in sign,
2943 * then we need to compare the actual values of the two nums.
2944 * To do this, we start by looking at the integral parts.
2945 * If the number of integral digits differ, then we have our
2946 * answer.
2947 */
2948 integx = x->value.decimal.total - x->value.decimal.frac;
2949 integy = y->value.decimal.total - y->value.decimal.frac;
2950 if (integx > integy)
2951 return order;
2952 else if (integy > integx)
2953 return -order;
2954 /*
2955 * If the number of integral digits is the same for both numbers,
2956 * then things get a little more complicated. We need to "normalize"
2957 * the numbers in order to properly compare them. To do this, we
2958 * look at the total length of each number (length => number of
2959 * significant digits), and divide the "shorter" by 10 (decreasing
2960 * the length) until they are of equal length.
2961 */
2962 dlen = x->value.decimal.total - y->value.decimal.total;
2963 if (dlen < 0) { /* y has more digits than x */
2964 swp = x;
2965 hi = y->value.decimal.hi;
2966 mi = y->value.decimal.mi;
2967 lo = y->value.decimal.lo;
2968 dlen = -dlen;
2969 order = -order;
2970 } else { /* x has more digits than y */
2971 swp = y;
2972 hi = x->value.decimal.hi;
2973 mi = x->value.decimal.mi;
2974 lo = x->value.decimal.lo;
Daniel Veillard4255d502002-04-16 15:50:10 +00002975 }
William M. Brack273670f2005-03-11 15:55:14 +00002976 while (dlen > 8) { /* in effect, right shift by 10**8 */
2977 lo = mi;
2978 mi = hi;
2979 hi = 0;
2980 dlen -= 8;
Daniel Veillard4255d502002-04-16 15:50:10 +00002981 }
William M. Brack273670f2005-03-11 15:55:14 +00002982 while (dlen > 0) {
2983 unsigned long rem1, rem2;
2984 rem1 = (hi % 10) * 100000000L;
2985 hi = hi / 10;
2986 rem2 = (mi % 10) * 100000000L;
2987 mi = (mi + rem1) / 10;
2988 lo = (lo + rem2) / 10;
2989 dlen--;
2990 }
2991 if (hi > swp->value.decimal.hi) {
2992 return order;
2993 } else if (hi == swp->value.decimal.hi) {
2994 if (mi > swp->value.decimal.mi) {
2995 return order;
2996 } else if (mi == swp->value.decimal.mi) {
2997 if (lo > swp->value.decimal.lo) {
2998 return order;
2999 } else if (lo == swp->value.decimal.lo) {
3000 if (x->value.decimal.total == y->value.decimal.total) {
3001 return 0;
3002 } else {
3003 return order;
3004 }
3005 }
3006 }
3007 }
3008 return -order;
Daniel Veillard4255d502002-04-16 15:50:10 +00003009}
3010
3011/**
Daniel Veillard070803b2002-05-03 07:29:38 +00003012 * xmlSchemaCompareDurations:
3013 * @x: a first duration value
3014 * @y: a second duration value
3015 *
3016 * Compare 2 durations
3017 *
3018 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3019 * case of error
3020 */
3021static int
3022xmlSchemaCompareDurations(xmlSchemaValPtr x, xmlSchemaValPtr y)
3023{
3024 long carry, mon, day;
3025 double sec;
Daniel Veillard80b19092003-03-28 13:29:53 +00003026 int invert = 1;
3027 long xmon, xday, myear, minday, maxday;
Daniel Veillard070803b2002-05-03 07:29:38 +00003028 static const long dayRange [2][12] = {
3029 { 0, 28, 59, 89, 120, 150, 181, 212, 242, 273, 303, 334, },
3030 { 0, 31, 62, 92, 123, 153, 184, 215, 245, 276, 306, 337} };
3031
3032 if ((x == NULL) || (y == NULL))
Daniel Veillard5a872412002-05-22 06:40:27 +00003033 return -2;
Daniel Veillard070803b2002-05-03 07:29:38 +00003034
3035 /* months */
3036 mon = x->value.dur.mon - y->value.dur.mon;
3037
3038 /* seconds */
3039 sec = x->value.dur.sec - y->value.dur.sec;
3040 carry = (long)sec / SECS_PER_DAY;
3041 sec -= (double)(carry * SECS_PER_DAY);
3042
3043 /* days */
3044 day = x->value.dur.day - y->value.dur.day + carry;
3045
3046 /* easy test */
3047 if (mon == 0) {
3048 if (day == 0)
3049 if (sec == 0.0)
3050 return 0;
3051 else if (sec < 0.0)
3052 return -1;
3053 else
3054 return 1;
3055 else if (day < 0)
3056 return -1;
3057 else
3058 return 1;
3059 }
3060
3061 if (mon > 0) {
3062 if ((day >= 0) && (sec >= 0.0))
3063 return 1;
3064 else {
3065 xmon = mon;
3066 xday = -day;
3067 }
3068 } else if ((day <= 0) && (sec <= 0.0)) {
3069 return -1;
3070 } else {
Daniel Veillard80b19092003-03-28 13:29:53 +00003071 invert = -1;
Daniel Veillard070803b2002-05-03 07:29:38 +00003072 xmon = -mon;
3073 xday = day;
3074 }
3075
3076 myear = xmon / 12;
Daniel Veillard80b19092003-03-28 13:29:53 +00003077 if (myear == 0) {
3078 minday = 0;
3079 maxday = 0;
3080 } else {
3081 maxday = 366 * ((myear + 3) / 4) +
3082 365 * ((myear - 1) % 4);
3083 minday = maxday - 1;
3084 }
3085
Daniel Veillard070803b2002-05-03 07:29:38 +00003086 xmon = xmon % 12;
3087 minday += dayRange[0][xmon];
3088 maxday += dayRange[1][xmon];
3089
Daniel Veillard80b19092003-03-28 13:29:53 +00003090 if ((maxday == minday) && (maxday == xday))
3091 return(0); /* can this really happen ? */
Daniel Veillard070803b2002-05-03 07:29:38 +00003092 if (maxday < xday)
Daniel Veillard80b19092003-03-28 13:29:53 +00003093 return(-invert);
3094 if (minday > xday)
3095 return(invert);
Daniel Veillard070803b2002-05-03 07:29:38 +00003096
3097 /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00003098 return 2;
3099}
3100
3101/*
3102 * macros for adding date/times and durations
3103 */
3104#define FQUOTIENT(a,b) (floor(((double)a/(double)b)))
3105#define MODULO(a,b) (a - FQUOTIENT(a,b) * b)
3106#define FQUOTIENT_RANGE(a,low,high) (FQUOTIENT((a-low),(high-low)))
3107#define MODULO_RANGE(a,low,high) ((MODULO((a-low),(high-low)))+low)
3108
3109/**
Daniel Veillard669adfc2004-05-29 20:12:46 +00003110 * xmlSchemaDupVal:
3111 * @v: the #xmlSchemaValPtr value to duplicate
3112 *
3113 * Makes a copy of @v. The calling program is responsible for freeing
3114 * the returned value.
3115 *
3116 * returns a pointer to a duplicated #xmlSchemaValPtr or NULL if error.
3117 */
3118static xmlSchemaValPtr
3119xmlSchemaDupVal (xmlSchemaValPtr v)
3120{
3121 xmlSchemaValPtr ret = xmlSchemaNewValue(v->type);
3122 if (ret == NULL)
3123 return NULL;
3124
3125 memcpy(ret, v, sizeof(xmlSchemaVal));
3126 return ret;
3127}
3128
3129/**
Kasimier T. Buchcik285ebab2005-03-04 18:04:59 +00003130 * xmlSchemaCopyValue:
3131 * @val: the precomputed value to be copied
3132 *
3133 * Copies the precomputed value. This duplicates any string within.
3134 *
3135 * Returns the copy or NULL if a copy for a data-type is not implemented.
3136 */
3137xmlSchemaValPtr
3138xmlSchemaCopyValue(xmlSchemaValPtr val)
3139{
3140 xmlSchemaValPtr ret;
3141
3142 if (val == NULL)
3143 return (NULL);
3144 /*
3145 * Copy the string values.
3146 */
3147 switch (val->type) {
3148 case XML_SCHEMAS_IDREFS:
3149 case XML_SCHEMAS_ENTITIES:
3150 case XML_SCHEMAS_NMTOKENS:
3151 case XML_SCHEMAS_ANYTYPE:
3152 case XML_SCHEMAS_ANYSIMPLETYPE:
3153 return (NULL);
3154 case XML_SCHEMAS_STRING:
3155 case XML_SCHEMAS_NORMSTRING:
3156 case XML_SCHEMAS_TOKEN:
3157 case XML_SCHEMAS_LANGUAGE:
3158 case XML_SCHEMAS_NAME:
3159 case XML_SCHEMAS_NCNAME:
3160 case XML_SCHEMAS_ID:
3161 case XML_SCHEMAS_IDREF:
3162 case XML_SCHEMAS_ENTITY:
3163 case XML_SCHEMAS_NMTOKEN:
Kasimier T. Buchcik2ee855d2005-03-07 11:14:14 +00003164 case XML_SCHEMAS_ANYURI:
Kasimier T. Buchcik285ebab2005-03-04 18:04:59 +00003165 ret = xmlSchemaDupVal(val);
3166 if (val->value.str != NULL)
3167 ret->value.str = xmlStrdup(BAD_CAST val->value.str);
3168 return (ret);
Kasimier T. Buchcik2ee855d2005-03-07 11:14:14 +00003169 case XML_SCHEMAS_QNAME:
Kasimier T. Buchcik285ebab2005-03-04 18:04:59 +00003170 case XML_SCHEMAS_NOTATION:
3171 ret = xmlSchemaDupVal(val);
3172 if (val->value.qname.name != NULL)
3173 ret->value.qname.name =
3174 xmlStrdup(BAD_CAST val->value.qname.name);
3175 if (val->value.qname.uri != NULL)
3176 ret->value.qname.uri =
3177 xmlStrdup(BAD_CAST val->value.qname.uri);
3178 return (ret);
3179 case XML_SCHEMAS_HEXBINARY:
3180 ret = xmlSchemaDupVal(val);
3181 if (val->value.hex.str != NULL)
3182 ret->value.hex.str = xmlStrdup(BAD_CAST val->value.hex.str);
3183 return (ret);
3184 case XML_SCHEMAS_BASE64BINARY:
3185 ret = xmlSchemaDupVal(val);
3186 if (val->value.base64.str != NULL)
3187 ret->value.base64.str =
3188 xmlStrdup(BAD_CAST val->value.base64.str);
3189 return (ret);
3190 default:
3191 return (xmlSchemaDupVal(val));
3192 }
3193 return (NULL);
3194}
3195
3196/**
Daniel Veillard5a872412002-05-22 06:40:27 +00003197 * _xmlSchemaDateAdd:
3198 * @dt: an #xmlSchemaValPtr
3199 * @dur: an #xmlSchemaValPtr of type #XS_DURATION
3200 *
3201 * Compute a new date/time from @dt and @dur. This function assumes @dt
3202 * is either #XML_SCHEMAS_DATETIME, #XML_SCHEMAS_DATE, #XML_SCHEMAS_GYEARMONTH,
Daniel Veillard669adfc2004-05-29 20:12:46 +00003203 * or #XML_SCHEMAS_GYEAR. The returned #xmlSchemaVal is the same type as
3204 * @dt. The calling program is responsible for freeing the returned value.
Daniel Veillard5a872412002-05-22 06:40:27 +00003205 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00003206 * Returns a pointer to a new #xmlSchemaVal or NULL if error.
Daniel Veillard5a872412002-05-22 06:40:27 +00003207 */
3208static xmlSchemaValPtr
3209_xmlSchemaDateAdd (xmlSchemaValPtr dt, xmlSchemaValPtr dur)
3210{
Daniel Veillard669adfc2004-05-29 20:12:46 +00003211 xmlSchemaValPtr ret, tmp;
Daniel Veillard5a872412002-05-22 06:40:27 +00003212 long carry, tempdays, temp;
3213 xmlSchemaValDatePtr r, d;
3214 xmlSchemaValDurationPtr u;
3215
3216 if ((dt == NULL) || (dur == NULL))
3217 return NULL;
3218
3219 ret = xmlSchemaNewValue(dt->type);
3220 if (ret == NULL)
3221 return NULL;
3222
Daniel Veillard669adfc2004-05-29 20:12:46 +00003223 /* make a copy so we don't alter the original value */
3224 tmp = xmlSchemaDupVal(dt);
3225 if (tmp == NULL) {
3226 xmlSchemaFreeValue(ret);
3227 return NULL;
3228 }
3229
Daniel Veillard5a872412002-05-22 06:40:27 +00003230 r = &(ret->value.date);
Daniel Veillard669adfc2004-05-29 20:12:46 +00003231 d = &(tmp->value.date);
Daniel Veillard5a872412002-05-22 06:40:27 +00003232 u = &(dur->value.dur);
3233
3234 /* normalization */
3235 if (d->mon == 0)
3236 d->mon = 1;
3237
3238 /* normalize for time zone offset */
3239 u->sec -= (d->tzo * 60);
3240 d->tzo = 0;
3241
3242 /* normalization */
3243 if (d->day == 0)
3244 d->day = 1;
3245
3246 /* month */
3247 carry = d->mon + u->mon;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003248 r->mon = (unsigned int) MODULO_RANGE(carry, 1, 13);
3249 carry = (long) FQUOTIENT_RANGE(carry, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00003250
3251 /* year (may be modified later) */
3252 r->year = d->year + carry;
3253 if (r->year == 0) {
3254 if (d->year > 0)
3255 r->year--;
3256 else
3257 r->year++;
3258 }
3259
3260 /* time zone */
3261 r->tzo = d->tzo;
3262 r->tz_flag = d->tz_flag;
3263
3264 /* seconds */
3265 r->sec = d->sec + u->sec;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003266 carry = (long) FQUOTIENT((long)r->sec, 60);
Daniel Veillard5a872412002-05-22 06:40:27 +00003267 if (r->sec != 0.0) {
3268 r->sec = MODULO(r->sec, 60.0);
3269 }
3270
3271 /* minute */
3272 carry += d->min;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003273 r->min = (unsigned int) MODULO(carry, 60);
3274 carry = (long) FQUOTIENT(carry, 60);
Daniel Veillard5a872412002-05-22 06:40:27 +00003275
3276 /* hours */
3277 carry += d->hour;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003278 r->hour = (unsigned int) MODULO(carry, 24);
3279 carry = (long)FQUOTIENT(carry, 24);
Daniel Veillard5a872412002-05-22 06:40:27 +00003280
3281 /*
3282 * days
3283 * Note we use tempdays because the temporary values may need more
3284 * than 5 bits
3285 */
3286 if ((VALID_YEAR(r->year)) && (VALID_MONTH(r->mon)) &&
3287 (d->day > MAX_DAYINMONTH(r->year, r->mon)))
3288 tempdays = MAX_DAYINMONTH(r->year, r->mon);
3289 else if (d->day < 1)
3290 tempdays = 1;
3291 else
3292 tempdays = d->day;
3293
3294 tempdays += u->day + carry;
3295
3296 while (1) {
3297 if (tempdays < 1) {
Daniel Veillardebe25d42004-03-25 09:35:49 +00003298 long tmon = (long) MODULO_RANGE(r->mon-1, 1, 13);
3299 long tyr = r->year + (long)FQUOTIENT_RANGE(r->mon-1, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00003300 if (tyr == 0)
3301 tyr--;
3302 tempdays += MAX_DAYINMONTH(tyr, tmon);
3303 carry = -1;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003304 } else if (tempdays > (long) MAX_DAYINMONTH(r->year, r->mon)) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003305 tempdays = tempdays - MAX_DAYINMONTH(r->year, r->mon);
3306 carry = 1;
3307 } else
3308 break;
3309
3310 temp = r->mon + carry;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003311 r->mon = (unsigned int) MODULO_RANGE(temp, 1, 13);
3312 r->year = r->year + (unsigned int) FQUOTIENT_RANGE(temp, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00003313 if (r->year == 0) {
3314 if (temp < 1)
3315 r->year--;
3316 else
3317 r->year++;
3318 }
3319 }
3320
3321 r->day = tempdays;
3322
3323 /*
3324 * adjust the date/time type to the date values
3325 */
3326 if (ret->type != XML_SCHEMAS_DATETIME) {
3327 if ((r->hour) || (r->min) || (r->sec))
3328 ret->type = XML_SCHEMAS_DATETIME;
3329 else if (ret->type != XML_SCHEMAS_DATE) {
3330 if ((r->mon != 1) && (r->day != 1))
3331 ret->type = XML_SCHEMAS_DATE;
3332 else if ((ret->type != XML_SCHEMAS_GYEARMONTH) && (r->mon != 1))
3333 ret->type = XML_SCHEMAS_GYEARMONTH;
3334 }
3335 }
3336
Daniel Veillard669adfc2004-05-29 20:12:46 +00003337 xmlSchemaFreeValue(tmp);
Daniel Veillard5a872412002-05-22 06:40:27 +00003338
Daniel Veillard5a872412002-05-22 06:40:27 +00003339 return ret;
3340}
3341
3342/**
3343 * xmlSchemaDateNormalize:
Daniel Veillard669adfc2004-05-29 20:12:46 +00003344 * @dt: an #xmlSchemaValPtr of a date/time type value.
3345 * @offset: number of seconds to adjust @dt by.
Daniel Veillard5a872412002-05-22 06:40:27 +00003346 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00003347 * Normalize @dt to GMT time. The @offset parameter is subtracted from
3348 * the return value is a time-zone offset is present on @dt.
Daniel Veillard5a872412002-05-22 06:40:27 +00003349 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00003350 * Returns a normalized copy of @dt or NULL if error.
Daniel Veillard5a872412002-05-22 06:40:27 +00003351 */
3352static xmlSchemaValPtr
3353xmlSchemaDateNormalize (xmlSchemaValPtr dt, double offset)
3354{
3355 xmlSchemaValPtr dur, ret;
3356
3357 if (dt == NULL)
3358 return NULL;
3359
3360 if (((dt->type != XML_SCHEMAS_TIME) &&
3361 (dt->type != XML_SCHEMAS_DATETIME)) || (dt->value.date.tzo == 0))
3362 return xmlSchemaDupVal(dt);
3363
3364 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
3365 if (dur == NULL)
3366 return NULL;
3367
3368 dur->value.date.sec -= offset;
3369
3370 ret = _xmlSchemaDateAdd(dt, dur);
3371 if (ret == NULL)
3372 return NULL;
3373
3374 xmlSchemaFreeValue(dur);
3375
3376 /* ret->value.date.tzo = 0; */
3377 return ret;
3378}
3379
3380/**
3381 * _xmlSchemaDateCastYMToDays:
3382 * @dt: an #xmlSchemaValPtr
3383 *
3384 * Convert mon and year of @dt to total number of days. Take the
3385 * number of years since (or before) 1 AD and add the number of leap
3386 * years. This is a function because negative
3387 * years must be handled a little differently and there is no zero year.
3388 *
3389 * Returns number of days.
3390 */
3391static long
3392_xmlSchemaDateCastYMToDays (const xmlSchemaValPtr dt)
3393{
3394 long ret;
Daniel Veillard49e89632004-09-23 16:24:36 +00003395 int mon;
Daniel Veillard5a872412002-05-22 06:40:27 +00003396
Daniel Veillard49e89632004-09-23 16:24:36 +00003397 mon = dt->value.date.mon;
3398 if (mon <= 0) mon = 1; /* normalization */
3399
3400 if (dt->value.date.year <= 0)
Daniel Veillard5a872412002-05-22 06:40:27 +00003401 ret = (dt->value.date.year * 365) +
3402 (((dt->value.date.year+1)/4)-((dt->value.date.year+1)/100)+
3403 ((dt->value.date.year+1)/400)) +
Daniel Veillard49e89632004-09-23 16:24:36 +00003404 DAY_IN_YEAR(0, mon, dt->value.date.year);
Daniel Veillard5a872412002-05-22 06:40:27 +00003405 else
3406 ret = ((dt->value.date.year-1) * 365) +
3407 (((dt->value.date.year-1)/4)-((dt->value.date.year-1)/100)+
3408 ((dt->value.date.year-1)/400)) +
Daniel Veillard49e89632004-09-23 16:24:36 +00003409 DAY_IN_YEAR(0, mon, dt->value.date.year);
Daniel Veillard5a872412002-05-22 06:40:27 +00003410
3411 return ret;
3412}
3413
3414/**
3415 * TIME_TO_NUMBER:
3416 * @dt: an #xmlSchemaValPtr
3417 *
3418 * Calculates the number of seconds in the time portion of @dt.
3419 *
3420 * Returns seconds.
3421 */
3422#define TIME_TO_NUMBER(dt) \
3423 ((double)((dt->value.date.hour * SECS_PER_HOUR) + \
Daniel Veillardb3721c22003-03-31 11:22:25 +00003424 (dt->value.date.min * SECS_PER_MIN) + \
3425 (dt->value.date.tzo * SECS_PER_MIN)) + \
3426 dt->value.date.sec)
Daniel Veillard5a872412002-05-22 06:40:27 +00003427
3428/**
3429 * xmlSchemaCompareDates:
3430 * @x: a first date/time value
3431 * @y: a second date/time value
3432 *
3433 * Compare 2 date/times
3434 *
3435 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3436 * case of error
3437 */
3438static int
3439xmlSchemaCompareDates (xmlSchemaValPtr x, xmlSchemaValPtr y)
3440{
3441 unsigned char xmask, ymask, xor_mask, and_mask;
3442 xmlSchemaValPtr p1, p2, q1, q2;
3443 long p1d, p2d, q1d, q2d;
3444
3445 if ((x == NULL) || (y == NULL))
3446 return -2;
3447
3448 if (x->value.date.tz_flag) {
3449
3450 if (!y->value.date.tz_flag) {
3451 p1 = xmlSchemaDateNormalize(x, 0);
3452 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3453 /* normalize y + 14:00 */
3454 q1 = xmlSchemaDateNormalize(y, (14 * SECS_PER_HOUR));
3455
3456 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003457 if (p1d < q1d) {
3458 xmlSchemaFreeValue(p1);
3459 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003460 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003461 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003462 double sec;
3463
3464 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00003465 if (sec < 0.0) {
3466 xmlSchemaFreeValue(p1);
3467 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003468 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003469 } else {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003470 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003471 /* normalize y - 14:00 */
3472 q2 = xmlSchemaDateNormalize(y, -(14 * SECS_PER_HOUR));
3473 q2d = _xmlSchemaDateCastYMToDays(q2) + q2->value.date.day;
3474 if (p1d > q2d)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003475 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003476 else if (p1d == q2d) {
3477 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q2);
3478 if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003479 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003480 else
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003481 ret = 2; /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00003482 }
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003483 xmlSchemaFreeValue(p1);
3484 xmlSchemaFreeValue(q1);
3485 xmlSchemaFreeValue(q2);
3486 if (ret != 0)
3487 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003488 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00003489 } else {
3490 xmlSchemaFreeValue(p1);
3491 xmlSchemaFreeValue(q1);
3492 }
Daniel Veillard5a872412002-05-22 06:40:27 +00003493 }
3494 } else if (y->value.date.tz_flag) {
3495 q1 = xmlSchemaDateNormalize(y, 0);
3496 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
3497
3498 /* normalize x - 14:00 */
3499 p1 = xmlSchemaDateNormalize(x, -(14 * SECS_PER_HOUR));
3500 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3501
Daniel Veillardfdc91562002-07-01 21:52:03 +00003502 if (p1d < q1d) {
3503 xmlSchemaFreeValue(p1);
3504 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003505 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003506 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003507 double sec;
3508
3509 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00003510 if (sec < 0.0) {
3511 xmlSchemaFreeValue(p1);
3512 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003513 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003514 } else {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003515 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003516 /* normalize x + 14:00 */
3517 p2 = xmlSchemaDateNormalize(x, (14 * SECS_PER_HOUR));
3518 p2d = _xmlSchemaDateCastYMToDays(p2) + p2->value.date.day;
3519
Daniel Veillard6560a422003-03-27 21:25:38 +00003520 if (p2d > q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003521 ret = 1;
Daniel Veillard6560a422003-03-27 21:25:38 +00003522 } else if (p2d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003523 sec = TIME_TO_NUMBER(p2) - TIME_TO_NUMBER(q1);
3524 if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003525 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003526 else
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003527 ret = 2; /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00003528 }
Daniel Veillard6560a422003-03-27 21:25:38 +00003529 xmlSchemaFreeValue(p1);
3530 xmlSchemaFreeValue(q1);
3531 xmlSchemaFreeValue(p2);
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003532 if (ret != 0)
3533 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003534 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00003535 } else {
3536 xmlSchemaFreeValue(p1);
3537 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003538 }
3539 }
3540
3541 /*
3542 * if the same type then calculate the difference
3543 */
3544 if (x->type == y->type) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003545 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003546 q1 = xmlSchemaDateNormalize(y, 0);
3547 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
3548
3549 p1 = xmlSchemaDateNormalize(x, 0);
3550 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3551
Daniel Veillardfdc91562002-07-01 21:52:03 +00003552 if (p1d < q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003553 ret = -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003554 } else if (p1d > q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003555 ret = 1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003556 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00003557 double sec;
3558
3559 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
3560 if (sec < 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003561 ret = -1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003562 else if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003563 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003564
3565 }
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003566 xmlSchemaFreeValue(p1);
3567 xmlSchemaFreeValue(q1);
3568 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003569 }
3570
3571 switch (x->type) {
3572 case XML_SCHEMAS_DATETIME:
3573 xmask = 0xf;
3574 break;
3575 case XML_SCHEMAS_DATE:
3576 xmask = 0x7;
3577 break;
3578 case XML_SCHEMAS_GYEAR:
3579 xmask = 0x1;
3580 break;
3581 case XML_SCHEMAS_GMONTH:
3582 xmask = 0x2;
3583 break;
3584 case XML_SCHEMAS_GDAY:
3585 xmask = 0x3;
3586 break;
3587 case XML_SCHEMAS_GYEARMONTH:
3588 xmask = 0x3;
3589 break;
3590 case XML_SCHEMAS_GMONTHDAY:
3591 xmask = 0x6;
3592 break;
3593 case XML_SCHEMAS_TIME:
3594 xmask = 0x8;
3595 break;
3596 default:
3597 xmask = 0;
3598 break;
3599 }
3600
3601 switch (y->type) {
3602 case XML_SCHEMAS_DATETIME:
3603 ymask = 0xf;
3604 break;
3605 case XML_SCHEMAS_DATE:
3606 ymask = 0x7;
3607 break;
3608 case XML_SCHEMAS_GYEAR:
3609 ymask = 0x1;
3610 break;
3611 case XML_SCHEMAS_GMONTH:
3612 ymask = 0x2;
3613 break;
3614 case XML_SCHEMAS_GDAY:
3615 ymask = 0x3;
3616 break;
3617 case XML_SCHEMAS_GYEARMONTH:
3618 ymask = 0x3;
3619 break;
3620 case XML_SCHEMAS_GMONTHDAY:
3621 ymask = 0x6;
3622 break;
3623 case XML_SCHEMAS_TIME:
3624 ymask = 0x8;
3625 break;
3626 default:
3627 ymask = 0;
3628 break;
3629 }
3630
3631 xor_mask = xmask ^ ymask; /* mark type differences */
3632 and_mask = xmask & ymask; /* mark field specification */
3633
3634 /* year */
3635 if (xor_mask & 1)
3636 return 2; /* indeterminate */
3637 else if (and_mask & 1) {
3638 if (x->value.date.year < y->value.date.year)
3639 return -1;
3640 else if (x->value.date.year > y->value.date.year)
3641 return 1;
3642 }
3643
3644 /* month */
3645 if (xor_mask & 2)
3646 return 2; /* indeterminate */
3647 else if (and_mask & 2) {
3648 if (x->value.date.mon < y->value.date.mon)
3649 return -1;
3650 else if (x->value.date.mon > y->value.date.mon)
3651 return 1;
3652 }
3653
3654 /* day */
3655 if (xor_mask & 4)
3656 return 2; /* indeterminate */
3657 else if (and_mask & 4) {
3658 if (x->value.date.day < y->value.date.day)
3659 return -1;
3660 else if (x->value.date.day > y->value.date.day)
3661 return 1;
3662 }
3663
3664 /* time */
3665 if (xor_mask & 8)
3666 return 2; /* indeterminate */
3667 else if (and_mask & 8) {
3668 if (x->value.date.hour < y->value.date.hour)
3669 return -1;
3670 else if (x->value.date.hour > y->value.date.hour)
3671 return 1;
3672 else if (x->value.date.min < y->value.date.min)
3673 return -1;
3674 else if (x->value.date.min > y->value.date.min)
3675 return 1;
3676 else if (x->value.date.sec < y->value.date.sec)
3677 return -1;
3678 else if (x->value.date.sec > y->value.date.sec)
3679 return 1;
3680 }
3681
Daniel Veillard070803b2002-05-03 07:29:38 +00003682 return 0;
3683}
3684
3685/**
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003686 * xmlSchemaComparePreserveReplaceStrings:
3687 * @x: a first string value
3688 * @y: a second string value
3689 * @invert: inverts the result if x < y or x > y.
3690 *
3691 * Compare 2 string for their normalized values.
3692 * @x is a string with whitespace of "preserve", @y is
3693 * a string with a whitespace of "replace". I.e. @x could
3694 * be an "xsd:string" and @y an "xsd:normalizedString".
3695 *
3696 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
3697 * case of error
3698 */
3699static int
3700xmlSchemaComparePreserveReplaceStrings(xmlSchemaValPtr x, xmlSchemaValPtr y,
3701 int invert)
3702{
3703 const xmlChar *utf1;
3704 const xmlChar *utf2;
3705 int tmp;
3706
3707 if ((x == NULL) || (y == NULL))
3708 return(-2);
3709 utf1 = x->value.str;
3710 utf2 = y->value.str;
3711
3712 while ((*utf1 != 0) && (*utf2 != 0)) {
3713 if (IS_WSP_REPLACE_CH(*utf2)) {
3714 if (! IS_WSP_SPACE_CH(*utf1)) {
3715 if ((*utf1 - 0x20) < 0) {
3716 if (invert)
3717 return(1);
3718 else
3719 return(-1);
3720 } else {
3721 if (invert)
3722 return(-1);
3723 else
3724 return(1);
3725 }
3726 }
3727 } else {
3728 tmp = *utf1 - *utf2;
3729 if (tmp < 0) {
3730 if (invert)
3731 return(1);
3732 else
3733 return(-1);
3734 }
3735 if (tmp > 0) {
3736 if (invert)
3737 return(-1);
3738 else
3739 return(1);
3740 }
3741 }
3742 utf1++;
3743 utf2++;
3744 }
3745 if (*utf1 != 0) {
3746 if (invert)
3747 return(-1);
3748 else
3749 return(1);
3750 }
3751 if (*utf2 != 0) {
3752 if (invert)
3753 return(1);
3754 else
3755 return(-1);
3756 }
3757 return(0);
3758}
3759
3760/**
3761 * xmlSchemaComparePreserveCollapseStrings:
3762 * @x: a first string value
3763 * @y: a second string value
3764 *
3765 * Compare 2 string for their normalized values.
3766 * @x is a string with whitespace of "preserve", @y is
3767 * a string with a whitespace of "collapse". I.e. @x could
3768 * be an "xsd:string" and @y an "xsd:normalizedString".
3769 *
3770 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
3771 * case of error
3772 */
3773static int
3774xmlSchemaComparePreserveCollapseStrings(xmlSchemaValPtr x, xmlSchemaValPtr y,
3775 int invert)
3776{
3777 const xmlChar *utf1;
3778 const xmlChar *utf2;
3779 int tmp;
3780
3781 if ((x == NULL) || (y == NULL))
3782 return(-2);
3783 utf1 = x->value.str;
3784 utf2 = y->value.str;
3785
3786 /*
3787 * Skip leading blank chars of the collapsed string.
3788 */
3789 while (IS_WSP_SPACE_CH(*utf2) || IS_WSP_REPLACE_CH(*utf2))
3790 utf2++;
3791
3792 while ((*utf1 != 0) && (*utf2 != 0)) {
3793 if (IS_WSP_SPACE_CH(*utf2) || IS_WSP_REPLACE_CH(*utf2)) {
3794 if (! IS_WSP_SPACE_CH(*utf1)) {
3795 /*
3796 * The utf2 character would have been replaced to 0x20.
3797 */
3798 if ((*utf1 - 0x20) < 0) {
3799 if (invert)
3800 return(1);
3801 else
3802 return(-1);
3803 } else {
3804 if (invert)
3805 return(-1);
3806 else
3807 return(1);
3808 }
3809 }
3810 utf1++;
3811 utf2++;
3812 /*
3813 * Skip contiguous blank chars of the collapsed string.
3814 */
3815 while (IS_WSP_SPACE_CH(*utf2) || IS_WSP_REPLACE_CH(*utf2))
3816 utf2++;
3817 } else {
3818 tmp = *utf1++ - *utf2++;
3819 if (tmp < 0) {
3820 if (invert)
3821 return(1);
3822 else
3823 return(-1);
3824 }
3825 if (tmp > 0) {
3826 if (invert)
3827 return(-1);
3828 else
3829 return(1);
3830 }
3831 }
3832 }
3833 if (*utf1 != 0) {
3834 if (invert)
3835 return(-1);
3836 else
3837 return(1);
3838 }
3839 if (*utf2 != 0) {
3840 /*
3841 * Skip trailing blank chars of the collapsed string.
3842 */
3843 while (IS_WSP_SPACE_CH(*utf2) || IS_WSP_REPLACE_CH(*utf2))
3844 utf2++;
3845 if (*utf2 != 0) {
3846 if (invert)
3847 return(1);
3848 else
3849 return(-1);
3850 }
3851 }
3852 return(0);
3853}
3854
3855/**
3856 * xmlSchemaComparePreserveCollapseStrings:
3857 * @x: a first string value
3858 * @y: a second string value
3859 *
3860 * Compare 2 string for their normalized values.
3861 * @x is a string with whitespace of "preserve", @y is
3862 * a string with a whitespace of "collapse". I.e. @x could
3863 * be an "xsd:string" and @y an "xsd:normalizedString".
3864 *
3865 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
3866 * case of error
3867 */
3868static int
3869xmlSchemaCompareReplaceCollapseStrings(xmlSchemaValPtr x, xmlSchemaValPtr y,
3870 int invert)
3871{
3872 const xmlChar *utf1;
3873 const xmlChar *utf2;
3874 int tmp;
3875
3876 if ((x == NULL) || (y == NULL))
3877 return(-2);
3878 utf1 = x->value.str;
3879 utf2 = y->value.str;
3880
3881 /*
3882 * Skip leading blank chars of the collapsed string.
3883 */
3884 while (IS_WSP_SPACE_CH(*utf2) || IS_WSP_REPLACE_CH(*utf2))
3885 utf2++;
3886
3887 while ((*utf1 != 0) && (*utf2 != 0)) {
3888 if (IS_WSP_SPACE_CH(*utf2) || IS_WSP_REPLACE_CH(*utf2)) {
3889 if (! (IS_WSP_SPACE_CH(*utf1) || IS_WSP_REPLACE_CH(*utf1))) {
3890 /*
3891 * The utf2 character would have been replaced to 0x20.
3892 */
3893 if ((*utf1 - 0x20) < 0) {
3894 if (invert)
3895 return(1);
3896 else
3897 return(-1);
3898 } else {
3899 if (invert)
3900 return(-1);
3901 else
3902 return(1);
3903 }
3904 }
3905 utf1++;
3906 utf2++;
3907 /*
3908 * Skip contiguous blank chars of the collapsed string.
3909 */
3910 while (IS_WSP_SPACE_CH(*utf2) || IS_WSP_REPLACE_CH(*utf2))
3911 utf2++;
3912 } else {
3913 if (IS_WSP_SPACE_CH(*utf1) || IS_WSP_REPLACE_CH(*utf1)) {
3914 /*
3915 * The utf1 character would have been replaced to 0x20.
3916 */
3917 if ((0x20 - *utf2) < 0) {
3918 if (invert)
3919 return(1);
3920 else
3921 return(-1);
3922 } else {
3923 if (invert)
3924 return(-1);
3925 else
3926 return(1);
3927 }
3928 }
3929 tmp = *utf1++ - *utf2++;
3930 if (tmp < 0)
3931 return(-1);
3932 if (tmp > 0)
3933 return(1);
3934 }
3935 }
3936 if (*utf1 != 0) {
3937 if (invert)
3938 return(-1);
3939 else
3940 return(1);
3941 }
3942 if (*utf2 != 0) {
3943 /*
3944 * Skip trailing blank chars of the collapsed string.
3945 */
3946 while (IS_WSP_SPACE_CH(*utf2) || IS_WSP_REPLACE_CH(*utf2))
3947 utf2++;
3948 if (*utf2 != 0) {
3949 if (invert)
3950 return(1);
3951 else
3952 return(-1);
3953 }
3954 }
3955 return(0);
3956}
3957
3958
3959/**
3960 * xmlSchemaCompareReplacedStrings:
3961 * @x: a first string value
3962 * @y: a second string value
3963 *
3964 * Compare 2 string for their normalized values.
3965 *
3966 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
3967 * case of error
3968 */
3969static int
3970xmlSchemaCompareReplacedStrings(xmlSchemaValPtr x, xmlSchemaValPtr y)
3971{
3972 const xmlChar *utf1;
3973 const xmlChar *utf2;
3974 int tmp;
3975
3976 if ((x == NULL) || (y == NULL))
3977 return(-2);
3978 utf1 = x->value.str;
3979 utf2 = y->value.str;
3980
3981 while ((*utf1 != 0) && (*utf2 != 0)) {
3982 if (IS_WSP_SPACE_CH(*utf2) || IS_WSP_REPLACE_CH(*utf2)) {
3983 if (! (IS_WSP_SPACE_CH(*utf1) || IS_WSP_REPLACE_CH(*utf1))) {
3984 if ((*utf1 - 0x20) < 0)
3985 return(-1);
3986 else
3987 return(1);
3988 }
3989 } else {
3990 if (IS_WSP_SPACE_CH(*utf1) || IS_WSP_REPLACE_CH(*utf1)) {
3991 if ((0x20 - *utf2) < 0)
3992 return(-1);
3993 else
3994 return(1);
3995 }
3996 tmp = *utf1 - *utf2;
3997 if (tmp < 0)
3998 return(-1);
3999 if (tmp > 0)
4000 return(1);
4001 }
4002 utf1++;
4003 utf2++;
4004 }
4005 if (*utf1 != 0)
4006 return(1);
4007 if (*utf2 != 0)
4008 return(-1);
4009 return(0);
4010}
4011
4012/**
Daniel Veillardc4c21552003-03-29 10:53:38 +00004013 * xmlSchemaCompareNormStrings:
4014 * @x: a first string value
4015 * @y: a second string value
4016 *
4017 * Compare 2 string for their normalized values.
4018 *
4019 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
4020 * case of error
4021 */
4022static int
4023xmlSchemaCompareNormStrings(xmlSchemaValPtr x, xmlSchemaValPtr y) {
4024 const xmlChar *utf1;
4025 const xmlChar *utf2;
4026 int tmp;
4027
4028 if ((x == NULL) || (y == NULL))
4029 return(-2);
4030 utf1 = x->value.str;
4031 utf2 = y->value.str;
4032
William M. Brack76e95df2003-10-18 16:20:14 +00004033 while (IS_BLANK_CH(*utf1)) utf1++;
4034 while (IS_BLANK_CH(*utf2)) utf2++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00004035 while ((*utf1 != 0) && (*utf2 != 0)) {
William M. Brack76e95df2003-10-18 16:20:14 +00004036 if (IS_BLANK_CH(*utf1)) {
4037 if (!IS_BLANK_CH(*utf2)) {
Daniel Veillardc4c21552003-03-29 10:53:38 +00004038 tmp = *utf1 - *utf2;
4039 return(tmp);
4040 }
William M. Brack76e95df2003-10-18 16:20:14 +00004041 while (IS_BLANK_CH(*utf1)) utf1++;
4042 while (IS_BLANK_CH(*utf2)) utf2++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00004043 } else {
4044 tmp = *utf1++ - *utf2++;
4045 if (tmp < 0)
4046 return(-1);
4047 if (tmp > 0)
4048 return(1);
4049 }
4050 }
4051 if (*utf1 != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00004052 while (IS_BLANK_CH(*utf1)) utf1++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00004053 if (*utf1 != 0)
4054 return(1);
4055 }
4056 if (*utf2 != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00004057 while (IS_BLANK_CH(*utf2)) utf2++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00004058 if (*utf2 != 0)
4059 return(-1);
4060 }
4061 return(0);
4062}
4063
4064/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00004065 * xmlSchemaCompareFloats:
4066 * @x: a first float or double value
4067 * @y: a second float or double value
4068 *
4069 * Compare 2 values
4070 *
4071 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
4072 * case of error
4073 */
4074static int
4075xmlSchemaCompareFloats(xmlSchemaValPtr x, xmlSchemaValPtr y) {
4076 double d1, d2;
4077
4078 if ((x == NULL) || (y == NULL))
4079 return(-2);
4080
4081 /*
4082 * Cast everything to doubles.
4083 */
4084 if (x->type == XML_SCHEMAS_DOUBLE)
4085 d1 = x->value.d;
4086 else if (x->type == XML_SCHEMAS_FLOAT)
4087 d1 = x->value.f;
4088 else
4089 return(-2);
4090
4091 if (y->type == XML_SCHEMAS_DOUBLE)
4092 d2 = y->value.d;
4093 else if (y->type == XML_SCHEMAS_FLOAT)
4094 d2 = y->value.f;
4095 else
4096 return(-2);
4097
4098 /*
4099 * Check for special cases.
4100 */
4101 if (xmlXPathIsNaN(d1)) {
4102 if (xmlXPathIsNaN(d2))
4103 return(0);
4104 return(1);
4105 }
4106 if (xmlXPathIsNaN(d2))
4107 return(-1);
4108 if (d1 == xmlXPathPINF) {
4109 if (d2 == xmlXPathPINF)
4110 return(0);
4111 return(1);
4112 }
4113 if (d2 == xmlXPathPINF)
4114 return(-1);
4115 if (d1 == xmlXPathNINF) {
4116 if (d2 == xmlXPathNINF)
4117 return(0);
4118 return(-1);
4119 }
4120 if (d2 == xmlXPathNINF)
4121 return(1);
4122
4123 /*
4124 * basic tests, the last one we should have equality, but
4125 * portability is more important than speed and handling
4126 * NaN or Inf in a portable way is always a challenge, so ...
4127 */
4128 if (d1 < d2)
4129 return(-1);
4130 if (d1 > d2)
4131 return(1);
4132 if (d1 == d2)
4133 return(0);
4134 return(2);
4135}
4136
4137/**
Daniel Veillard4255d502002-04-16 15:50:10 +00004138 * xmlSchemaCompareValues:
4139 * @x: a first value
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004140 * @xwtsp: the whitespace type
Daniel Veillard4255d502002-04-16 15:50:10 +00004141 * @y: a second value
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004142 * @ywtsp: the whitespace type
Daniel Veillard4255d502002-04-16 15:50:10 +00004143 *
4144 * Compare 2 values
4145 *
Daniel Veillard5a872412002-05-22 06:40:27 +00004146 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
4147 * case of error
Daniel Veillard4255d502002-04-16 15:50:10 +00004148 */
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004149static int
4150xmlSchemaCompareValuesInternal(xmlSchemaValPtr x,
4151 xmlSchemaWhitespaceValueType xws,
4152 xmlSchemaValPtr y,
4153 xmlSchemaWhitespaceValueType yws) {
Daniel Veillard4255d502002-04-16 15:50:10 +00004154 if ((x == NULL) || (y == NULL))
4155 return(-2);
4156
4157 switch (x->type) {
Daniel Veillard80b19092003-03-28 13:29:53 +00004158 case XML_SCHEMAS_UNKNOWN:
William M. Brack2f2a6632004-08-20 23:09:47 +00004159 case XML_SCHEMAS_ANYTYPE:
Daniel Veillard80b19092003-03-28 13:29:53 +00004160 return(-2);
4161 case XML_SCHEMAS_INTEGER:
4162 case XML_SCHEMAS_NPINTEGER:
4163 case XML_SCHEMAS_NINTEGER:
4164 case XML_SCHEMAS_NNINTEGER:
4165 case XML_SCHEMAS_PINTEGER:
4166 case XML_SCHEMAS_INT:
4167 case XML_SCHEMAS_UINT:
4168 case XML_SCHEMAS_LONG:
4169 case XML_SCHEMAS_ULONG:
4170 case XML_SCHEMAS_SHORT:
4171 case XML_SCHEMAS_USHORT:
4172 case XML_SCHEMAS_BYTE:
4173 case XML_SCHEMAS_UBYTE:
Daniel Veillard4255d502002-04-16 15:50:10 +00004174 case XML_SCHEMAS_DECIMAL:
Daniel Veillard80b19092003-03-28 13:29:53 +00004175 if (y->type == x->type)
4176 return(xmlSchemaCompareDecimals(x, y));
4177 if ((y->type == XML_SCHEMAS_DECIMAL) ||
4178 (y->type == XML_SCHEMAS_INTEGER) ||
4179 (y->type == XML_SCHEMAS_NPINTEGER) ||
4180 (y->type == XML_SCHEMAS_NINTEGER) ||
4181 (y->type == XML_SCHEMAS_NNINTEGER) ||
4182 (y->type == XML_SCHEMAS_PINTEGER) ||
4183 (y->type == XML_SCHEMAS_INT) ||
4184 (y->type == XML_SCHEMAS_UINT) ||
4185 (y->type == XML_SCHEMAS_LONG) ||
4186 (y->type == XML_SCHEMAS_ULONG) ||
4187 (y->type == XML_SCHEMAS_SHORT) ||
4188 (y->type == XML_SCHEMAS_USHORT) ||
4189 (y->type == XML_SCHEMAS_BYTE) ||
4190 (y->type == XML_SCHEMAS_UBYTE))
Daniel Veillard4255d502002-04-16 15:50:10 +00004191 return(xmlSchemaCompareDecimals(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00004192 return(-2);
Daniel Veillard070803b2002-05-03 07:29:38 +00004193 case XML_SCHEMAS_DURATION:
4194 if (y->type == XML_SCHEMAS_DURATION)
4195 return(xmlSchemaCompareDurations(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00004196 return(-2);
4197 case XML_SCHEMAS_TIME:
4198 case XML_SCHEMAS_GDAY:
4199 case XML_SCHEMAS_GMONTH:
4200 case XML_SCHEMAS_GMONTHDAY:
4201 case XML_SCHEMAS_GYEAR:
4202 case XML_SCHEMAS_GYEARMONTH:
4203 case XML_SCHEMAS_DATE:
4204 case XML_SCHEMAS_DATETIME:
4205 if ((y->type == XML_SCHEMAS_DATETIME) ||
4206 (y->type == XML_SCHEMAS_TIME) ||
4207 (y->type == XML_SCHEMAS_GDAY) ||
4208 (y->type == XML_SCHEMAS_GMONTH) ||
4209 (y->type == XML_SCHEMAS_GMONTHDAY) ||
4210 (y->type == XML_SCHEMAS_GYEAR) ||
4211 (y->type == XML_SCHEMAS_DATE) ||
4212 (y->type == XML_SCHEMAS_GYEARMONTH))
4213 return (xmlSchemaCompareDates(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00004214 return (-2);
Kasimier T. Buchcik2ee855d2005-03-07 11:14:14 +00004215 /*
4216 * Note that we will support comparison of string types against
4217 * anySimpleType as well.
4218 */
4219 case XML_SCHEMAS_ANYSIMPLETYPE:
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004220 case XML_SCHEMAS_STRING:
4221 case XML_SCHEMAS_NORMSTRING:
Daniel Veillard80b19092003-03-28 13:29:53 +00004222 case XML_SCHEMAS_TOKEN:
4223 case XML_SCHEMAS_LANGUAGE:
4224 case XML_SCHEMAS_NMTOKEN:
Daniel Veillard80b19092003-03-28 13:29:53 +00004225 case XML_SCHEMAS_NAME:
Daniel Veillard80b19092003-03-28 13:29:53 +00004226 case XML_SCHEMAS_NCNAME:
4227 case XML_SCHEMAS_ID:
4228 case XML_SCHEMAS_IDREF:
Daniel Veillard80b19092003-03-28 13:29:53 +00004229 case XML_SCHEMAS_ENTITY:
Daniel Veillard80b19092003-03-28 13:29:53 +00004230 case XML_SCHEMAS_NOTATION:
4231 case XML_SCHEMAS_ANYURI:
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004232 /*
4233 * TODO: Compare those against QName.
4234 */
4235 if (y->type == XML_SCHEMAS_QNAME) {
4236 TODO
4237 return (-2);
4238 }
Kasimier T. Buchcik2ee855d2005-03-07 11:14:14 +00004239 if ((y->type == XML_SCHEMAS_ANYSIMPLETYPE) ||
4240 (y->type == XML_SCHEMAS_STRING) ||
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004241 (y->type == XML_SCHEMAS_NORMSTRING) ||
Daniel Veillardc4c21552003-03-29 10:53:38 +00004242 (y->type == XML_SCHEMAS_TOKEN) ||
4243 (y->type == XML_SCHEMAS_LANGUAGE) ||
4244 (y->type == XML_SCHEMAS_NMTOKEN) ||
4245 (y->type == XML_SCHEMAS_NAME) ||
Daniel Veillardc4c21552003-03-29 10:53:38 +00004246 (y->type == XML_SCHEMAS_NCNAME) ||
4247 (y->type == XML_SCHEMAS_ID) ||
4248 (y->type == XML_SCHEMAS_IDREF) ||
4249 (y->type == XML_SCHEMAS_ENTITY) ||
4250 (y->type == XML_SCHEMAS_NOTATION) ||
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004251 (y->type == XML_SCHEMAS_ANYURI)) {
4252
4253 if (xws == XML_SCHEMA_WHITESPACE_PRESERVE) {
4254
4255 if (yws == XML_SCHEMA_WHITESPACE_PRESERVE) {
4256 /* TODO: What about x < y or x > y. */
4257 if (xmlStrEqual(x->value.str, y->value.str))
4258 return (0);
4259 else
4260 return (2);
4261 } else if (yws == XML_SCHEMA_WHITESPACE_REPLACE)
4262 return (xmlSchemaComparePreserveReplaceStrings(x, y, 0));
4263 else if (yws == XML_SCHEMA_WHITESPACE_COLLAPSE)
4264 return (xmlSchemaComparePreserveCollapseStrings(x, y, 0));
4265
4266 } else if (xws == XML_SCHEMA_WHITESPACE_REPLACE) {
4267
4268 if (yws == XML_SCHEMA_WHITESPACE_PRESERVE)
4269 return (xmlSchemaComparePreserveReplaceStrings(y, x, 1));
4270 if (yws == XML_SCHEMA_WHITESPACE_REPLACE)
4271 return (xmlSchemaCompareReplacedStrings(x, y));
4272 if (yws == XML_SCHEMA_WHITESPACE_COLLAPSE)
4273 return (xmlSchemaCompareReplaceCollapseStrings(x, y, 0));
4274
4275 } else if (xws == XML_SCHEMA_WHITESPACE_COLLAPSE) {
4276
4277 if (yws == XML_SCHEMA_WHITESPACE_PRESERVE)
4278 return (xmlSchemaComparePreserveCollapseStrings(y, x, 1));
4279 if (yws == XML_SCHEMA_WHITESPACE_REPLACE)
4280 return (xmlSchemaCompareReplaceCollapseStrings(y, x, 1));
4281 if (yws == XML_SCHEMA_WHITESPACE_COLLAPSE)
4282 return (xmlSchemaCompareNormStrings(x, y));
4283 } else
4284 return (-2);
4285
4286 }
Daniel Veillardc4c21552003-03-29 10:53:38 +00004287 return (-2);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004288 case XML_SCHEMAS_QNAME:
4289 if (y->type == XML_SCHEMAS_QNAME) {
4290 if ((xmlStrEqual(x->value.qname.name, y->value.qname.name)) &&
4291 (xmlStrEqual(x->value.qname.uri, y->value.qname.uri)))
4292 return(0);
4293 return(2);
4294 }
4295 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00004296 case XML_SCHEMAS_FLOAT:
4297 case XML_SCHEMAS_DOUBLE:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00004298 if ((y->type == XML_SCHEMAS_FLOAT) ||
4299 (y->type == XML_SCHEMAS_DOUBLE))
4300 return (xmlSchemaCompareFloats(x, y));
4301 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00004302 case XML_SCHEMAS_BOOLEAN:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00004303 if (y->type == XML_SCHEMAS_BOOLEAN) {
4304 if (x->value.b == y->value.b)
4305 return(0);
4306 if (x->value.b == 0)
4307 return(-1);
4308 return(1);
4309 }
4310 return (-2);
Daniel Veillard560c2a42003-07-06 21:13:49 +00004311 case XML_SCHEMAS_HEXBINARY:
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004312 if (y->type == XML_SCHEMAS_HEXBINARY) {
4313 if (x->value.hex.total == y->value.hex.total) {
4314 int ret = xmlStrcmp(x->value.hex.str, y->value.hex.str);
4315 if (ret > 0)
4316 return(1);
4317 else if (ret == 0)
4318 return(0);
4319 }
4320 else if (x->value.hex.total > y->value.hex.total)
4321 return(1);
4322
4323 return(-1);
4324 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00004325 return (-2);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00004326 case XML_SCHEMAS_BASE64BINARY:
4327 if (y->type == XML_SCHEMAS_BASE64BINARY) {
4328 if (x->value.base64.total == y->value.base64.total) {
4329 int ret = xmlStrcmp(x->value.base64.str,
4330 y->value.base64.str);
4331 if (ret > 0)
4332 return(1);
4333 else if (ret == 0)
4334 return(0);
4335 }
4336 else if (x->value.base64.total > y->value.base64.total)
4337 return(1);
4338 else
4339 return(-1);
4340 }
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004341 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00004342 case XML_SCHEMAS_IDREFS:
4343 case XML_SCHEMAS_ENTITIES:
4344 case XML_SCHEMAS_NMTOKENS:
4345 TODO
4346 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00004347 }
Daniel Veillard5a872412002-05-22 06:40:27 +00004348 return -2;
Daniel Veillard4255d502002-04-16 15:50:10 +00004349}
4350
4351/**
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004352 * xmlSchemaCompareValues:
4353 * @x: a first value
4354 * @y: a second value
4355 *
4356 * Compare 2 values
4357 *
4358 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
4359 * case of error
4360 */
4361int
4362xmlSchemaCompareValues(xmlSchemaValPtr x, xmlSchemaValPtr y) {
4363 xmlSchemaWhitespaceValueType xws, yws;
4364
Daniel Veillard5e094142005-02-18 19:36:12 +00004365 if ((x == NULL) || (y == NULL))
4366 return(-2);
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004367 if (x->type == XML_SCHEMAS_STRING)
4368 xws = XML_SCHEMA_WHITESPACE_PRESERVE;
4369 else if (x->type == XML_SCHEMAS_NORMSTRING)
4370 xws = XML_SCHEMA_WHITESPACE_REPLACE;
4371 else
4372 xws = XML_SCHEMA_WHITESPACE_COLLAPSE;
4373
4374 if (y->type == XML_SCHEMAS_STRING)
4375 yws = XML_SCHEMA_WHITESPACE_PRESERVE;
4376 else if (x->type == XML_SCHEMAS_NORMSTRING)
4377 yws = XML_SCHEMA_WHITESPACE_REPLACE;
4378 else
4379 yws = XML_SCHEMA_WHITESPACE_COLLAPSE;
4380
4381 return(xmlSchemaCompareValuesInternal(x, xws, y, yws));
4382}
4383
4384/**
4385 * xmlSchemaCompareValuesWhtsp:
4386 * @x: a first value
4387 * @xws: the whitespace value of x
4388 * @y: a second value
4389 * @yws: the whitespace value of y
4390 *
4391 * Compare 2 values
4392 *
4393 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
4394 * case of error
4395 */
4396int
4397xmlSchemaCompareValuesWhtsp(xmlSchemaValPtr x,
4398 xmlSchemaWhitespaceValueType xws,
4399 xmlSchemaValPtr y,
4400 xmlSchemaWhitespaceValueType yws) {
4401 return(xmlSchemaCompareValuesInternal(x, xws, y, yws));
4402}
4403
4404/**
Daniel Veillardc4c21552003-03-29 10:53:38 +00004405 * xmlSchemaNormLen:
4406 * @value: a string
4407 *
4408 * Computes the UTF8 length of the normalized value of the string
4409 *
4410 * Returns the length or -1 in case of error.
4411 */
4412static int
4413xmlSchemaNormLen(const xmlChar *value) {
4414 const xmlChar *utf;
4415 int ret = 0;
4416
4417 if (value == NULL)
4418 return(-1);
4419 utf = value;
William M. Brack76e95df2003-10-18 16:20:14 +00004420 while (IS_BLANK_CH(*utf)) utf++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00004421 while (*utf != 0) {
4422 if (utf[0] & 0x80) {
4423 if ((utf[1] & 0xc0) != 0x80)
4424 return(-1);
4425 if ((utf[0] & 0xe0) == 0xe0) {
4426 if ((utf[2] & 0xc0) != 0x80)
4427 return(-1);
4428 if ((utf[0] & 0xf0) == 0xf0) {
4429 if ((utf[0] & 0xf8) != 0xf0 || (utf[3] & 0xc0) != 0x80)
4430 return(-1);
4431 utf += 4;
4432 } else {
4433 utf += 3;
4434 }
4435 } else {
4436 utf += 2;
4437 }
William M. Brack76e95df2003-10-18 16:20:14 +00004438 } else if (IS_BLANK_CH(*utf)) {
4439 while (IS_BLANK_CH(*utf)) utf++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00004440 if (*utf == 0)
4441 break;
4442 } else {
4443 utf++;
4444 }
4445 ret++;
4446 }
4447 return(ret);
4448}
4449
Daniel Veillard6927b102004-10-27 17:29:04 +00004450/**
4451 * xmlSchemaGetFacetValueAsULong:
4452 * @facet: an schemas type facet
4453 *
4454 * Extract the value of a facet
4455 *
4456 * Returns the value as a long
4457 */
Daniel Veillardc0826a72004-08-10 14:17:33 +00004458unsigned long
4459xmlSchemaGetFacetValueAsULong(xmlSchemaFacetPtr facet)
4460{
4461 /*
4462 * TODO: Check if this is a decimal.
4463 */
William M. Brack094dd862004-11-14 14:28:34 +00004464 if (facet == NULL)
4465 return 0;
Daniel Veillardc0826a72004-08-10 14:17:33 +00004466 return ((unsigned long) facet->val->value.decimal.lo);
4467}
4468
Daniel Veillardc4c21552003-03-29 10:53:38 +00004469/**
Daniel Veillard01fa6152004-06-29 17:04:39 +00004470 * xmlSchemaValidateListSimpleTypeFacet:
4471 * @facet: the facet to check
4472 * @value: the lexical repr of the value to validate
4473 * @actualLen: the number of list items
4474 * @expectedLen: the resulting expected number of list items
4475 *
4476 * Checks the value of a list simple type against a facet.
4477 *
4478 * Returns 0 if the value is valid, a positive error code
4479 * number otherwise and -1 in case of an internal error.
4480 */
4481int
4482xmlSchemaValidateListSimpleTypeFacet(xmlSchemaFacetPtr facet,
4483 const xmlChar *value,
4484 unsigned long actualLen,
4485 unsigned long *expectedLen)
4486{
Daniel Veillardce682bc2004-11-05 17:22:25 +00004487 if (facet == NULL)
4488 return(-1);
Daniel Veillard01fa6152004-06-29 17:04:39 +00004489 /*
4490 * TODO: Check if this will work with large numbers.
4491 * (compare value.decimal.mi and value.decimal.hi as well?).
4492 */
4493 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
4494 if (actualLen != facet->val->value.decimal.lo) {
Daniel Veillardc0826a72004-08-10 14:17:33 +00004495 if (expectedLen != 0)
4496 *expectedLen = facet->val->value.decimal.lo;
Daniel Veillard01fa6152004-06-29 17:04:39 +00004497 return (XML_SCHEMAV_CVC_LENGTH_VALID);
4498 }
4499 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
4500 if (actualLen < facet->val->value.decimal.lo) {
Daniel Veillardc0826a72004-08-10 14:17:33 +00004501 if (expectedLen != 0)
4502 *expectedLen = facet->val->value.decimal.lo;
Daniel Veillard01fa6152004-06-29 17:04:39 +00004503 return (XML_SCHEMAV_CVC_MINLENGTH_VALID);
4504 }
4505 } else if (facet->type == XML_SCHEMA_FACET_MAXLENGTH) {
4506 if (actualLen > facet->val->value.decimal.lo) {
Daniel Veillardc0826a72004-08-10 14:17:33 +00004507 if (expectedLen != 0)
4508 *expectedLen = facet->val->value.decimal.lo;
Daniel Veillard01fa6152004-06-29 17:04:39 +00004509 return (XML_SCHEMAV_CVC_MAXLENGTH_VALID);
4510 }
4511 } else
4512 /*
4513 * NOTE: That we can pass NULL as xmlSchemaValPtr to
4514 * xmlSchemaValidateFacet, since the remaining facet types
4515 * are: XML_SCHEMA_FACET_PATTERN, XML_SCHEMA_FACET_ENUMERATION.
4516 */
4517 return(xmlSchemaValidateFacet(NULL, facet, value, NULL));
4518 return (0);
4519}
4520
4521/**
Daniel Veillard6927b102004-10-27 17:29:04 +00004522 * xmlSchemaValidateLengthFacet:
Daniel Veillardc0826a72004-08-10 14:17:33 +00004523 * @type: the built-in type
4524 * @facet: the facet to check
4525 * @value: the lexical repr. of the value to be validated
4526 * @val: the precomputed value
4527 * @length: the actual length of the value
4528 *
4529 * Checka a value against a "length", "minLength" and "maxLength"
4530 * facet; sets @length to the computed length of @value.
4531 *
4532 * Returns 0 if the value is valid, a positive error code
4533 * otherwise and -1 in case of an internal or API error.
4534 */
4535int
4536xmlSchemaValidateLengthFacet(xmlSchemaTypePtr type,
4537 xmlSchemaFacetPtr facet,
4538 const xmlChar *value,
4539 xmlSchemaValPtr val,
4540 unsigned long *length)
4541{
4542 unsigned int len = 0;
4543
Daniel Veillardce682bc2004-11-05 17:22:25 +00004544 if ((length == NULL) || (facet == NULL) || (type == NULL))
4545 return (-1);
Daniel Veillardc0826a72004-08-10 14:17:33 +00004546 *length = 0;
4547 if ((facet->type != XML_SCHEMA_FACET_LENGTH) &&
4548 (facet->type != XML_SCHEMA_FACET_MAXLENGTH) &&
4549 (facet->type != XML_SCHEMA_FACET_MINLENGTH))
4550 return (-1);
4551
4552 if ((facet->val == NULL) ||
4553 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
4554 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
4555 (facet->val->value.decimal.frac != 0)) {
4556 return(-1);
4557 }
4558 if ((val != NULL) && (val->type == XML_SCHEMAS_HEXBINARY))
4559 len = val->value.hex.total;
4560 else if ((val != NULL) && (val->type == XML_SCHEMAS_BASE64BINARY))
4561 len = val->value.base64.total;
4562 else {
4563 switch (type->builtInType) {
4564 case XML_SCHEMAS_IDREF:
4565 case XML_SCHEMAS_NORMSTRING:
4566 case XML_SCHEMAS_TOKEN:
4567 case XML_SCHEMAS_LANGUAGE:
4568 case XML_SCHEMAS_NMTOKEN:
4569 case XML_SCHEMAS_NAME:
4570 case XML_SCHEMAS_NCNAME:
4571 case XML_SCHEMAS_ID:
4572 len = xmlSchemaNormLen(value);
4573 break;
4574 case XML_SCHEMAS_STRING:
4575 /*
4576 * FIXME: What exactly to do with anyURI?
4577 */
4578 case XML_SCHEMAS_ANYURI:
4579 if (value != NULL)
4580 len = xmlUTF8Strlen(value);
4581 break;
4582 default:
4583 TODO
4584 }
4585 }
4586 *length = (unsigned long) len;
4587 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
4588 if (len != facet->val->value.decimal.lo)
4589 return(XML_SCHEMAV_CVC_LENGTH_VALID);
4590 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
4591 if (len < facet->val->value.decimal.lo)
4592 return(XML_SCHEMAV_CVC_MINLENGTH_VALID);
4593 } else {
4594 if (len > facet->val->value.decimal.lo)
4595 return(XML_SCHEMAV_CVC_MAXLENGTH_VALID);
4596 }
4597
4598 return (0);
4599}
4600
4601/**
4602 * xmlSchemaValidateFacet:
Daniel Veillard01c13b52002-12-10 15:19:08 +00004603 * @base: the base type
Daniel Veillard4255d502002-04-16 15:50:10 +00004604 * @facet: the facet to check
4605 * @value: the lexical repr of the value to validate
4606 * @val: the precomputed value
4607 *
4608 * Check a value against a facet condition
4609 *
4610 * Returns 0 if the element is schemas valid, a positive error code
4611 * number otherwise and -1 in case of internal or API error.
4612 */
4613int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00004614xmlSchemaValidateFacet(xmlSchemaTypePtr base ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +00004615 xmlSchemaFacetPtr facet,
Daniel Veillard4255d502002-04-16 15:50:10 +00004616 const xmlChar *value, xmlSchemaValPtr val)
4617{
4618 int ret;
4619
Daniel Veillardce682bc2004-11-05 17:22:25 +00004620 if ((facet == NULL) || (value == NULL))
4621 return(-1);
Daniel Veillard4255d502002-04-16 15:50:10 +00004622 switch (facet->type) {
4623 case XML_SCHEMA_FACET_PATTERN:
4624 ret = xmlRegexpExec(facet->regexp, value);
4625 if (ret == 1)
4626 return(0);
4627 if (ret == 0) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00004628 return(XML_SCHEMAV_CVC_PATTERN_VALID);
Daniel Veillard4255d502002-04-16 15:50:10 +00004629 }
4630 return(ret);
4631 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
4632 ret = xmlSchemaCompareValues(val, facet->val);
4633 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004634 /* TODO error code */
Daniel Veillard4255d502002-04-16 15:50:10 +00004635 return(-1);
4636 }
4637 if (ret == -1)
4638 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00004639 /* error code */
Daniel Veillard01fa6152004-06-29 17:04:39 +00004640 return(XML_SCHEMAV_CVC_MAXEXCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00004641 case XML_SCHEMA_FACET_MAXINCLUSIVE:
4642 ret = xmlSchemaCompareValues(val, facet->val);
4643 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004644 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00004645 return(-1);
4646 }
4647 if ((ret == -1) || (ret == 0))
4648 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00004649 /* error code */
Daniel Veillard01fa6152004-06-29 17:04:39 +00004650 return(XML_SCHEMAV_CVC_MAXINCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00004651 case XML_SCHEMA_FACET_MINEXCLUSIVE:
4652 ret = xmlSchemaCompareValues(val, facet->val);
4653 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004654 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00004655 return(-1);
4656 }
4657 if (ret == 1)
4658 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00004659 /* error code */
Daniel Veillard01fa6152004-06-29 17:04:39 +00004660 return(XML_SCHEMAV_CVC_MINEXCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00004661 case XML_SCHEMA_FACET_MININCLUSIVE:
4662 ret = xmlSchemaCompareValues(val, facet->val);
4663 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004664 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00004665 return(-1);
4666 }
4667 if ((ret == 1) || (ret == 0))
4668 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00004669 /* error code */
Daniel Veillard01fa6152004-06-29 17:04:39 +00004670 return(XML_SCHEMAV_CVC_MININCLUSIVE_VALID);
Daniel Veillard8651f532002-04-17 09:06:27 +00004671 case XML_SCHEMA_FACET_WHITESPACE:
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004672 /* TODO whitespaces */
Daniel Veillard01fa6152004-06-29 17:04:39 +00004673 /*
4674 * NOTE: Whitespace should be handled to normalize
4675 * the value to be validated against a the facets;
4676 * not to normalize the value in-between.
4677 */
Daniel Veillard8651f532002-04-17 09:06:27 +00004678 return(0);
Daniel Veillard88c58912002-04-23 07:12:20 +00004679 case XML_SCHEMA_FACET_ENUMERATION:
4680 if ((facet->value != NULL) &&
4681 (xmlStrEqual(facet->value, value)))
4682 return(0);
Daniel Veillard01fa6152004-06-29 17:04:39 +00004683 return(XML_SCHEMAV_CVC_ENUMERATION_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004684 case XML_SCHEMA_FACET_LENGTH:
4685 case XML_SCHEMA_FACET_MAXLENGTH:
4686 case XML_SCHEMA_FACET_MINLENGTH: {
4687 unsigned int len = 0;
4688
4689 if ((facet->val == NULL) ||
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004690 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
4691 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004692 (facet->val->value.decimal.frac != 0)) {
4693 return(-1);
4694 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00004695 if ((val != NULL) && (val->type == XML_SCHEMAS_HEXBINARY))
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004696 len = val->value.hex.total;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00004697 else if ((val != NULL) && (val->type == XML_SCHEMAS_BASE64BINARY))
4698 len = val->value.base64.total;
4699 else {
Daniel Veillard01fa6152004-06-29 17:04:39 +00004700 switch (base->builtInType) {
Daniel Veillard560c2a42003-07-06 21:13:49 +00004701 case XML_SCHEMAS_IDREF:
4702 case XML_SCHEMAS_NORMSTRING:
4703 case XML_SCHEMAS_TOKEN:
4704 case XML_SCHEMAS_LANGUAGE:
4705 case XML_SCHEMAS_NMTOKEN:
4706 case XML_SCHEMAS_NAME:
4707 case XML_SCHEMAS_NCNAME:
4708 case XML_SCHEMAS_ID:
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004709 len = xmlSchemaNormLen(value);
4710 break;
Daniel Veillard560c2a42003-07-06 21:13:49 +00004711 case XML_SCHEMAS_STRING:
Daniel Veillard01fa6152004-06-29 17:04:39 +00004712 /*
4713 * FIXME: What exactly to do with anyURI?
4714 */
4715 case XML_SCHEMAS_ANYURI:
William M. Brackfbf2c5e2004-02-03 17:55:56 +00004716 if (value != NULL)
4717 len = xmlUTF8Strlen(value);
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004718 break;
Daniel Veillard560c2a42003-07-06 21:13:49 +00004719 default:
4720 TODO
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004721 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004722 }
4723 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004724 if (len != facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004725 return(XML_SCHEMAV_CVC_LENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004726 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004727 if (len < facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004728 return(XML_SCHEMAV_CVC_MINLENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004729 } else {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004730 if (len > facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004731 return(XML_SCHEMAV_CVC_MAXLENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004732 }
4733 break;
4734 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00004735 case XML_SCHEMA_FACET_TOTALDIGITS:
4736 case XML_SCHEMA_FACET_FRACTIONDIGITS:
4737
4738 if ((facet->val == NULL) ||
4739 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
4740 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
4741 (facet->val->value.decimal.frac != 0)) {
4742 return(-1);
4743 }
4744 if ((val == NULL) ||
4745 ((val->type != XML_SCHEMAS_DECIMAL) &&
4746 (val->type != XML_SCHEMAS_INTEGER) &&
4747 (val->type != XML_SCHEMAS_NPINTEGER) &&
4748 (val->type != XML_SCHEMAS_NINTEGER) &&
4749 (val->type != XML_SCHEMAS_NNINTEGER) &&
4750 (val->type != XML_SCHEMAS_PINTEGER) &&
4751 (val->type != XML_SCHEMAS_INT) &&
4752 (val->type != XML_SCHEMAS_UINT) &&
4753 (val->type != XML_SCHEMAS_LONG) &&
4754 (val->type != XML_SCHEMAS_ULONG) &&
4755 (val->type != XML_SCHEMAS_SHORT) &&
4756 (val->type != XML_SCHEMAS_USHORT) &&
4757 (val->type != XML_SCHEMAS_BYTE) &&
4758 (val->type != XML_SCHEMAS_UBYTE))) {
4759 return(-1);
4760 }
4761 if (facet->type == XML_SCHEMA_FACET_TOTALDIGITS) {
4762 if (val->value.decimal.total > facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004763 return(XML_SCHEMAV_CVC_TOTALDIGITS_VALID);
Daniel Veillard560c2a42003-07-06 21:13:49 +00004764
4765 } else if (facet->type == XML_SCHEMA_FACET_FRACTIONDIGITS) {
4766 if (val->value.decimal.frac > facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004767 return(XML_SCHEMAV_CVC_FRACTIONDIGITS_VALID);
Daniel Veillard560c2a42003-07-06 21:13:49 +00004768 }
4769 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00004770 default:
4771 TODO
4772 }
4773 return(0);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00004774
Daniel Veillard4255d502002-04-16 15:50:10 +00004775}
4776
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004777/**
4778 * xmlSchemaGetCanonValue:
4779 * @val: the precomputed value
4780 * @retValue: the returned value
4781 *
Daniel Veillardb5839c32005-02-19 18:27:14 +00004782 * Get a the cononical representation of the value.
4783 * The caller has to free the returned retValue.
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004784 *
4785 * Returns 0 if the value could be built and -1 in case of
4786 * API errors or if the value type is not supported yet.
4787 */
4788int
Daniel Veillardb5839c32005-02-19 18:27:14 +00004789xmlSchemaGetCanonValue(xmlSchemaValPtr val, const xmlChar **retValue)
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004790{
Daniel Veillardb5839c32005-02-19 18:27:14 +00004791 if ((retValue == NULL) || (val == NULL))
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004792 return (-1);
4793 *retValue = NULL;
4794 switch (val->type) {
4795 case XML_SCHEMAS_STRING:
4796 case XML_SCHEMAS_NORMSTRING:
4797 /*
4798 case XML_SCHEMAS_TOKEN:
4799 case XML_SCHEMAS_LANGUAGE:
4800 case XML_SCHEMAS_NMTOKEN:
4801 case XML_SCHEMAS_NAME:
4802 case XML_SCHEMAS_QNAME:
4803 case XML_SCHEMAS_NCNAME:
4804 case XML_SCHEMAS_ID:
4805 case XML_SCHEMAS_IDREF:
4806 case XML_SCHEMAS_ENTITY:
4807 case XML_SCHEMAS_NOTATION:
4808 case XML_SCHEMAS_ANYURI:
4809 */
4810 if (val->value.str == NULL)
4811 *retValue = NULL;
4812 else
4813 /* TODO: This is not yet correct for non-normalized values. */
4814 *retValue =
4815 BAD_CAST xmlStrdup((const xmlChar *) val->value.str);
4816 return (0);
4817 default:
4818 return (-1);
4819 }
4820 return (-1);
4821}
4822
Daniel Veillard4255d502002-04-16 15:50:10 +00004823#endif /* LIBXML_SCHEMAS_ENABLED */