blob: d7249e08f761ed3163c3b03eb5253cdb575c979f [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 */
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00001933 if (dec != -1) {
William M. Brack273670f2005-03-11 15:55:14 +00001934 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) {
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00002068 /*
2069 * TODO: sscanf seems not to give the correct
2070 * value for extremely high/low values.
2071 * E.g. "1E-149" results in zero.
2072 */
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002073 if (sscanf((const char *) value, "%f",
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002074 &(v->value.f)) == 1) {
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00002075 *val = v;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002076 } else {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002077 xmlSchemaFreeValue(v);
2078 goto return1;
2079 }
2080 } else {
2081 goto error;
2082 }
2083 } else {
2084 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
2085 if (v != NULL) {
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00002086 /*
2087 * TODO: sscanf seems not to give the correct
2088 * value for extremely high/low values.
2089 */
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002090 if (sscanf((const char *) value, "%lf",
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002091 &(v->value.d)) == 1) {
2092 *val = v;
2093 } else {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002094 xmlSchemaFreeValue(v);
2095 goto return1;
2096 }
2097 } else {
2098 goto error;
2099 }
2100 }
2101 }
2102 goto return0;
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00002103 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002104 case XML_SCHEMAS_BOOLEAN:{
2105 const xmlChar *cur = value;
2106
2107 if ((cur[0] == '0') && (cur[1] == 0))
2108 ret = 0;
2109 else if ((cur[0] == '1') && (cur[1] == 0))
2110 ret = 1;
2111 else if ((cur[0] == 't') && (cur[1] == 'r')
2112 && (cur[2] == 'u') && (cur[3] == 'e')
2113 && (cur[4] == 0))
2114 ret = 1;
2115 else if ((cur[0] == 'f') && (cur[1] == 'a')
2116 && (cur[2] == 'l') && (cur[3] == 's')
2117 && (cur[4] == 'e') && (cur[5] == 0))
2118 ret = 0;
2119 else
2120 goto return1;
2121 if (val != NULL) {
2122 v = xmlSchemaNewValue(XML_SCHEMAS_BOOLEAN);
2123 if (v != NULL) {
2124 v->value.b = ret;
2125 *val = v;
2126 } else {
2127 goto error;
2128 }
2129 }
2130 goto return0;
2131 }
2132 case XML_SCHEMAS_TOKEN:{
2133 const xmlChar *cur = value;
2134
William M. Brack76e95df2003-10-18 16:20:14 +00002135 if (IS_BLANK_CH(*cur))
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002136 goto return1;
2137
2138 while (*cur != 0) {
2139 if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) {
2140 goto return1;
2141 } else if (*cur == ' ') {
2142 cur++;
2143 if (*cur == 0)
2144 goto return1;
2145 if (*cur == ' ')
2146 goto return1;
2147 } else {
2148 cur++;
2149 }
2150 }
2151 if (val != NULL) {
2152 v = xmlSchemaNewValue(XML_SCHEMAS_TOKEN);
2153 if (v != NULL) {
2154 v->value.str = xmlStrdup(value);
2155 *val = v;
2156 } else {
2157 goto error;
2158 }
2159 }
2160 goto return0;
2161 }
2162 case XML_SCHEMAS_LANGUAGE:
2163 if (xmlCheckLanguageID(value) == 1) {
2164 if (val != NULL) {
2165 v = xmlSchemaNewValue(XML_SCHEMAS_LANGUAGE);
2166 if (v != NULL) {
2167 v->value.str = xmlStrdup(value);
2168 *val = v;
2169 } else {
2170 goto error;
2171 }
2172 }
2173 goto return0;
2174 }
2175 goto return1;
2176 case XML_SCHEMAS_NMTOKEN:
2177 if (xmlValidateNMToken(value, 1) == 0) {
2178 if (val != NULL) {
2179 v = xmlSchemaNewValue(XML_SCHEMAS_NMTOKEN);
2180 if (v != NULL) {
2181 v->value.str = xmlStrdup(value);
2182 *val = v;
2183 } else {
2184 goto error;
2185 }
2186 }
2187 goto return0;
2188 }
2189 goto return1;
2190 case XML_SCHEMAS_NMTOKENS:
2191 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeNmtokenDef,
2192 value, val, node);
2193 if (ret > 0)
2194 ret = 0;
2195 else
2196 ret = 1;
2197 goto done;
2198 case XML_SCHEMAS_NAME:
2199 ret = xmlValidateName(value, 1);
Daniel Veillarddf292f72005-01-16 19:00:15 +00002200 if ((ret == 0) && (val != NULL) && (value != NULL)) {
2201 v = xmlSchemaNewValue(XML_SCHEMAS_NAME);
2202 if (v != NULL) {
2203 const xmlChar *start = value, *end;
2204 while (IS_BLANK_CH(*start)) start++;
2205 end = start;
2206 while ((*end != 0) && (!IS_BLANK_CH(*end))) end++;
2207 v->value.str = xmlStrndup(start, end - start);
2208 *val = v;
2209 } else {
2210 goto error;
2211 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002212 }
2213 goto done;
2214 case XML_SCHEMAS_QNAME:{
2215 xmlChar *uri = NULL;
2216 xmlChar *local = NULL;
2217
2218 ret = xmlValidateQName(value, 1);
2219 if ((ret == 0) && (node != NULL)) {
2220 xmlChar *prefix;
2221
2222 local = xmlSplitQName2(value, &prefix);
2223 if (prefix != NULL) {
2224 xmlNsPtr ns;
2225
2226 ns = xmlSearchNs(node->doc, node, prefix);
2227 if (ns == NULL)
2228 ret = 1;
2229 else if (val != NULL)
2230 uri = xmlStrdup(ns->href);
2231 }
2232 if ((local != NULL) && ((val == NULL) || (ret != 0)))
2233 xmlFree(local);
2234 if (prefix != NULL)
2235 xmlFree(prefix);
2236 }
2237 if ((ret == 0) && (val != NULL)) {
2238 v = xmlSchemaNewValue(XML_SCHEMAS_QNAME);
2239 if (v != NULL) {
2240 if (local != NULL)
2241 v->value.qname.name = local;
2242 else
2243 v->value.qname.name = xmlStrdup(value);
2244 if (uri != NULL)
2245 v->value.qname.uri = uri;
2246
2247 *val = v;
2248 } else {
2249 if (local != NULL)
2250 xmlFree(local);
2251 if (uri != NULL)
2252 xmlFree(uri);
2253 goto error;
2254 }
2255 }
2256 goto done;
2257 }
2258 case XML_SCHEMAS_NCNAME:
2259 ret = xmlValidateNCName(value, 1);
2260 if ((ret == 0) && (val != NULL)) {
2261 v = xmlSchemaNewValue(XML_SCHEMAS_NCNAME);
2262 if (v != NULL) {
2263 v->value.str = xmlStrdup(value);
2264 *val = v;
2265 } else {
2266 goto error;
2267 }
2268 }
2269 goto done;
2270 case XML_SCHEMAS_ID:
2271 ret = xmlValidateNCName(value, 1);
2272 if ((ret == 0) && (val != NULL)) {
2273 v = xmlSchemaNewValue(XML_SCHEMAS_ID);
2274 if (v != NULL) {
2275 v->value.str = xmlStrdup(value);
2276 *val = v;
2277 } else {
2278 goto error;
2279 }
2280 }
2281 if ((ret == 0) && (node != NULL) &&
2282 (node->type == XML_ATTRIBUTE_NODE)) {
2283 xmlAttrPtr attr = (xmlAttrPtr) node;
2284
2285 /*
2286 * NOTE: the IDness might have already be declared in the DTD
2287 */
2288 if (attr->atype != XML_ATTRIBUTE_ID) {
2289 xmlIDPtr res;
2290 xmlChar *strip;
2291
2292 strip = xmlSchemaStrip(value);
2293 if (strip != NULL) {
2294 res = xmlAddID(NULL, node->doc, strip, attr);
2295 xmlFree(strip);
2296 } else
2297 res = xmlAddID(NULL, node->doc, value, attr);
2298 if (res == NULL) {
2299 ret = 2;
2300 } else {
2301 attr->atype = XML_ATTRIBUTE_ID;
2302 }
2303 }
2304 }
2305 goto done;
2306 case XML_SCHEMAS_IDREF:
2307 ret = xmlValidateNCName(value, 1);
2308 if ((ret == 0) && (val != NULL)) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00002309 v = xmlSchemaNewValue(XML_SCHEMAS_IDREF);
2310 if (v == NULL)
2311 goto error;
2312 v->value.str = xmlStrdup(value);
2313 *val = v;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002314 }
2315 if ((ret == 0) && (node != NULL) &&
2316 (node->type == XML_ATTRIBUTE_NODE)) {
2317 xmlAttrPtr attr = (xmlAttrPtr) node;
2318 xmlChar *strip;
2319
2320 strip = xmlSchemaStrip(value);
2321 if (strip != NULL) {
2322 xmlAddRef(NULL, node->doc, strip, attr);
2323 xmlFree(strip);
2324 } else
2325 xmlAddRef(NULL, node->doc, value, attr);
2326 attr->atype = XML_ATTRIBUTE_IDREF;
2327 }
2328 goto done;
2329 case XML_SCHEMAS_IDREFS:
2330 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeIdrefDef,
2331 value, val, node);
2332 if (ret < 0)
2333 ret = 2;
2334 else
2335 ret = 0;
2336 if ((ret == 0) && (node != NULL) &&
2337 (node->type == XML_ATTRIBUTE_NODE)) {
2338 xmlAttrPtr attr = (xmlAttrPtr) node;
2339
2340 attr->atype = XML_ATTRIBUTE_IDREFS;
2341 }
2342 goto done;
2343 case XML_SCHEMAS_ENTITY:{
2344 xmlChar *strip;
2345
2346 ret = xmlValidateNCName(value, 1);
2347 if ((node == NULL) || (node->doc == NULL))
2348 ret = 3;
2349 if (ret == 0) {
2350 xmlEntityPtr ent;
2351
2352 strip = xmlSchemaStrip(value);
2353 if (strip != NULL) {
2354 ent = xmlGetDocEntity(node->doc, strip);
2355 xmlFree(strip);
2356 } else {
2357 ent = xmlGetDocEntity(node->doc, value);
2358 }
2359 if ((ent == NULL) ||
2360 (ent->etype !=
2361 XML_EXTERNAL_GENERAL_UNPARSED_ENTITY))
2362 ret = 4;
2363 }
2364 if ((ret == 0) && (val != NULL)) {
2365 TODO;
2366 }
2367 if ((ret == 0) && (node != NULL) &&
2368 (node->type == XML_ATTRIBUTE_NODE)) {
2369 xmlAttrPtr attr = (xmlAttrPtr) node;
2370
2371 attr->atype = XML_ATTRIBUTE_ENTITY;
2372 }
2373 goto done;
2374 }
2375 case XML_SCHEMAS_ENTITIES:
2376 if ((node == NULL) || (node->doc == NULL))
2377 goto return3;
2378 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeEntityDef,
2379 value, val, node);
2380 if (ret <= 0)
2381 ret = 1;
2382 else
2383 ret = 0;
2384 if ((ret == 0) && (node != NULL) &&
2385 (node->type == XML_ATTRIBUTE_NODE)) {
2386 xmlAttrPtr attr = (xmlAttrPtr) node;
2387
2388 attr->atype = XML_ATTRIBUTE_ENTITIES;
2389 }
2390 goto done;
2391 case XML_SCHEMAS_NOTATION:{
2392 xmlChar *uri = NULL;
2393 xmlChar *local = NULL;
2394
2395 ret = xmlValidateQName(value, 1);
2396 if ((ret == 0) && (node != NULL)) {
2397 xmlChar *prefix;
2398
2399 local = xmlSplitQName2(value, &prefix);
2400 if (prefix != NULL) {
2401 xmlNsPtr ns;
2402
2403 ns = xmlSearchNs(node->doc, node, prefix);
2404 if (ns == NULL)
2405 ret = 1;
2406 else if (val != NULL)
2407 uri = xmlStrdup(ns->href);
2408 }
2409 if ((local != NULL) && ((val == NULL) || (ret != 0)))
2410 xmlFree(local);
2411 if (prefix != NULL)
2412 xmlFree(prefix);
2413 }
2414 if ((node == NULL) || (node->doc == NULL))
2415 ret = 3;
2416 if (ret == 0) {
2417 ret = xmlValidateNotationUse(NULL, node->doc, value);
2418 if (ret == 1)
2419 ret = 0;
2420 else
2421 ret = 1;
2422 }
2423 if ((ret == 0) && (val != NULL)) {
2424 v = xmlSchemaNewValue(XML_SCHEMAS_NOTATION);
2425 if (v != NULL) {
2426 if (local != NULL)
2427 v->value.qname.name = local;
2428 else
2429 v->value.qname.name = xmlStrdup(value);
2430 if (uri != NULL)
2431 v->value.qname.uri = uri;
2432
2433 *val = v;
2434 } else {
2435 if (local != NULL)
2436 xmlFree(local);
2437 if (uri != NULL)
2438 xmlFree(uri);
2439 goto error;
2440 }
2441 }
2442 goto done;
2443 }
2444 case XML_SCHEMAS_ANYURI:{
Daniel Veillard11c466a2004-03-14 12:20:15 +00002445 if (*value != 0) {
2446 xmlURIPtr uri = xmlParseURI((const char *) value);
2447 if (uri == NULL)
2448 goto return1;
2449 xmlFreeURI(uri);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002450 }
Daniel Veillard11c466a2004-03-14 12:20:15 +00002451
2452 if (val != NULL) {
2453 v = xmlSchemaNewValue(XML_SCHEMAS_ANYURI);
2454 if (v == NULL)
2455 goto error;
2456 v->value.str = xmlStrdup(value);
2457 *val = v;
2458 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002459 goto return0;
2460 }
2461 case XML_SCHEMAS_HEXBINARY:{
2462 const xmlChar *cur = value;
2463 xmlChar *base;
2464 int total, i = 0;
2465
Daniel Veillardf34a20e2004-08-31 08:42:17 +00002466 if (cur == NULL)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002467 goto return1;
2468
2469 while (((*cur >= '0') && (*cur <= '9')) ||
2470 ((*cur >= 'A') && (*cur <= 'F')) ||
2471 ((*cur >= 'a') && (*cur <= 'f'))) {
2472 i++;
2473 cur++;
2474 }
2475
2476 if (*cur != 0)
2477 goto return1;
2478 if ((i % 2) != 0)
2479 goto return1;
2480
2481 if (val != NULL) {
2482
2483 v = xmlSchemaNewValue(XML_SCHEMAS_HEXBINARY);
2484 if (v == NULL)
2485 goto error;
2486
2487 cur = xmlStrdup(value);
2488 if (cur == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002489 xmlSchemaTypeErrMemory(node, "allocating hexbin data");
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002490 xmlFree(v);
2491 goto return1;
2492 }
2493
2494 total = i / 2; /* number of octets */
2495
2496 base = (xmlChar *) cur;
2497 while (i-- > 0) {
2498 if (*base >= 'a')
2499 *base = *base - ('a' - 'A');
2500 base++;
2501 }
2502
2503 v->value.hex.str = (xmlChar *) cur;
2504 v->value.hex.total = total;
2505 *val = v;
2506 }
2507 goto return0;
2508 }
2509 case XML_SCHEMAS_BASE64BINARY:{
2510 /* ISSUE:
2511 *
2512 * Ignore all stray characters? (yes, currently)
2513 * Worry about long lines? (no, currently)
2514 *
2515 * rfc2045.txt:
2516 *
2517 * "The encoded output stream must be represented in lines of
2518 * no more than 76 characters each. All line breaks or other
2519 * characters not found in Table 1 must be ignored by decoding
2520 * software. In base64 data, characters other than those in
2521 * Table 1, line breaks, and other white space probably
2522 * indicate a transmission error, about which a warning
2523 * message or even a message rejection might be appropriate
2524 * under some circumstances." */
2525 const xmlChar *cur = value;
2526 xmlChar *base;
2527 int total, i = 0, pad = 0;
2528
2529 if (cur == NULL)
2530 goto return1;
2531
2532 for (; *cur; ++cur) {
2533 int decc;
2534
2535 decc = _xmlSchemaBase64Decode(*cur);
2536 if (decc < 0) ;
2537 else if (decc < 64)
2538 i++;
2539 else
2540 break;
2541 }
2542 for (; *cur; ++cur) {
2543 int decc;
2544
2545 decc = _xmlSchemaBase64Decode(*cur);
2546 if (decc < 0) ;
2547 else if (decc < 64)
2548 goto return1;
2549 if (decc == 64)
2550 pad++;
2551 }
2552
2553 /* rfc2045.txt: "Special processing is performed if fewer than
2554 * 24 bits are available at the end of the data being encoded.
2555 * A full encoding quantum is always completed at the end of a
2556 * body. When fewer than 24 input bits are available in an
2557 * input group, zero bits are added (on the right) to form an
2558 * integral number of 6-bit groups. Padding at the end of the
2559 * data is performed using the "=" character. Since all
2560 * base64 input is an integral number of octets, only the
2561 * following cases can arise: (1) the final quantum of
2562 * encoding input is an integral multiple of 24 bits; here,
2563 * the final unit of encoded output will be an integral
2564 * multiple ofindent: Standard input:701: Warning:old style
2565 * assignment ambiguity in "=*". Assuming "= *" 4 characters
2566 * with no "=" padding, (2) the final
2567 * quantum of encoding input is exactly 8 bits; here, the
2568 * final unit of encoded output will be two characters
2569 * followed by two "=" padding characters, or (3) the final
2570 * quantum of encoding input is exactly 16 bits; here, the
2571 * final unit of encoded output will be three characters
2572 * followed by one "=" padding character." */
2573
2574 total = 3 * (i / 4);
2575 if (pad == 0) {
2576 if (i % 4 != 0)
2577 goto return1;
2578 } else if (pad == 1) {
2579 int decc;
2580
2581 if (i % 4 != 3)
2582 goto return1;
2583 for (decc = _xmlSchemaBase64Decode(*cur);
2584 (decc < 0) || (decc > 63);
2585 decc = _xmlSchemaBase64Decode(*cur))
2586 --cur;
2587 /* 16bits in 24bits means 2 pad bits: nnnnnn nnmmmm mmmm00*/
2588 /* 00111100 -> 0x3c */
2589 if (decc & ~0x3c)
2590 goto return1;
2591 total += 2;
2592 } else if (pad == 2) {
2593 int decc;
2594
2595 if (i % 4 != 2)
2596 goto return1;
2597 for (decc = _xmlSchemaBase64Decode(*cur);
2598 (decc < 0) || (decc > 63);
2599 decc = _xmlSchemaBase64Decode(*cur))
2600 --cur;
2601 /* 8bits in 12bits means 4 pad bits: nnnnnn nn0000 */
2602 /* 00110000 -> 0x30 */
2603 if (decc & ~0x30)
2604 goto return1;
2605 total += 1;
2606 } else
2607 goto return1;
2608
2609 if (val != NULL) {
2610 v = xmlSchemaNewValue(XML_SCHEMAS_BASE64BINARY);
2611 if (v == NULL)
2612 goto error;
2613 base =
2614 (xmlChar *) xmlMallocAtomic((i + pad + 1) *
2615 sizeof(xmlChar));
2616 if (base == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002617 xmlSchemaTypeErrMemory(node, "allocating base64 data");
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002618 xmlFree(v);
2619 goto return1;
2620 }
2621 v->value.base64.str = base;
2622 for (cur = value; *cur; ++cur)
2623 if (_xmlSchemaBase64Decode(*cur) >= 0) {
2624 *base = *cur;
2625 ++base;
2626 }
2627 *base = 0;
2628 v->value.base64.total = total;
2629 *val = v;
2630 }
2631 goto return0;
2632 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002633 case XML_SCHEMAS_INTEGER:
2634 case XML_SCHEMAS_PINTEGER:
2635 case XML_SCHEMAS_NPINTEGER:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002636 case XML_SCHEMAS_NINTEGER:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002637 case XML_SCHEMAS_NNINTEGER:{
2638 const xmlChar *cur = value;
2639 unsigned long lo, mi, hi;
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00002640 int sign = 0, total = 0;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002641
2642 if (cur == NULL)
2643 goto return1;
2644 if (*cur == '-') {
2645 sign = 1;
2646 cur++;
2647 } else if (*cur == '+')
2648 cur++;
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00002649 /* Skip leading zeroes. */
2650 while ((*cur == '0') && ((*(cur + 1)) != 0))
2651 cur++;
2652 if (*cur != '0') {
2653 total = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2654 if (total <= 0)
2655 goto return1;
2656 if (*cur != 0)
2657 goto return1;
2658 } else {
2659 /* Tiny speedup for "0" */
2660 total = 1;
2661 lo = 0;
2662 mi = 0;
2663 hi = 0;
2664 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002665 if (type->builtInType == XML_SCHEMAS_NPINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002666 if ((sign == 0) &&
2667 ((hi != 0) || (mi != 0) || (lo != 0)))
2668 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002669 } else if (type->builtInType == XML_SCHEMAS_PINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002670 if (sign == 1)
2671 goto return1;
2672 if ((hi == 0) && (mi == 0) && (lo == 0))
2673 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002674 } else if (type->builtInType == XML_SCHEMAS_NINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002675 if (sign == 0)
2676 goto return1;
2677 if ((hi == 0) && (mi == 0) && (lo == 0))
2678 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002679 } else if (type->builtInType == XML_SCHEMAS_NNINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002680 if ((sign == 1) &&
2681 ((hi != 0) || (mi != 0) || (lo != 0)))
2682 goto return1;
2683 }
2684 /*
2685 * We can store a value only if no overflow occured
2686 */
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00002687 if (val != NULL) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00002688 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002689 if (v != NULL) {
2690 v->value.decimal.lo = lo;
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00002691 v->value.decimal.mi = mi;
2692 v->value.decimal.hi = hi;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002693 v->value.decimal.sign = sign;
2694 v->value.decimal.frac = 0;
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00002695 v->value.decimal.total = total;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002696 *val = v;
2697 }
2698 }
2699 goto return0;
2700 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002701 case XML_SCHEMAS_LONG:
2702 case XML_SCHEMAS_BYTE:
2703 case XML_SCHEMAS_SHORT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002704 case XML_SCHEMAS_INT:{
2705 const xmlChar *cur = value;
2706 unsigned long lo, mi, hi;
2707 int total = 0;
2708 int sign = 0;
2709
2710 if (cur == NULL)
2711 goto return1;
2712 if (*cur == '-') {
2713 sign = 1;
2714 cur++;
2715 } else if (*cur == '+')
2716 cur++;
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00002717 /* Skip leading zeroes. */
2718 while ((*cur == '0') && ((*(cur + 1)) != 0))
2719 cur++;
2720 if (*cur != '0') {
2721 total = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2722 if (total <= 0)
2723 goto return1;
2724 if (*cur != 0)
2725 goto return1;
2726 } else {
2727 /* Tiny speedup for "0" */
2728 total = 1;
2729 lo = 0;
2730 mi = 0;
2731 hi = 0;
2732 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002733 if (type->builtInType == XML_SCHEMAS_LONG) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002734 if (hi >= 922) {
2735 if (hi > 922)
2736 goto return1;
2737 if (mi >= 33720368) {
2738 if (mi > 33720368)
2739 goto return1;
2740 if ((sign == 0) && (lo > 54775807))
2741 goto return1;
2742 if ((sign == 1) && (lo > 54775808))
2743 goto return1;
2744 }
2745 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002746 } else if (type->builtInType == XML_SCHEMAS_INT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002747 if (hi != 0)
2748 goto return1;
2749 if (mi >= 21) {
2750 if (mi > 21)
2751 goto return1;
2752 if ((sign == 0) && (lo > 47483647))
2753 goto return1;
2754 if ((sign == 1) && (lo > 47483648))
2755 goto return1;
2756 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002757 } else if (type->builtInType == XML_SCHEMAS_SHORT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002758 if ((mi != 0) || (hi != 0))
2759 goto return1;
2760 if ((sign == 1) && (lo > 32768))
2761 goto return1;
2762 if ((sign == 0) && (lo > 32767))
2763 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002764 } else if (type->builtInType == XML_SCHEMAS_BYTE) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002765 if ((mi != 0) || (hi != 0))
2766 goto return1;
2767 if ((sign == 1) && (lo > 128))
2768 goto return1;
2769 if ((sign == 0) && (lo > 127))
2770 goto return1;
2771 }
2772 if (val != NULL) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00002773 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002774 if (v != NULL) {
2775 v->value.decimal.lo = lo;
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00002776 v->value.decimal.mi = mi;
2777 v->value.decimal.hi = hi;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002778 v->value.decimal.sign = sign;
2779 v->value.decimal.frac = 0;
2780 v->value.decimal.total = total;
2781 *val = v;
2782 }
2783 }
2784 goto return0;
2785 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002786 case XML_SCHEMAS_UINT:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002787 case XML_SCHEMAS_ULONG:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002788 case XML_SCHEMAS_USHORT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002789 case XML_SCHEMAS_UBYTE:{
2790 const xmlChar *cur = value;
2791 unsigned long lo, mi, hi;
2792 int total = 0;
2793
2794 if (cur == NULL)
2795 goto return1;
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00002796 /* Note that "+" is not allowed. */
2797 /* Skip leading zeroes. */
2798 while ((*cur == '0') && ((*(cur + 1)) != 0))
2799 cur++;
2800 if (*cur != '0') {
2801 total = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2802 if (total <= 0)
2803 goto return1;
2804 if (*cur != 0)
2805 goto return1;
2806 } else {
2807 /* Tiny speedup for "0" */
2808 total = 1;
2809 lo = 0;
2810 mi = 0;
2811 hi = 0;
2812 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002813 if (type->builtInType == XML_SCHEMAS_ULONG) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002814 if (hi >= 1844) {
2815 if (hi > 1844)
2816 goto return1;
2817 if (mi >= 67440737) {
2818 if (mi > 67440737)
2819 goto return1;
2820 if (lo > 9551615)
2821 goto return1;
2822 }
2823 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002824 } else if (type->builtInType == XML_SCHEMAS_UINT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002825 if (hi != 0)
2826 goto return1;
2827 if (mi >= 42) {
2828 if (mi > 42)
2829 goto return1;
2830 if (lo > 94967295)
2831 goto return1;
2832 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002833 } else if (type->builtInType == XML_SCHEMAS_USHORT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002834 if ((mi != 0) || (hi != 0))
2835 goto return1;
2836 if (lo > 65535)
2837 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002838 } else if (type->builtInType == XML_SCHEMAS_UBYTE) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002839 if ((mi != 0) || (hi != 0))
2840 goto return1;
2841 if (lo > 255)
2842 goto return1;
2843 }
2844 if (val != NULL) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00002845 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002846 if (v != NULL) {
2847 v->value.decimal.lo = lo;
2848 v->value.decimal.mi = mi;
2849 v->value.decimal.hi = hi;
2850 v->value.decimal.sign = 0;
2851 v->value.decimal.frac = 0;
2852 v->value.decimal.total = total;
2853 *val = v;
2854 }
2855 }
2856 goto return0;
2857 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002858 }
2859
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002860 done:
2861 if (norm != NULL)
2862 xmlFree(norm);
2863 return (ret);
2864 return3:
2865 if (norm != NULL)
2866 xmlFree(norm);
2867 return (3);
2868 return1:
2869 if (norm != NULL)
2870 xmlFree(norm);
2871 return (1);
2872 return0:
2873 if (norm != NULL)
2874 xmlFree(norm);
2875 return (0);
2876 error:
2877 if (norm != NULL)
2878 xmlFree(norm);
2879 return (-1);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002880}
2881
2882/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002883 * xmlSchemaValPredefTypeNode:
Daniel Veillard4255d502002-04-16 15:50:10 +00002884 * @type: the predefined type
2885 * @value: the value to check
2886 * @val: the return computed value
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002887 * @node: the node containing the value
Daniel Veillard4255d502002-04-16 15:50:10 +00002888 *
2889 * Check that a value conforms to the lexical space of the predefined type.
2890 * if true a value is computed and returned in @val.
2891 *
2892 * Returns 0 if this validates, a positive error code number otherwise
2893 * and -1 in case of internal or API error.
2894 */
2895int
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002896xmlSchemaValPredefTypeNode(xmlSchemaTypePtr type, const xmlChar *value,
2897 xmlSchemaValPtr *val, xmlNodePtr node) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002898 return(xmlSchemaValAtomicType(type, value, val, node, 0));
Daniel Veillard4255d502002-04-16 15:50:10 +00002899}
2900
2901/**
Daniel Veillardc0826a72004-08-10 14:17:33 +00002902 * xmlSchemaValPredefTypeNodeNoNorm:
2903 * @type: the predefined type
2904 * @value: the value to check
2905 * @val: the return computed value
2906 * @node: the node containing the value
2907 *
2908 * Check that a value conforms to the lexical space of the predefined type.
2909 * if true a value is computed and returned in @val.
2910 * This one does apply any normalization to the value.
2911 *
2912 * Returns 0 if this validates, a positive error code number otherwise
2913 * and -1 in case of internal or API error.
2914 */
2915int
2916xmlSchemaValPredefTypeNodeNoNorm(xmlSchemaTypePtr type, const xmlChar *value,
2917 xmlSchemaValPtr *val, xmlNodePtr node) {
2918 return(xmlSchemaValAtomicType(type, value, val, node, 1));
2919}
2920
2921/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002922 * xmlSchemaValidatePredefinedType:
2923 * @type: the predefined type
2924 * @value: the value to check
2925 * @val: the return computed value
2926 *
2927 * Check that a value conforms to the lexical space of the predefined type.
2928 * if true a value is computed and returned in @val.
2929 *
2930 * Returns 0 if this validates, a positive error code number otherwise
2931 * and -1 in case of internal or API error.
2932 */
2933int
2934xmlSchemaValidatePredefinedType(xmlSchemaTypePtr type, const xmlChar *value,
2935 xmlSchemaValPtr *val) {
2936 return(xmlSchemaValPredefTypeNode(type, value, val, NULL));
2937}
2938
2939/**
Daniel Veillard4255d502002-04-16 15:50:10 +00002940 * xmlSchemaCompareDecimals:
2941 * @x: a first decimal value
2942 * @y: a second decimal value
2943 *
2944 * Compare 2 decimals
2945 *
2946 * Returns -1 if x < y, 0 if x == y, 1 if x > y and -2 in case of error
2947 */
2948static int
2949xmlSchemaCompareDecimals(xmlSchemaValPtr x, xmlSchemaValPtr y)
2950{
2951 xmlSchemaValPtr swp;
William M. Brack273670f2005-03-11 15:55:14 +00002952 int order = 1, integx, integy, dlen;
2953 unsigned long hi, mi, lo;
Daniel Veillard4255d502002-04-16 15:50:10 +00002954
William M. Brack273670f2005-03-11 15:55:14 +00002955 /*
2956 * First test: If x is -ve and not zero
2957 */
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002958 if ((x->value.decimal.sign) &&
2959 ((x->value.decimal.lo != 0) ||
2960 (x->value.decimal.mi != 0) ||
2961 (x->value.decimal.hi != 0))) {
William M. Brack273670f2005-03-11 15:55:14 +00002962 /*
2963 * Then if y is -ve and not zero reverse the compare
2964 */
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002965 if ((y->value.decimal.sign) &&
2966 ((y->value.decimal.lo != 0) ||
2967 (y->value.decimal.mi != 0) ||
2968 (y->value.decimal.hi != 0)))
Daniel Veillard80b19092003-03-28 13:29:53 +00002969 order = -1;
William M. Brack273670f2005-03-11 15:55:14 +00002970 /*
2971 * Otherwise (y >= 0) we have the answer
2972 */
Daniel Veillard80b19092003-03-28 13:29:53 +00002973 else
2974 return (-1);
William M. Brack273670f2005-03-11 15:55:14 +00002975 /*
2976 * If x is not -ve and y is -ve we have the answer
2977 */
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002978 } else if ((y->value.decimal.sign) &&
2979 ((y->value.decimal.lo != 0) ||
2980 (y->value.decimal.mi != 0) ||
2981 (y->value.decimal.hi != 0))) {
Daniel Veillard4255d502002-04-16 15:50:10 +00002982 return (1);
Daniel Veillard80b19092003-03-28 13:29:53 +00002983 }
William M. Brack273670f2005-03-11 15:55:14 +00002984 /*
2985 * If it's not simply determined by a difference in sign,
2986 * then we need to compare the actual values of the two nums.
2987 * To do this, we start by looking at the integral parts.
2988 * If the number of integral digits differ, then we have our
2989 * answer.
2990 */
2991 integx = x->value.decimal.total - x->value.decimal.frac;
2992 integy = y->value.decimal.total - y->value.decimal.frac;
2993 if (integx > integy)
2994 return order;
2995 else if (integy > integx)
2996 return -order;
2997 /*
2998 * If the number of integral digits is the same for both numbers,
2999 * then things get a little more complicated. We need to "normalize"
3000 * the numbers in order to properly compare them. To do this, we
3001 * look at the total length of each number (length => number of
3002 * significant digits), and divide the "shorter" by 10 (decreasing
3003 * the length) until they are of equal length.
3004 */
3005 dlen = x->value.decimal.total - y->value.decimal.total;
3006 if (dlen < 0) { /* y has more digits than x */
3007 swp = x;
3008 hi = y->value.decimal.hi;
3009 mi = y->value.decimal.mi;
3010 lo = y->value.decimal.lo;
3011 dlen = -dlen;
3012 order = -order;
3013 } else { /* x has more digits than y */
3014 swp = y;
3015 hi = x->value.decimal.hi;
3016 mi = x->value.decimal.mi;
3017 lo = x->value.decimal.lo;
Daniel Veillard4255d502002-04-16 15:50:10 +00003018 }
William M. Brack273670f2005-03-11 15:55:14 +00003019 while (dlen > 8) { /* in effect, right shift by 10**8 */
3020 lo = mi;
3021 mi = hi;
3022 hi = 0;
3023 dlen -= 8;
Daniel Veillard4255d502002-04-16 15:50:10 +00003024 }
William M. Brack273670f2005-03-11 15:55:14 +00003025 while (dlen > 0) {
3026 unsigned long rem1, rem2;
3027 rem1 = (hi % 10) * 100000000L;
3028 hi = hi / 10;
3029 rem2 = (mi % 10) * 100000000L;
3030 mi = (mi + rem1) / 10;
3031 lo = (lo + rem2) / 10;
3032 dlen--;
3033 }
3034 if (hi > swp->value.decimal.hi) {
3035 return order;
3036 } else if (hi == swp->value.decimal.hi) {
3037 if (mi > swp->value.decimal.mi) {
3038 return order;
3039 } else if (mi == swp->value.decimal.mi) {
3040 if (lo > swp->value.decimal.lo) {
3041 return order;
3042 } else if (lo == swp->value.decimal.lo) {
3043 if (x->value.decimal.total == y->value.decimal.total) {
3044 return 0;
3045 } else {
3046 return order;
3047 }
3048 }
3049 }
3050 }
3051 return -order;
Daniel Veillard4255d502002-04-16 15:50:10 +00003052}
3053
3054/**
Daniel Veillard070803b2002-05-03 07:29:38 +00003055 * xmlSchemaCompareDurations:
3056 * @x: a first duration value
3057 * @y: a second duration value
3058 *
3059 * Compare 2 durations
3060 *
3061 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3062 * case of error
3063 */
3064static int
3065xmlSchemaCompareDurations(xmlSchemaValPtr x, xmlSchemaValPtr y)
3066{
3067 long carry, mon, day;
3068 double sec;
Daniel Veillard80b19092003-03-28 13:29:53 +00003069 int invert = 1;
3070 long xmon, xday, myear, minday, maxday;
Daniel Veillard070803b2002-05-03 07:29:38 +00003071 static const long dayRange [2][12] = {
3072 { 0, 28, 59, 89, 120, 150, 181, 212, 242, 273, 303, 334, },
3073 { 0, 31, 62, 92, 123, 153, 184, 215, 245, 276, 306, 337} };
3074
3075 if ((x == NULL) || (y == NULL))
Daniel Veillard5a872412002-05-22 06:40:27 +00003076 return -2;
Daniel Veillard070803b2002-05-03 07:29:38 +00003077
3078 /* months */
3079 mon = x->value.dur.mon - y->value.dur.mon;
3080
3081 /* seconds */
3082 sec = x->value.dur.sec - y->value.dur.sec;
3083 carry = (long)sec / SECS_PER_DAY;
3084 sec -= (double)(carry * SECS_PER_DAY);
3085
3086 /* days */
3087 day = x->value.dur.day - y->value.dur.day + carry;
3088
3089 /* easy test */
3090 if (mon == 0) {
3091 if (day == 0)
3092 if (sec == 0.0)
3093 return 0;
3094 else if (sec < 0.0)
3095 return -1;
3096 else
3097 return 1;
3098 else if (day < 0)
3099 return -1;
3100 else
3101 return 1;
3102 }
3103
3104 if (mon > 0) {
3105 if ((day >= 0) && (sec >= 0.0))
3106 return 1;
3107 else {
3108 xmon = mon;
3109 xday = -day;
3110 }
3111 } else if ((day <= 0) && (sec <= 0.0)) {
3112 return -1;
3113 } else {
Daniel Veillard80b19092003-03-28 13:29:53 +00003114 invert = -1;
Daniel Veillard070803b2002-05-03 07:29:38 +00003115 xmon = -mon;
3116 xday = day;
3117 }
3118
3119 myear = xmon / 12;
Daniel Veillard80b19092003-03-28 13:29:53 +00003120 if (myear == 0) {
3121 minday = 0;
3122 maxday = 0;
3123 } else {
3124 maxday = 366 * ((myear + 3) / 4) +
3125 365 * ((myear - 1) % 4);
3126 minday = maxday - 1;
3127 }
3128
Daniel Veillard070803b2002-05-03 07:29:38 +00003129 xmon = xmon % 12;
3130 minday += dayRange[0][xmon];
3131 maxday += dayRange[1][xmon];
3132
Daniel Veillard80b19092003-03-28 13:29:53 +00003133 if ((maxday == minday) && (maxday == xday))
3134 return(0); /* can this really happen ? */
Daniel Veillard070803b2002-05-03 07:29:38 +00003135 if (maxday < xday)
Daniel Veillard80b19092003-03-28 13:29:53 +00003136 return(-invert);
3137 if (minday > xday)
3138 return(invert);
Daniel Veillard070803b2002-05-03 07:29:38 +00003139
3140 /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00003141 return 2;
3142}
3143
3144/*
3145 * macros for adding date/times and durations
3146 */
3147#define FQUOTIENT(a,b) (floor(((double)a/(double)b)))
3148#define MODULO(a,b) (a - FQUOTIENT(a,b) * b)
3149#define FQUOTIENT_RANGE(a,low,high) (FQUOTIENT((a-low),(high-low)))
3150#define MODULO_RANGE(a,low,high) ((MODULO((a-low),(high-low)))+low)
3151
3152/**
Daniel Veillard669adfc2004-05-29 20:12:46 +00003153 * xmlSchemaDupVal:
3154 * @v: the #xmlSchemaValPtr value to duplicate
3155 *
3156 * Makes a copy of @v. The calling program is responsible for freeing
3157 * the returned value.
3158 *
3159 * returns a pointer to a duplicated #xmlSchemaValPtr or NULL if error.
3160 */
3161static xmlSchemaValPtr
3162xmlSchemaDupVal (xmlSchemaValPtr v)
3163{
3164 xmlSchemaValPtr ret = xmlSchemaNewValue(v->type);
3165 if (ret == NULL)
3166 return NULL;
3167
3168 memcpy(ret, v, sizeof(xmlSchemaVal));
3169 return ret;
3170}
3171
3172/**
Kasimier T. Buchcik285ebab2005-03-04 18:04:59 +00003173 * xmlSchemaCopyValue:
3174 * @val: the precomputed value to be copied
3175 *
3176 * Copies the precomputed value. This duplicates any string within.
3177 *
3178 * Returns the copy or NULL if a copy for a data-type is not implemented.
3179 */
3180xmlSchemaValPtr
3181xmlSchemaCopyValue(xmlSchemaValPtr val)
3182{
3183 xmlSchemaValPtr ret;
3184
3185 if (val == NULL)
3186 return (NULL);
3187 /*
3188 * Copy the string values.
3189 */
3190 switch (val->type) {
3191 case XML_SCHEMAS_IDREFS:
3192 case XML_SCHEMAS_ENTITIES:
3193 case XML_SCHEMAS_NMTOKENS:
3194 case XML_SCHEMAS_ANYTYPE:
3195 case XML_SCHEMAS_ANYSIMPLETYPE:
3196 return (NULL);
3197 case XML_SCHEMAS_STRING:
3198 case XML_SCHEMAS_NORMSTRING:
3199 case XML_SCHEMAS_TOKEN:
3200 case XML_SCHEMAS_LANGUAGE:
3201 case XML_SCHEMAS_NAME:
3202 case XML_SCHEMAS_NCNAME:
3203 case XML_SCHEMAS_ID:
3204 case XML_SCHEMAS_IDREF:
3205 case XML_SCHEMAS_ENTITY:
3206 case XML_SCHEMAS_NMTOKEN:
Kasimier T. Buchcik2ee855d2005-03-07 11:14:14 +00003207 case XML_SCHEMAS_ANYURI:
Kasimier T. Buchcik285ebab2005-03-04 18:04:59 +00003208 ret = xmlSchemaDupVal(val);
3209 if (val->value.str != NULL)
3210 ret->value.str = xmlStrdup(BAD_CAST val->value.str);
3211 return (ret);
Kasimier T. Buchcik2ee855d2005-03-07 11:14:14 +00003212 case XML_SCHEMAS_QNAME:
Kasimier T. Buchcik285ebab2005-03-04 18:04:59 +00003213 case XML_SCHEMAS_NOTATION:
3214 ret = xmlSchemaDupVal(val);
3215 if (val->value.qname.name != NULL)
3216 ret->value.qname.name =
3217 xmlStrdup(BAD_CAST val->value.qname.name);
3218 if (val->value.qname.uri != NULL)
3219 ret->value.qname.uri =
3220 xmlStrdup(BAD_CAST val->value.qname.uri);
3221 return (ret);
3222 case XML_SCHEMAS_HEXBINARY:
3223 ret = xmlSchemaDupVal(val);
3224 if (val->value.hex.str != NULL)
3225 ret->value.hex.str = xmlStrdup(BAD_CAST val->value.hex.str);
3226 return (ret);
3227 case XML_SCHEMAS_BASE64BINARY:
3228 ret = xmlSchemaDupVal(val);
3229 if (val->value.base64.str != NULL)
3230 ret->value.base64.str =
3231 xmlStrdup(BAD_CAST val->value.base64.str);
3232 return (ret);
3233 default:
3234 return (xmlSchemaDupVal(val));
3235 }
3236 return (NULL);
3237}
3238
3239/**
Daniel Veillard5a872412002-05-22 06:40:27 +00003240 * _xmlSchemaDateAdd:
3241 * @dt: an #xmlSchemaValPtr
3242 * @dur: an #xmlSchemaValPtr of type #XS_DURATION
3243 *
3244 * Compute a new date/time from @dt and @dur. This function assumes @dt
3245 * is either #XML_SCHEMAS_DATETIME, #XML_SCHEMAS_DATE, #XML_SCHEMAS_GYEARMONTH,
Daniel Veillard669adfc2004-05-29 20:12:46 +00003246 * or #XML_SCHEMAS_GYEAR. The returned #xmlSchemaVal is the same type as
3247 * @dt. The calling program is responsible for freeing the returned value.
Daniel Veillard5a872412002-05-22 06:40:27 +00003248 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00003249 * Returns a pointer to a new #xmlSchemaVal or NULL if error.
Daniel Veillard5a872412002-05-22 06:40:27 +00003250 */
3251static xmlSchemaValPtr
3252_xmlSchemaDateAdd (xmlSchemaValPtr dt, xmlSchemaValPtr dur)
3253{
Daniel Veillard669adfc2004-05-29 20:12:46 +00003254 xmlSchemaValPtr ret, tmp;
Daniel Veillard5a872412002-05-22 06:40:27 +00003255 long carry, tempdays, temp;
3256 xmlSchemaValDatePtr r, d;
3257 xmlSchemaValDurationPtr u;
3258
3259 if ((dt == NULL) || (dur == NULL))
3260 return NULL;
3261
3262 ret = xmlSchemaNewValue(dt->type);
3263 if (ret == NULL)
3264 return NULL;
3265
Daniel Veillard669adfc2004-05-29 20:12:46 +00003266 /* make a copy so we don't alter the original value */
3267 tmp = xmlSchemaDupVal(dt);
3268 if (tmp == NULL) {
3269 xmlSchemaFreeValue(ret);
3270 return NULL;
3271 }
3272
Daniel Veillard5a872412002-05-22 06:40:27 +00003273 r = &(ret->value.date);
Daniel Veillard669adfc2004-05-29 20:12:46 +00003274 d = &(tmp->value.date);
Daniel Veillard5a872412002-05-22 06:40:27 +00003275 u = &(dur->value.dur);
3276
3277 /* normalization */
3278 if (d->mon == 0)
3279 d->mon = 1;
3280
3281 /* normalize for time zone offset */
3282 u->sec -= (d->tzo * 60);
3283 d->tzo = 0;
3284
3285 /* normalization */
3286 if (d->day == 0)
3287 d->day = 1;
3288
3289 /* month */
3290 carry = d->mon + u->mon;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003291 r->mon = (unsigned int) MODULO_RANGE(carry, 1, 13);
3292 carry = (long) FQUOTIENT_RANGE(carry, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00003293
3294 /* year (may be modified later) */
3295 r->year = d->year + carry;
3296 if (r->year == 0) {
3297 if (d->year > 0)
3298 r->year--;
3299 else
3300 r->year++;
3301 }
3302
3303 /* time zone */
3304 r->tzo = d->tzo;
3305 r->tz_flag = d->tz_flag;
3306
3307 /* seconds */
3308 r->sec = d->sec + u->sec;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003309 carry = (long) FQUOTIENT((long)r->sec, 60);
Daniel Veillard5a872412002-05-22 06:40:27 +00003310 if (r->sec != 0.0) {
3311 r->sec = MODULO(r->sec, 60.0);
3312 }
3313
3314 /* minute */
3315 carry += d->min;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003316 r->min = (unsigned int) MODULO(carry, 60);
3317 carry = (long) FQUOTIENT(carry, 60);
Daniel Veillard5a872412002-05-22 06:40:27 +00003318
3319 /* hours */
3320 carry += d->hour;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003321 r->hour = (unsigned int) MODULO(carry, 24);
3322 carry = (long)FQUOTIENT(carry, 24);
Daniel Veillard5a872412002-05-22 06:40:27 +00003323
3324 /*
3325 * days
3326 * Note we use tempdays because the temporary values may need more
3327 * than 5 bits
3328 */
3329 if ((VALID_YEAR(r->year)) && (VALID_MONTH(r->mon)) &&
3330 (d->day > MAX_DAYINMONTH(r->year, r->mon)))
3331 tempdays = MAX_DAYINMONTH(r->year, r->mon);
3332 else if (d->day < 1)
3333 tempdays = 1;
3334 else
3335 tempdays = d->day;
3336
3337 tempdays += u->day + carry;
3338
3339 while (1) {
3340 if (tempdays < 1) {
Daniel Veillardebe25d42004-03-25 09:35:49 +00003341 long tmon = (long) MODULO_RANGE(r->mon-1, 1, 13);
3342 long tyr = r->year + (long)FQUOTIENT_RANGE(r->mon-1, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00003343 if (tyr == 0)
3344 tyr--;
3345 tempdays += MAX_DAYINMONTH(tyr, tmon);
3346 carry = -1;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003347 } else if (tempdays > (long) MAX_DAYINMONTH(r->year, r->mon)) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003348 tempdays = tempdays - MAX_DAYINMONTH(r->year, r->mon);
3349 carry = 1;
3350 } else
3351 break;
3352
3353 temp = r->mon + carry;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003354 r->mon = (unsigned int) MODULO_RANGE(temp, 1, 13);
3355 r->year = r->year + (unsigned int) FQUOTIENT_RANGE(temp, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00003356 if (r->year == 0) {
3357 if (temp < 1)
3358 r->year--;
3359 else
3360 r->year++;
3361 }
3362 }
3363
3364 r->day = tempdays;
3365
3366 /*
3367 * adjust the date/time type to the date values
3368 */
3369 if (ret->type != XML_SCHEMAS_DATETIME) {
3370 if ((r->hour) || (r->min) || (r->sec))
3371 ret->type = XML_SCHEMAS_DATETIME;
3372 else if (ret->type != XML_SCHEMAS_DATE) {
3373 if ((r->mon != 1) && (r->day != 1))
3374 ret->type = XML_SCHEMAS_DATE;
3375 else if ((ret->type != XML_SCHEMAS_GYEARMONTH) && (r->mon != 1))
3376 ret->type = XML_SCHEMAS_GYEARMONTH;
3377 }
3378 }
3379
Daniel Veillard669adfc2004-05-29 20:12:46 +00003380 xmlSchemaFreeValue(tmp);
Daniel Veillard5a872412002-05-22 06:40:27 +00003381
Daniel Veillard5a872412002-05-22 06:40:27 +00003382 return ret;
3383}
3384
3385/**
3386 * xmlSchemaDateNormalize:
Daniel Veillard669adfc2004-05-29 20:12:46 +00003387 * @dt: an #xmlSchemaValPtr of a date/time type value.
3388 * @offset: number of seconds to adjust @dt by.
Daniel Veillard5a872412002-05-22 06:40:27 +00003389 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00003390 * Normalize @dt to GMT time. The @offset parameter is subtracted from
3391 * the return value is a time-zone offset is present on @dt.
Daniel Veillard5a872412002-05-22 06:40:27 +00003392 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00003393 * Returns a normalized copy of @dt or NULL if error.
Daniel Veillard5a872412002-05-22 06:40:27 +00003394 */
3395static xmlSchemaValPtr
3396xmlSchemaDateNormalize (xmlSchemaValPtr dt, double offset)
3397{
3398 xmlSchemaValPtr dur, ret;
3399
3400 if (dt == NULL)
3401 return NULL;
3402
3403 if (((dt->type != XML_SCHEMAS_TIME) &&
3404 (dt->type != XML_SCHEMAS_DATETIME)) || (dt->value.date.tzo == 0))
3405 return xmlSchemaDupVal(dt);
3406
3407 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
3408 if (dur == NULL)
3409 return NULL;
3410
3411 dur->value.date.sec -= offset;
3412
3413 ret = _xmlSchemaDateAdd(dt, dur);
3414 if (ret == NULL)
3415 return NULL;
3416
3417 xmlSchemaFreeValue(dur);
3418
3419 /* ret->value.date.tzo = 0; */
3420 return ret;
3421}
3422
3423/**
3424 * _xmlSchemaDateCastYMToDays:
3425 * @dt: an #xmlSchemaValPtr
3426 *
3427 * Convert mon and year of @dt to total number of days. Take the
3428 * number of years since (or before) 1 AD and add the number of leap
3429 * years. This is a function because negative
3430 * years must be handled a little differently and there is no zero year.
3431 *
3432 * Returns number of days.
3433 */
3434static long
3435_xmlSchemaDateCastYMToDays (const xmlSchemaValPtr dt)
3436{
3437 long ret;
Daniel Veillard49e89632004-09-23 16:24:36 +00003438 int mon;
Daniel Veillard5a872412002-05-22 06:40:27 +00003439
Daniel Veillard49e89632004-09-23 16:24:36 +00003440 mon = dt->value.date.mon;
3441 if (mon <= 0) mon = 1; /* normalization */
3442
3443 if (dt->value.date.year <= 0)
Daniel Veillard5a872412002-05-22 06:40:27 +00003444 ret = (dt->value.date.year * 365) +
3445 (((dt->value.date.year+1)/4)-((dt->value.date.year+1)/100)+
3446 ((dt->value.date.year+1)/400)) +
Daniel Veillard49e89632004-09-23 16:24:36 +00003447 DAY_IN_YEAR(0, mon, dt->value.date.year);
Daniel Veillard5a872412002-05-22 06:40:27 +00003448 else
3449 ret = ((dt->value.date.year-1) * 365) +
3450 (((dt->value.date.year-1)/4)-((dt->value.date.year-1)/100)+
3451 ((dt->value.date.year-1)/400)) +
Daniel Veillard49e89632004-09-23 16:24:36 +00003452 DAY_IN_YEAR(0, mon, dt->value.date.year);
Daniel Veillard5a872412002-05-22 06:40:27 +00003453
3454 return ret;
3455}
3456
3457/**
3458 * TIME_TO_NUMBER:
3459 * @dt: an #xmlSchemaValPtr
3460 *
3461 * Calculates the number of seconds in the time portion of @dt.
3462 *
3463 * Returns seconds.
3464 */
3465#define TIME_TO_NUMBER(dt) \
3466 ((double)((dt->value.date.hour * SECS_PER_HOUR) + \
Daniel Veillardb3721c22003-03-31 11:22:25 +00003467 (dt->value.date.min * SECS_PER_MIN) + \
3468 (dt->value.date.tzo * SECS_PER_MIN)) + \
3469 dt->value.date.sec)
Daniel Veillard5a872412002-05-22 06:40:27 +00003470
3471/**
3472 * xmlSchemaCompareDates:
3473 * @x: a first date/time value
3474 * @y: a second date/time value
3475 *
3476 * Compare 2 date/times
3477 *
3478 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3479 * case of error
3480 */
3481static int
3482xmlSchemaCompareDates (xmlSchemaValPtr x, xmlSchemaValPtr y)
3483{
3484 unsigned char xmask, ymask, xor_mask, and_mask;
3485 xmlSchemaValPtr p1, p2, q1, q2;
3486 long p1d, p2d, q1d, q2d;
3487
3488 if ((x == NULL) || (y == NULL))
3489 return -2;
3490
3491 if (x->value.date.tz_flag) {
3492
3493 if (!y->value.date.tz_flag) {
3494 p1 = xmlSchemaDateNormalize(x, 0);
3495 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3496 /* normalize y + 14:00 */
3497 q1 = xmlSchemaDateNormalize(y, (14 * SECS_PER_HOUR));
3498
3499 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003500 if (p1d < q1d) {
3501 xmlSchemaFreeValue(p1);
3502 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003503 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003504 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003505 double sec;
3506
3507 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00003508 if (sec < 0.0) {
3509 xmlSchemaFreeValue(p1);
3510 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003511 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003512 } else {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003513 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003514 /* normalize y - 14:00 */
3515 q2 = xmlSchemaDateNormalize(y, -(14 * SECS_PER_HOUR));
3516 q2d = _xmlSchemaDateCastYMToDays(q2) + q2->value.date.day;
3517 if (p1d > q2d)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003518 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003519 else if (p1d == q2d) {
3520 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q2);
3521 if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003522 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003523 else
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003524 ret = 2; /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00003525 }
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003526 xmlSchemaFreeValue(p1);
3527 xmlSchemaFreeValue(q1);
3528 xmlSchemaFreeValue(q2);
3529 if (ret != 0)
3530 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003531 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00003532 } else {
3533 xmlSchemaFreeValue(p1);
3534 xmlSchemaFreeValue(q1);
3535 }
Daniel Veillard5a872412002-05-22 06:40:27 +00003536 }
3537 } else if (y->value.date.tz_flag) {
3538 q1 = xmlSchemaDateNormalize(y, 0);
3539 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
3540
3541 /* normalize x - 14:00 */
3542 p1 = xmlSchemaDateNormalize(x, -(14 * SECS_PER_HOUR));
3543 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3544
Daniel Veillardfdc91562002-07-01 21:52:03 +00003545 if (p1d < q1d) {
3546 xmlSchemaFreeValue(p1);
3547 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003548 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003549 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003550 double sec;
3551
3552 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00003553 if (sec < 0.0) {
3554 xmlSchemaFreeValue(p1);
3555 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003556 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003557 } else {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003558 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003559 /* normalize x + 14:00 */
3560 p2 = xmlSchemaDateNormalize(x, (14 * SECS_PER_HOUR));
3561 p2d = _xmlSchemaDateCastYMToDays(p2) + p2->value.date.day;
3562
Daniel Veillard6560a422003-03-27 21:25:38 +00003563 if (p2d > q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003564 ret = 1;
Daniel Veillard6560a422003-03-27 21:25:38 +00003565 } else if (p2d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003566 sec = TIME_TO_NUMBER(p2) - TIME_TO_NUMBER(q1);
3567 if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003568 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003569 else
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003570 ret = 2; /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00003571 }
Daniel Veillard6560a422003-03-27 21:25:38 +00003572 xmlSchemaFreeValue(p1);
3573 xmlSchemaFreeValue(q1);
3574 xmlSchemaFreeValue(p2);
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003575 if (ret != 0)
3576 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003577 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00003578 } else {
3579 xmlSchemaFreeValue(p1);
3580 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003581 }
3582 }
3583
3584 /*
3585 * if the same type then calculate the difference
3586 */
3587 if (x->type == y->type) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003588 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003589 q1 = xmlSchemaDateNormalize(y, 0);
3590 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
3591
3592 p1 = xmlSchemaDateNormalize(x, 0);
3593 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3594
Daniel Veillardfdc91562002-07-01 21:52:03 +00003595 if (p1d < q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003596 ret = -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003597 } else if (p1d > q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003598 ret = 1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003599 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00003600 double sec;
3601
3602 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
3603 if (sec < 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003604 ret = -1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003605 else if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003606 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003607
3608 }
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003609 xmlSchemaFreeValue(p1);
3610 xmlSchemaFreeValue(q1);
3611 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003612 }
3613
3614 switch (x->type) {
3615 case XML_SCHEMAS_DATETIME:
3616 xmask = 0xf;
3617 break;
3618 case XML_SCHEMAS_DATE:
3619 xmask = 0x7;
3620 break;
3621 case XML_SCHEMAS_GYEAR:
3622 xmask = 0x1;
3623 break;
3624 case XML_SCHEMAS_GMONTH:
3625 xmask = 0x2;
3626 break;
3627 case XML_SCHEMAS_GDAY:
3628 xmask = 0x3;
3629 break;
3630 case XML_SCHEMAS_GYEARMONTH:
3631 xmask = 0x3;
3632 break;
3633 case XML_SCHEMAS_GMONTHDAY:
3634 xmask = 0x6;
3635 break;
3636 case XML_SCHEMAS_TIME:
3637 xmask = 0x8;
3638 break;
3639 default:
3640 xmask = 0;
3641 break;
3642 }
3643
3644 switch (y->type) {
3645 case XML_SCHEMAS_DATETIME:
3646 ymask = 0xf;
3647 break;
3648 case XML_SCHEMAS_DATE:
3649 ymask = 0x7;
3650 break;
3651 case XML_SCHEMAS_GYEAR:
3652 ymask = 0x1;
3653 break;
3654 case XML_SCHEMAS_GMONTH:
3655 ymask = 0x2;
3656 break;
3657 case XML_SCHEMAS_GDAY:
3658 ymask = 0x3;
3659 break;
3660 case XML_SCHEMAS_GYEARMONTH:
3661 ymask = 0x3;
3662 break;
3663 case XML_SCHEMAS_GMONTHDAY:
3664 ymask = 0x6;
3665 break;
3666 case XML_SCHEMAS_TIME:
3667 ymask = 0x8;
3668 break;
3669 default:
3670 ymask = 0;
3671 break;
3672 }
3673
3674 xor_mask = xmask ^ ymask; /* mark type differences */
3675 and_mask = xmask & ymask; /* mark field specification */
3676
3677 /* year */
3678 if (xor_mask & 1)
3679 return 2; /* indeterminate */
3680 else if (and_mask & 1) {
3681 if (x->value.date.year < y->value.date.year)
3682 return -1;
3683 else if (x->value.date.year > y->value.date.year)
3684 return 1;
3685 }
3686
3687 /* month */
3688 if (xor_mask & 2)
3689 return 2; /* indeterminate */
3690 else if (and_mask & 2) {
3691 if (x->value.date.mon < y->value.date.mon)
3692 return -1;
3693 else if (x->value.date.mon > y->value.date.mon)
3694 return 1;
3695 }
3696
3697 /* day */
3698 if (xor_mask & 4)
3699 return 2; /* indeterminate */
3700 else if (and_mask & 4) {
3701 if (x->value.date.day < y->value.date.day)
3702 return -1;
3703 else if (x->value.date.day > y->value.date.day)
3704 return 1;
3705 }
3706
3707 /* time */
3708 if (xor_mask & 8)
3709 return 2; /* indeterminate */
3710 else if (and_mask & 8) {
3711 if (x->value.date.hour < y->value.date.hour)
3712 return -1;
3713 else if (x->value.date.hour > y->value.date.hour)
3714 return 1;
3715 else if (x->value.date.min < y->value.date.min)
3716 return -1;
3717 else if (x->value.date.min > y->value.date.min)
3718 return 1;
3719 else if (x->value.date.sec < y->value.date.sec)
3720 return -1;
3721 else if (x->value.date.sec > y->value.date.sec)
3722 return 1;
3723 }
3724
Daniel Veillard070803b2002-05-03 07:29:38 +00003725 return 0;
3726}
3727
3728/**
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003729 * xmlSchemaComparePreserveReplaceStrings:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003730 * @xv: a first string value
3731 * @yv: a second string value
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003732 * @invert: inverts the result if x < y or x > y.
3733 *
3734 * Compare 2 string for their normalized values.
3735 * @x is a string with whitespace of "preserve", @y is
3736 * a string with a whitespace of "replace". I.e. @x could
3737 * be an "xsd:string" and @y an "xsd:normalizedString".
3738 *
3739 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
3740 * case of error
3741 */
3742static int
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003743xmlSchemaComparePreserveReplaceStrings(const xmlChar *xv,
3744 const xmlChar *yv,
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003745 int invert)
3746{
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003747 int tmp;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003748
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003749 while ((*xv != 0) && (*yv != 0)) {
3750 if (IS_WSP_REPLACE_CH(*yv)) {
3751 if (! IS_WSP_SPACE_CH(*xv)) {
3752 if ((*xv - 0x20) < 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003753 if (invert)
3754 return(1);
3755 else
3756 return(-1);
3757 } else {
3758 if (invert)
3759 return(-1);
3760 else
3761 return(1);
3762 }
3763 }
3764 } else {
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003765 tmp = *xv - *yv;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003766 if (tmp < 0) {
3767 if (invert)
3768 return(1);
3769 else
3770 return(-1);
3771 }
3772 if (tmp > 0) {
3773 if (invert)
3774 return(-1);
3775 else
3776 return(1);
3777 }
3778 }
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003779 xv++;
3780 yv++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003781 }
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003782 if (*xv != 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003783 if (invert)
3784 return(-1);
3785 else
3786 return(1);
3787 }
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003788 if (*yv != 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003789 if (invert)
3790 return(1);
3791 else
3792 return(-1);
3793 }
3794 return(0);
3795}
3796
3797/**
3798 * xmlSchemaComparePreserveCollapseStrings:
3799 * @x: a first string value
3800 * @y: a second string value
3801 *
3802 * Compare 2 string for their normalized values.
3803 * @x is a string with whitespace of "preserve", @y is
3804 * a string with a whitespace of "collapse". I.e. @x could
3805 * be an "xsd:string" and @y an "xsd:normalizedString".
3806 *
3807 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
3808 * case of error
3809 */
3810static int
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003811xmlSchemaComparePreserveCollapseStrings(const xmlChar *xv,
3812 const xmlChar *yv,
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003813 int invert)
3814{
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003815 int tmp;
3816
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003817 /*
3818 * Skip leading blank chars of the collapsed string.
3819 */
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003820 while (IS_WSP_SPACE_CH(*yv) || IS_WSP_REPLACE_CH(*yv))
3821 yv++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003822
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003823 while ((*xv != 0) && (*yv != 0)) {
3824 if (IS_WSP_SPACE_CH(*yv) || IS_WSP_REPLACE_CH(*yv)) {
3825 if (! IS_WSP_SPACE_CH(*xv)) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003826 /*
3827 * The utf2 character would have been replaced to 0x20.
3828 */
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003829 if ((*xv - 0x20) < 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003830 if (invert)
3831 return(1);
3832 else
3833 return(-1);
3834 } else {
3835 if (invert)
3836 return(-1);
3837 else
3838 return(1);
3839 }
3840 }
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003841 xv++;
3842 yv++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003843 /*
3844 * Skip contiguous blank chars of the collapsed string.
3845 */
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003846 while (IS_WSP_SPACE_CH(*yv) || IS_WSP_REPLACE_CH(*yv))
3847 yv++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003848 } else {
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003849 tmp = *xv++ - *yv++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003850 if (tmp < 0) {
3851 if (invert)
3852 return(1);
3853 else
3854 return(-1);
3855 }
3856 if (tmp > 0) {
3857 if (invert)
3858 return(-1);
3859 else
3860 return(1);
3861 }
3862 }
3863 }
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003864 if (*xv != 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003865 if (invert)
3866 return(-1);
3867 else
3868 return(1);
3869 }
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003870 if (*yv != 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003871 /*
3872 * Skip trailing blank chars of the collapsed string.
3873 */
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003874 while (IS_WSP_SPACE_CH(*yv) || IS_WSP_REPLACE_CH(*yv))
3875 yv++;
3876 if (*yv != 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003877 if (invert)
3878 return(1);
3879 else
3880 return(-1);
3881 }
3882 }
3883 return(0);
3884}
3885
3886/**
3887 * xmlSchemaComparePreserveCollapseStrings:
3888 * @x: a first string value
3889 * @y: a second string value
3890 *
3891 * Compare 2 string for their normalized values.
3892 * @x is a string with whitespace of "preserve", @y is
3893 * a string with a whitespace of "collapse". I.e. @x could
3894 * be an "xsd:string" and @y an "xsd:normalizedString".
3895 *
3896 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
3897 * case of error
3898 */
3899static int
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003900xmlSchemaCompareReplaceCollapseStrings(const xmlChar *xv,
3901 const xmlChar *yv,
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003902 int invert)
3903{
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003904 int tmp;
3905
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003906 /*
3907 * Skip leading blank chars of the collapsed string.
3908 */
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003909 while (IS_WSP_SPACE_CH(*yv) || IS_WSP_REPLACE_CH(*yv))
3910 yv++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003911
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003912 while ((*xv != 0) && (*yv != 0)) {
3913 if (IS_WSP_SPACE_CH(*yv) || IS_WSP_REPLACE_CH(*yv)) {
3914 if (! (IS_WSP_SPACE_CH(*xv) || IS_WSP_REPLACE_CH(*xv))) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003915 /*
3916 * The utf2 character would have been replaced to 0x20.
3917 */
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003918 if ((*xv - 0x20) < 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003919 if (invert)
3920 return(1);
3921 else
3922 return(-1);
3923 } else {
3924 if (invert)
3925 return(-1);
3926 else
3927 return(1);
3928 }
3929 }
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003930 xv++;
3931 yv++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003932 /*
3933 * Skip contiguous blank chars of the collapsed string.
3934 */
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003935 while (IS_WSP_SPACE_CH(*yv) || IS_WSP_REPLACE_CH(*yv))
3936 yv++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003937 } else {
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003938 if (IS_WSP_SPACE_CH(*xv) || IS_WSP_REPLACE_CH(*xv)) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003939 /*
3940 * The utf1 character would have been replaced to 0x20.
3941 */
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003942 if ((0x20 - *yv) < 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003943 if (invert)
3944 return(1);
3945 else
3946 return(-1);
3947 } else {
3948 if (invert)
3949 return(-1);
3950 else
3951 return(1);
3952 }
3953 }
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003954 tmp = *xv++ - *yv++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003955 if (tmp < 0)
3956 return(-1);
3957 if (tmp > 0)
3958 return(1);
3959 }
3960 }
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003961 if (*xv != 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003962 if (invert)
3963 return(-1);
3964 else
3965 return(1);
3966 }
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003967 if (*yv != 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003968 /*
3969 * Skip trailing blank chars of the collapsed string.
3970 */
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003971 while (IS_WSP_SPACE_CH(*yv) || IS_WSP_REPLACE_CH(*yv))
3972 yv++;
3973 if (*yv != 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003974 if (invert)
3975 return(1);
3976 else
3977 return(-1);
3978 }
3979 }
3980 return(0);
3981}
3982
3983
3984/**
3985 * xmlSchemaCompareReplacedStrings:
3986 * @x: a first string value
3987 * @y: a second string value
3988 *
3989 * Compare 2 string for their normalized values.
3990 *
3991 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
3992 * case of error
3993 */
3994static int
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003995xmlSchemaCompareReplacedStrings(const xmlChar *xv,
3996 const xmlChar *yv)
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003997{
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003998 int tmp;
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003999
4000 while ((*xv != 0) && (*yv != 0)) {
4001 if (IS_WSP_SPACE_CH(*yv) || IS_WSP_REPLACE_CH(*yv)) {
4002 if (! (IS_WSP_SPACE_CH(*xv) || IS_WSP_REPLACE_CH(*xv))) {
4003 if ((*xv - 0x20) < 0)
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004004 return(-1);
4005 else
4006 return(1);
4007 }
4008 } else {
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004009 if (IS_WSP_SPACE_CH(*xv) || IS_WSP_REPLACE_CH(*xv)) {
4010 if ((0x20 - *yv) < 0)
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004011 return(-1);
4012 else
4013 return(1);
4014 }
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004015 tmp = *xv - *yv;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004016 if (tmp < 0)
4017 return(-1);
4018 if (tmp > 0)
4019 return(1);
4020 }
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004021 xv++;
4022 yv++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004023 }
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004024 if (*xv != 0)
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004025 return(1);
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004026 if (*yv != 0)
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004027 return(-1);
4028 return(0);
4029}
4030
4031/**
Daniel Veillardc4c21552003-03-29 10:53:38 +00004032 * xmlSchemaCompareNormStrings:
4033 * @x: a first string value
4034 * @y: a second string value
4035 *
4036 * Compare 2 string for their normalized values.
4037 *
4038 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
4039 * case of error
4040 */
4041static int
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004042xmlSchemaCompareNormStrings(const xmlChar *xv,
4043 const xmlChar *yv) {
Daniel Veillardc4c21552003-03-29 10:53:38 +00004044 int tmp;
Daniel Veillardc4c21552003-03-29 10:53:38 +00004045
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004046 while (IS_BLANK_CH(*xv)) xv++;
4047 while (IS_BLANK_CH(*yv)) yv++;
4048 while ((*xv != 0) && (*yv != 0)) {
4049 if (IS_BLANK_CH(*xv)) {
4050 if (!IS_BLANK_CH(*yv)) {
4051 tmp = *xv - *yv;
Daniel Veillardc4c21552003-03-29 10:53:38 +00004052 return(tmp);
4053 }
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004054 while (IS_BLANK_CH(*xv)) xv++;
4055 while (IS_BLANK_CH(*yv)) yv++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00004056 } else {
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004057 tmp = *xv++ - *yv++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00004058 if (tmp < 0)
4059 return(-1);
4060 if (tmp > 0)
4061 return(1);
4062 }
4063 }
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004064 if (*xv != 0) {
4065 while (IS_BLANK_CH(*xv)) xv++;
4066 if (*xv != 0)
Daniel Veillardc4c21552003-03-29 10:53:38 +00004067 return(1);
4068 }
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004069 if (*yv != 0) {
4070 while (IS_BLANK_CH(*yv)) yv++;
4071 if (*yv != 0)
Daniel Veillardc4c21552003-03-29 10:53:38 +00004072 return(-1);
4073 }
4074 return(0);
4075}
4076
4077/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00004078 * xmlSchemaCompareFloats:
4079 * @x: a first float or double value
4080 * @y: a second float or double value
4081 *
4082 * Compare 2 values
4083 *
4084 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
4085 * case of error
4086 */
4087static int
4088xmlSchemaCompareFloats(xmlSchemaValPtr x, xmlSchemaValPtr y) {
4089 double d1, d2;
4090
4091 if ((x == NULL) || (y == NULL))
4092 return(-2);
4093
4094 /*
4095 * Cast everything to doubles.
4096 */
4097 if (x->type == XML_SCHEMAS_DOUBLE)
4098 d1 = x->value.d;
4099 else if (x->type == XML_SCHEMAS_FLOAT)
4100 d1 = x->value.f;
4101 else
4102 return(-2);
4103
4104 if (y->type == XML_SCHEMAS_DOUBLE)
4105 d2 = y->value.d;
4106 else if (y->type == XML_SCHEMAS_FLOAT)
4107 d2 = y->value.f;
4108 else
4109 return(-2);
4110
4111 /*
4112 * Check for special cases.
4113 */
4114 if (xmlXPathIsNaN(d1)) {
4115 if (xmlXPathIsNaN(d2))
4116 return(0);
4117 return(1);
4118 }
4119 if (xmlXPathIsNaN(d2))
4120 return(-1);
4121 if (d1 == xmlXPathPINF) {
4122 if (d2 == xmlXPathPINF)
4123 return(0);
4124 return(1);
4125 }
4126 if (d2 == xmlXPathPINF)
4127 return(-1);
4128 if (d1 == xmlXPathNINF) {
4129 if (d2 == xmlXPathNINF)
4130 return(0);
4131 return(-1);
4132 }
4133 if (d2 == xmlXPathNINF)
4134 return(1);
4135
4136 /*
4137 * basic tests, the last one we should have equality, but
4138 * portability is more important than speed and handling
4139 * NaN or Inf in a portable way is always a challenge, so ...
4140 */
4141 if (d1 < d2)
4142 return(-1);
4143 if (d1 > d2)
4144 return(1);
4145 if (d1 == d2)
4146 return(0);
4147 return(2);
4148}
4149
4150/**
Daniel Veillard4255d502002-04-16 15:50:10 +00004151 * xmlSchemaCompareValues:
4152 * @x: a first value
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004153 * @xvalue: the first value as a string (optional)
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004154 * @xwtsp: the whitespace type
Daniel Veillard4255d502002-04-16 15:50:10 +00004155 * @y: a second value
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004156 * @xvalue: the second value as a string (optional)
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004157 * @ywtsp: the whitespace type
Daniel Veillard4255d502002-04-16 15:50:10 +00004158 *
4159 * Compare 2 values
4160 *
Daniel Veillard5a872412002-05-22 06:40:27 +00004161 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
4162 * case of error
Daniel Veillard4255d502002-04-16 15:50:10 +00004163 */
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004164static int
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004165xmlSchemaCompareValuesInternal(xmlSchemaValType xtype,
4166 xmlSchemaValPtr x,
4167 const xmlChar *xvalue,
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004168 xmlSchemaWhitespaceValueType xws,
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004169 xmlSchemaValType ytype,
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004170 xmlSchemaValPtr y,
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004171 const xmlChar *yvalue,
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004172 xmlSchemaWhitespaceValueType yws) {
Daniel Veillard4255d502002-04-16 15:50:10 +00004173 if ((x == NULL) || (y == NULL))
4174 return(-2);
4175
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004176 switch (xtype) {
Daniel Veillard80b19092003-03-28 13:29:53 +00004177 case XML_SCHEMAS_UNKNOWN:
William M. Brack2f2a6632004-08-20 23:09:47 +00004178 case XML_SCHEMAS_ANYTYPE:
Daniel Veillard80b19092003-03-28 13:29:53 +00004179 return(-2);
4180 case XML_SCHEMAS_INTEGER:
4181 case XML_SCHEMAS_NPINTEGER:
4182 case XML_SCHEMAS_NINTEGER:
4183 case XML_SCHEMAS_NNINTEGER:
4184 case XML_SCHEMAS_PINTEGER:
4185 case XML_SCHEMAS_INT:
4186 case XML_SCHEMAS_UINT:
4187 case XML_SCHEMAS_LONG:
4188 case XML_SCHEMAS_ULONG:
4189 case XML_SCHEMAS_SHORT:
4190 case XML_SCHEMAS_USHORT:
4191 case XML_SCHEMAS_BYTE:
4192 case XML_SCHEMAS_UBYTE:
Daniel Veillard4255d502002-04-16 15:50:10 +00004193 case XML_SCHEMAS_DECIMAL:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004194 if ((x == NULL) || (y == NULL))
4195 return(-2);
4196 if (ytype == xtype)
Daniel Veillard80b19092003-03-28 13:29:53 +00004197 return(xmlSchemaCompareDecimals(x, y));
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004198 if ((ytype == XML_SCHEMAS_DECIMAL) ||
4199 (ytype == XML_SCHEMAS_INTEGER) ||
4200 (ytype == XML_SCHEMAS_NPINTEGER) ||
4201 (ytype == XML_SCHEMAS_NINTEGER) ||
4202 (ytype == XML_SCHEMAS_NNINTEGER) ||
4203 (ytype == XML_SCHEMAS_PINTEGER) ||
4204 (ytype == XML_SCHEMAS_INT) ||
4205 (ytype == XML_SCHEMAS_UINT) ||
4206 (ytype == XML_SCHEMAS_LONG) ||
4207 (ytype == XML_SCHEMAS_ULONG) ||
4208 (ytype == XML_SCHEMAS_SHORT) ||
4209 (ytype == XML_SCHEMAS_USHORT) ||
4210 (ytype == XML_SCHEMAS_BYTE) ||
4211 (ytype == XML_SCHEMAS_UBYTE))
Daniel Veillard4255d502002-04-16 15:50:10 +00004212 return(xmlSchemaCompareDecimals(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00004213 return(-2);
Daniel Veillard070803b2002-05-03 07:29:38 +00004214 case XML_SCHEMAS_DURATION:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004215 if ((x == NULL) || (y == NULL))
4216 return(-2);
Daniel Veillard070803b2002-05-03 07:29:38 +00004217 if (y->type == XML_SCHEMAS_DURATION)
4218 return(xmlSchemaCompareDurations(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00004219 return(-2);
4220 case XML_SCHEMAS_TIME:
4221 case XML_SCHEMAS_GDAY:
4222 case XML_SCHEMAS_GMONTH:
4223 case XML_SCHEMAS_GMONTHDAY:
4224 case XML_SCHEMAS_GYEAR:
4225 case XML_SCHEMAS_GYEARMONTH:
4226 case XML_SCHEMAS_DATE:
4227 case XML_SCHEMAS_DATETIME:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004228 if ((x == NULL) || (y == NULL))
4229 return(-2);
4230 if ((ytype == XML_SCHEMAS_DATETIME) ||
4231 (ytype == XML_SCHEMAS_TIME) ||
4232 (ytype == XML_SCHEMAS_GDAY) ||
4233 (ytype == XML_SCHEMAS_GMONTH) ||
4234 (ytype == XML_SCHEMAS_GMONTHDAY) ||
4235 (ytype == XML_SCHEMAS_GYEAR) ||
4236 (ytype == XML_SCHEMAS_DATE) ||
4237 (ytype == XML_SCHEMAS_GYEARMONTH))
Daniel Veillard5a872412002-05-22 06:40:27 +00004238 return (xmlSchemaCompareDates(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00004239 return (-2);
Kasimier T. Buchcik2ee855d2005-03-07 11:14:14 +00004240 /*
4241 * Note that we will support comparison of string types against
4242 * anySimpleType as well.
4243 */
4244 case XML_SCHEMAS_ANYSIMPLETYPE:
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004245 case XML_SCHEMAS_STRING:
4246 case XML_SCHEMAS_NORMSTRING:
Daniel Veillard80b19092003-03-28 13:29:53 +00004247 case XML_SCHEMAS_TOKEN:
4248 case XML_SCHEMAS_LANGUAGE:
4249 case XML_SCHEMAS_NMTOKEN:
Daniel Veillard80b19092003-03-28 13:29:53 +00004250 case XML_SCHEMAS_NAME:
Daniel Veillard80b19092003-03-28 13:29:53 +00004251 case XML_SCHEMAS_NCNAME:
4252 case XML_SCHEMAS_ID:
4253 case XML_SCHEMAS_IDREF:
Daniel Veillard80b19092003-03-28 13:29:53 +00004254 case XML_SCHEMAS_ENTITY:
Daniel Veillard80b19092003-03-28 13:29:53 +00004255 case XML_SCHEMAS_NOTATION:
4256 case XML_SCHEMAS_ANYURI:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004257 {
4258 const xmlChar *xv, *yv;
4259
4260 if (x == NULL)
4261 xv = xvalue;
4262 else
4263 xv = x->value.str;
4264 if (y == NULL)
4265 yv = yvalue;
4266 else
4267 yv = y->value.str;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004268 /*
4269 * TODO: Compare those against QName.
4270 */
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004271 if (ytype == XML_SCHEMAS_QNAME) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004272 TODO
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004273 if (y == NULL)
4274 return(-2);
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004275 return (-2);
4276 }
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004277 if ((ytype == XML_SCHEMAS_ANYSIMPLETYPE) ||
4278 (ytype == XML_SCHEMAS_STRING) ||
4279 (ytype == XML_SCHEMAS_NORMSTRING) ||
4280 (ytype == XML_SCHEMAS_TOKEN) ||
4281 (ytype == XML_SCHEMAS_LANGUAGE) ||
4282 (ytype == XML_SCHEMAS_NMTOKEN) ||
4283 (ytype == XML_SCHEMAS_NAME) ||
4284 (ytype == XML_SCHEMAS_NCNAME) ||
4285 (ytype == XML_SCHEMAS_ID) ||
4286 (ytype == XML_SCHEMAS_IDREF) ||
4287 (ytype == XML_SCHEMAS_ENTITY) ||
4288 (ytype == XML_SCHEMAS_NOTATION) ||
4289 (ytype == XML_SCHEMAS_ANYURI)) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004290
4291 if (xws == XML_SCHEMA_WHITESPACE_PRESERVE) {
4292
4293 if (yws == XML_SCHEMA_WHITESPACE_PRESERVE) {
4294 /* TODO: What about x < y or x > y. */
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004295 if (xmlStrEqual(xv, yv))
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004296 return (0);
4297 else
4298 return (2);
4299 } else if (yws == XML_SCHEMA_WHITESPACE_REPLACE)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004300 return (xmlSchemaComparePreserveReplaceStrings(xv, yv, 0));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004301 else if (yws == XML_SCHEMA_WHITESPACE_COLLAPSE)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004302 return (xmlSchemaComparePreserveCollapseStrings(xv, yv, 0));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004303
4304 } else if (xws == XML_SCHEMA_WHITESPACE_REPLACE) {
4305
4306 if (yws == XML_SCHEMA_WHITESPACE_PRESERVE)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004307 return (xmlSchemaComparePreserveReplaceStrings(yv, xv, 1));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004308 if (yws == XML_SCHEMA_WHITESPACE_REPLACE)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004309 return (xmlSchemaCompareReplacedStrings(xv, yv));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004310 if (yws == XML_SCHEMA_WHITESPACE_COLLAPSE)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004311 return (xmlSchemaCompareReplaceCollapseStrings(xv, yv, 0));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004312
4313 } else if (xws == XML_SCHEMA_WHITESPACE_COLLAPSE) {
4314
4315 if (yws == XML_SCHEMA_WHITESPACE_PRESERVE)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004316 return (xmlSchemaComparePreserveCollapseStrings(yv, xv, 1));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004317 if (yws == XML_SCHEMA_WHITESPACE_REPLACE)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004318 return (xmlSchemaCompareReplaceCollapseStrings(yv, xv, 1));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004319 if (yws == XML_SCHEMA_WHITESPACE_COLLAPSE)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004320 return (xmlSchemaCompareNormStrings(xv, yv));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004321 } else
4322 return (-2);
4323
4324 }
Daniel Veillardc4c21552003-03-29 10:53:38 +00004325 return (-2);
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004326 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004327 case XML_SCHEMAS_QNAME:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004328 if ((x == NULL) || (y == NULL))
4329 return(-2);
4330 if (ytype == XML_SCHEMAS_QNAME) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004331 if ((xmlStrEqual(x->value.qname.name, y->value.qname.name)) &&
4332 (xmlStrEqual(x->value.qname.uri, y->value.qname.uri)))
4333 return(0);
4334 return(2);
4335 }
4336 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00004337 case XML_SCHEMAS_FLOAT:
4338 case XML_SCHEMAS_DOUBLE:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004339 if ((x == NULL) || (y == NULL))
4340 return(-2);
4341 if ((ytype == XML_SCHEMAS_FLOAT) ||
4342 (ytype == XML_SCHEMAS_DOUBLE))
Daniel Veillardb6c7f412003-03-29 16:41:55 +00004343 return (xmlSchemaCompareFloats(x, y));
4344 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00004345 case XML_SCHEMAS_BOOLEAN:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004346 if ((x == NULL) || (y == NULL))
4347 return(-2);
4348 if (ytype == XML_SCHEMAS_BOOLEAN) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00004349 if (x->value.b == y->value.b)
4350 return(0);
4351 if (x->value.b == 0)
4352 return(-1);
4353 return(1);
4354 }
4355 return (-2);
Daniel Veillard560c2a42003-07-06 21:13:49 +00004356 case XML_SCHEMAS_HEXBINARY:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004357 if ((x == NULL) || (y == NULL))
4358 return(-2);
4359 if (ytype == XML_SCHEMAS_HEXBINARY) {
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004360 if (x->value.hex.total == y->value.hex.total) {
4361 int ret = xmlStrcmp(x->value.hex.str, y->value.hex.str);
4362 if (ret > 0)
4363 return(1);
4364 else if (ret == 0)
4365 return(0);
4366 }
4367 else if (x->value.hex.total > y->value.hex.total)
4368 return(1);
4369
4370 return(-1);
4371 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00004372 return (-2);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00004373 case XML_SCHEMAS_BASE64BINARY:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004374 if ((x == NULL) || (y == NULL))
4375 return(-2);
4376 if (ytype == XML_SCHEMAS_BASE64BINARY) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00004377 if (x->value.base64.total == y->value.base64.total) {
4378 int ret = xmlStrcmp(x->value.base64.str,
4379 y->value.base64.str);
4380 if (ret > 0)
4381 return(1);
4382 else if (ret == 0)
4383 return(0);
4384 }
4385 else if (x->value.base64.total > y->value.base64.total)
4386 return(1);
4387 else
4388 return(-1);
4389 }
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004390 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00004391 case XML_SCHEMAS_IDREFS:
4392 case XML_SCHEMAS_ENTITIES:
4393 case XML_SCHEMAS_NMTOKENS:
4394 TODO
4395 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00004396 }
Daniel Veillard5a872412002-05-22 06:40:27 +00004397 return -2;
Daniel Veillard4255d502002-04-16 15:50:10 +00004398}
4399
4400/**
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004401 * xmlSchemaCompareValues:
4402 * @x: a first value
4403 * @y: a second value
4404 *
4405 * Compare 2 values
4406 *
4407 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
4408 * case of error
4409 */
4410int
4411xmlSchemaCompareValues(xmlSchemaValPtr x, xmlSchemaValPtr y) {
4412 xmlSchemaWhitespaceValueType xws, yws;
4413
Daniel Veillard5e094142005-02-18 19:36:12 +00004414 if ((x == NULL) || (y == NULL))
4415 return(-2);
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004416 if (x->type == XML_SCHEMAS_STRING)
4417 xws = XML_SCHEMA_WHITESPACE_PRESERVE;
4418 else if (x->type == XML_SCHEMAS_NORMSTRING)
4419 xws = XML_SCHEMA_WHITESPACE_REPLACE;
4420 else
4421 xws = XML_SCHEMA_WHITESPACE_COLLAPSE;
4422
4423 if (y->type == XML_SCHEMAS_STRING)
4424 yws = XML_SCHEMA_WHITESPACE_PRESERVE;
4425 else if (x->type == XML_SCHEMAS_NORMSTRING)
4426 yws = XML_SCHEMA_WHITESPACE_REPLACE;
4427 else
4428 yws = XML_SCHEMA_WHITESPACE_COLLAPSE;
4429
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004430 return(xmlSchemaCompareValuesInternal(x->type, x, NULL, xws, y->type,
4431 y, NULL, yws));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004432}
4433
4434/**
4435 * xmlSchemaCompareValuesWhtsp:
4436 * @x: a first value
4437 * @xws: the whitespace value of x
4438 * @y: a second value
4439 * @yws: the whitespace value of y
4440 *
4441 * Compare 2 values
4442 *
4443 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
4444 * case of error
4445 */
4446int
4447xmlSchemaCompareValuesWhtsp(xmlSchemaValPtr x,
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004448 xmlSchemaWhitespaceValueType xws,
4449 xmlSchemaValPtr y,
4450 xmlSchemaWhitespaceValueType yws)
4451{
4452 return(xmlSchemaCompareValuesInternal(x->type, x, NULL, xws, y->type,
4453 y, NULL, yws));
4454}
4455
4456/**
4457 * xmlSchemaCompareValuesWhtspExt:
4458 * @x: a first value
4459 * @xws: the whitespace value of x
4460 * @y: a second value
4461 * @yws: the whitespace value of y
4462 *
4463 * Compare 2 values
4464 *
4465 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
4466 * case of error
4467 */
4468static int
4469xmlSchemaCompareValuesWhtspExt(xmlSchemaValType xtype,
4470 xmlSchemaValPtr x,
4471 const xmlChar *xvalue,
4472 xmlSchemaWhitespaceValueType xws,
4473 xmlSchemaValType ytype,
4474 xmlSchemaValPtr y,
4475 const xmlChar *yvalue,
4476 xmlSchemaWhitespaceValueType yws)
4477{
4478 return(xmlSchemaCompareValuesInternal(xtype, x, xvalue, xws, ytype, y,
4479 yvalue, yws));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004480}
4481
4482/**
Daniel Veillardc4c21552003-03-29 10:53:38 +00004483 * xmlSchemaNormLen:
4484 * @value: a string
4485 *
4486 * Computes the UTF8 length of the normalized value of the string
4487 *
4488 * Returns the length or -1 in case of error.
4489 */
4490static int
4491xmlSchemaNormLen(const xmlChar *value) {
4492 const xmlChar *utf;
4493 int ret = 0;
4494
4495 if (value == NULL)
4496 return(-1);
4497 utf = value;
William M. Brack76e95df2003-10-18 16:20:14 +00004498 while (IS_BLANK_CH(*utf)) utf++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00004499 while (*utf != 0) {
4500 if (utf[0] & 0x80) {
4501 if ((utf[1] & 0xc0) != 0x80)
4502 return(-1);
4503 if ((utf[0] & 0xe0) == 0xe0) {
4504 if ((utf[2] & 0xc0) != 0x80)
4505 return(-1);
4506 if ((utf[0] & 0xf0) == 0xf0) {
4507 if ((utf[0] & 0xf8) != 0xf0 || (utf[3] & 0xc0) != 0x80)
4508 return(-1);
4509 utf += 4;
4510 } else {
4511 utf += 3;
4512 }
4513 } else {
4514 utf += 2;
4515 }
William M. Brack76e95df2003-10-18 16:20:14 +00004516 } else if (IS_BLANK_CH(*utf)) {
4517 while (IS_BLANK_CH(*utf)) utf++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00004518 if (*utf == 0)
4519 break;
4520 } else {
4521 utf++;
4522 }
4523 ret++;
4524 }
4525 return(ret);
4526}
4527
Daniel Veillard6927b102004-10-27 17:29:04 +00004528/**
4529 * xmlSchemaGetFacetValueAsULong:
4530 * @facet: an schemas type facet
4531 *
4532 * Extract the value of a facet
4533 *
4534 * Returns the value as a long
4535 */
Daniel Veillardc0826a72004-08-10 14:17:33 +00004536unsigned long
4537xmlSchemaGetFacetValueAsULong(xmlSchemaFacetPtr facet)
4538{
4539 /*
4540 * TODO: Check if this is a decimal.
4541 */
William M. Brack094dd862004-11-14 14:28:34 +00004542 if (facet == NULL)
4543 return 0;
Daniel Veillardc0826a72004-08-10 14:17:33 +00004544 return ((unsigned long) facet->val->value.decimal.lo);
4545}
4546
Daniel Veillardc4c21552003-03-29 10:53:38 +00004547/**
Daniel Veillard01fa6152004-06-29 17:04:39 +00004548 * xmlSchemaValidateListSimpleTypeFacet:
4549 * @facet: the facet to check
4550 * @value: the lexical repr of the value to validate
4551 * @actualLen: the number of list items
4552 * @expectedLen: the resulting expected number of list items
4553 *
4554 * Checks the value of a list simple type against a facet.
4555 *
4556 * Returns 0 if the value is valid, a positive error code
4557 * number otherwise and -1 in case of an internal error.
4558 */
4559int
4560xmlSchemaValidateListSimpleTypeFacet(xmlSchemaFacetPtr facet,
4561 const xmlChar *value,
4562 unsigned long actualLen,
4563 unsigned long *expectedLen)
4564{
Daniel Veillardce682bc2004-11-05 17:22:25 +00004565 if (facet == NULL)
4566 return(-1);
Daniel Veillard01fa6152004-06-29 17:04:39 +00004567 /*
4568 * TODO: Check if this will work with large numbers.
4569 * (compare value.decimal.mi and value.decimal.hi as well?).
4570 */
4571 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
4572 if (actualLen != facet->val->value.decimal.lo) {
Daniel Veillardc0826a72004-08-10 14:17:33 +00004573 if (expectedLen != 0)
4574 *expectedLen = facet->val->value.decimal.lo;
Daniel Veillard01fa6152004-06-29 17:04:39 +00004575 return (XML_SCHEMAV_CVC_LENGTH_VALID);
4576 }
4577 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
4578 if (actualLen < facet->val->value.decimal.lo) {
Daniel Veillardc0826a72004-08-10 14:17:33 +00004579 if (expectedLen != 0)
4580 *expectedLen = facet->val->value.decimal.lo;
Daniel Veillard01fa6152004-06-29 17:04:39 +00004581 return (XML_SCHEMAV_CVC_MINLENGTH_VALID);
4582 }
4583 } else if (facet->type == XML_SCHEMA_FACET_MAXLENGTH) {
4584 if (actualLen > facet->val->value.decimal.lo) {
Daniel Veillardc0826a72004-08-10 14:17:33 +00004585 if (expectedLen != 0)
4586 *expectedLen = facet->val->value.decimal.lo;
Daniel Veillard01fa6152004-06-29 17:04:39 +00004587 return (XML_SCHEMAV_CVC_MAXLENGTH_VALID);
4588 }
4589 } else
4590 /*
4591 * NOTE: That we can pass NULL as xmlSchemaValPtr to
4592 * xmlSchemaValidateFacet, since the remaining facet types
4593 * are: XML_SCHEMA_FACET_PATTERN, XML_SCHEMA_FACET_ENUMERATION.
4594 */
4595 return(xmlSchemaValidateFacet(NULL, facet, value, NULL));
4596 return (0);
4597}
4598
4599/**
Daniel Veillard6927b102004-10-27 17:29:04 +00004600 * xmlSchemaValidateLengthFacet:
Daniel Veillardc0826a72004-08-10 14:17:33 +00004601 * @type: the built-in type
4602 * @facet: the facet to check
4603 * @value: the lexical repr. of the value to be validated
4604 * @val: the precomputed value
4605 * @length: the actual length of the value
4606 *
4607 * Checka a value against a "length", "minLength" and "maxLength"
4608 * facet; sets @length to the computed length of @value.
4609 *
4610 * Returns 0 if the value is valid, a positive error code
4611 * otherwise and -1 in case of an internal or API error.
4612 */
4613int
4614xmlSchemaValidateLengthFacet(xmlSchemaTypePtr type,
4615 xmlSchemaFacetPtr facet,
4616 const xmlChar *value,
4617 xmlSchemaValPtr val,
4618 unsigned long *length)
4619{
4620 unsigned int len = 0;
4621
Daniel Veillardce682bc2004-11-05 17:22:25 +00004622 if ((length == NULL) || (facet == NULL) || (type == NULL))
4623 return (-1);
Daniel Veillardc0826a72004-08-10 14:17:33 +00004624 *length = 0;
4625 if ((facet->type != XML_SCHEMA_FACET_LENGTH) &&
4626 (facet->type != XML_SCHEMA_FACET_MAXLENGTH) &&
4627 (facet->type != XML_SCHEMA_FACET_MINLENGTH))
4628 return (-1);
4629
4630 if ((facet->val == NULL) ||
4631 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
4632 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
4633 (facet->val->value.decimal.frac != 0)) {
4634 return(-1);
4635 }
4636 if ((val != NULL) && (val->type == XML_SCHEMAS_HEXBINARY))
4637 len = val->value.hex.total;
4638 else if ((val != NULL) && (val->type == XML_SCHEMAS_BASE64BINARY))
4639 len = val->value.base64.total;
4640 else {
4641 switch (type->builtInType) {
4642 case XML_SCHEMAS_IDREF:
4643 case XML_SCHEMAS_NORMSTRING:
4644 case XML_SCHEMAS_TOKEN:
4645 case XML_SCHEMAS_LANGUAGE:
4646 case XML_SCHEMAS_NMTOKEN:
4647 case XML_SCHEMAS_NAME:
4648 case XML_SCHEMAS_NCNAME:
4649 case XML_SCHEMAS_ID:
4650 len = xmlSchemaNormLen(value);
4651 break;
4652 case XML_SCHEMAS_STRING:
4653 /*
4654 * FIXME: What exactly to do with anyURI?
4655 */
4656 case XML_SCHEMAS_ANYURI:
4657 if (value != NULL)
4658 len = xmlUTF8Strlen(value);
4659 break;
4660 default:
4661 TODO
4662 }
4663 }
4664 *length = (unsigned long) len;
4665 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
4666 if (len != facet->val->value.decimal.lo)
4667 return(XML_SCHEMAV_CVC_LENGTH_VALID);
4668 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
4669 if (len < facet->val->value.decimal.lo)
4670 return(XML_SCHEMAV_CVC_MINLENGTH_VALID);
4671 } else {
4672 if (len > facet->val->value.decimal.lo)
4673 return(XML_SCHEMAV_CVC_MAXLENGTH_VALID);
4674 }
4675
4676 return (0);
4677}
4678
4679/**
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004680 * xmlSchemaValidateFacetInternal:
Daniel Veillard01c13b52002-12-10 15:19:08 +00004681 * @base: the base type
Daniel Veillard4255d502002-04-16 15:50:10 +00004682 * @facet: the facet to check
4683 * @value: the lexical repr of the value to validate
4684 * @val: the precomputed value
4685 *
4686 * Check a value against a facet condition
4687 *
4688 * Returns 0 if the element is schemas valid, a positive error code
4689 * number otherwise and -1 in case of internal or API error.
4690 */
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004691static int
4692xmlSchemaValidateFacetInternal(xmlSchemaFacetPtr facet,
4693 xmlSchemaWhitespaceValueType fws,
4694 xmlSchemaValType valType,
4695 xmlSchemaValPtr val,
4696 const xmlChar *value,
4697 xmlSchemaWhitespaceValueType ws)
Daniel Veillard4255d502002-04-16 15:50:10 +00004698{
4699 int ret;
4700
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004701 if (facet == NULL)
4702 return(-1);
4703
Daniel Veillard4255d502002-04-16 15:50:10 +00004704 switch (facet->type) {
4705 case XML_SCHEMA_FACET_PATTERN:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004706 /*
4707 * NOTE that for patterns, the @value needs to be the normalized
4708 * value, *not* the lexical initial value or the canonical value.
4709 */
4710 if (value == NULL)
4711 return(-1);
Daniel Veillard4255d502002-04-16 15:50:10 +00004712 ret = xmlRegexpExec(facet->regexp, value);
4713 if (ret == 1)
4714 return(0);
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004715 if (ret == 0)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004716 return(XML_SCHEMAV_CVC_PATTERN_VALID);
Daniel Veillard4255d502002-04-16 15:50:10 +00004717 return(ret);
4718 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
4719 ret = xmlSchemaCompareValues(val, facet->val);
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004720 if (ret == -2)
Daniel Veillard4255d502002-04-16 15:50:10 +00004721 return(-1);
Daniel Veillard4255d502002-04-16 15:50:10 +00004722 if (ret == -1)
4723 return(0);
Daniel Veillard01fa6152004-06-29 17:04:39 +00004724 return(XML_SCHEMAV_CVC_MAXEXCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00004725 case XML_SCHEMA_FACET_MAXINCLUSIVE:
4726 ret = xmlSchemaCompareValues(val, facet->val);
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004727 if (ret == -2)
Daniel Veillard070803b2002-05-03 07:29:38 +00004728 return(-1);
Daniel Veillard070803b2002-05-03 07:29:38 +00004729 if ((ret == -1) || (ret == 0))
4730 return(0);
Daniel Veillard01fa6152004-06-29 17:04:39 +00004731 return(XML_SCHEMAV_CVC_MAXINCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00004732 case XML_SCHEMA_FACET_MINEXCLUSIVE:
4733 ret = xmlSchemaCompareValues(val, facet->val);
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004734 if (ret == -2)
Daniel Veillard070803b2002-05-03 07:29:38 +00004735 return(-1);
Daniel Veillard070803b2002-05-03 07:29:38 +00004736 if (ret == 1)
4737 return(0);
Daniel Veillard01fa6152004-06-29 17:04:39 +00004738 return(XML_SCHEMAV_CVC_MINEXCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00004739 case XML_SCHEMA_FACET_MININCLUSIVE:
4740 ret = xmlSchemaCompareValues(val, facet->val);
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004741 if (ret == -2)
Daniel Veillard070803b2002-05-03 07:29:38 +00004742 return(-1);
Daniel Veillard070803b2002-05-03 07:29:38 +00004743 if ((ret == 1) || (ret == 0))
4744 return(0);
Daniel Veillard01fa6152004-06-29 17:04:39 +00004745 return(XML_SCHEMAV_CVC_MININCLUSIVE_VALID);
Daniel Veillard8651f532002-04-17 09:06:27 +00004746 case XML_SCHEMA_FACET_WHITESPACE:
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004747 /* TODO whitespaces */
Daniel Veillard01fa6152004-06-29 17:04:39 +00004748 /*
4749 * NOTE: Whitespace should be handled to normalize
4750 * the value to be validated against a the facets;
4751 * not to normalize the value in-between.
4752 */
Daniel Veillard8651f532002-04-17 09:06:27 +00004753 return(0);
Daniel Veillard88c58912002-04-23 07:12:20 +00004754 case XML_SCHEMA_FACET_ENUMERATION:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004755 if (fws == XML_SCHEMA_WHITESPACE_UNKNOWN) {
4756 if ((facet->value != NULL) &&
4757 (xmlStrEqual(facet->value, value)))
4758 return(0);
4759 } else {
4760 ret = xmlSchemaCompareValuesWhtspExt(facet->val->type,
4761 facet->val, facet->value, fws, valType, val,
4762 value, ws);
4763 if (ret == -2)
4764 return(-1);
4765 if (ret == 0)
4766 return(0);
4767 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00004768 return(XML_SCHEMAV_CVC_ENUMERATION_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004769 case XML_SCHEMA_FACET_LENGTH:
4770 case XML_SCHEMA_FACET_MAXLENGTH:
4771 case XML_SCHEMA_FACET_MINLENGTH: {
4772 unsigned int len = 0;
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004773 /* TODO: Take the whitespace of the value into account. */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004774
4775 if ((facet->val == NULL) ||
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004776 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
4777 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004778 (facet->val->value.decimal.frac != 0)) {
4779 return(-1);
4780 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00004781 if ((val != NULL) && (val->type == XML_SCHEMAS_HEXBINARY))
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004782 len = val->value.hex.total;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00004783 else if ((val != NULL) && (val->type == XML_SCHEMAS_BASE64BINARY))
4784 len = val->value.base64.total;
4785 else {
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004786 switch (valType) {
Daniel Veillard560c2a42003-07-06 21:13:49 +00004787 case XML_SCHEMAS_IDREF:
4788 case XML_SCHEMAS_NORMSTRING:
4789 case XML_SCHEMAS_TOKEN:
4790 case XML_SCHEMAS_LANGUAGE:
4791 case XML_SCHEMAS_NMTOKEN:
4792 case XML_SCHEMAS_NAME:
4793 case XML_SCHEMAS_NCNAME:
4794 case XML_SCHEMAS_ID:
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004795 len = xmlSchemaNormLen(value);
4796 break;
Daniel Veillard560c2a42003-07-06 21:13:49 +00004797 case XML_SCHEMAS_STRING:
Daniel Veillard01fa6152004-06-29 17:04:39 +00004798 /*
4799 * FIXME: What exactly to do with anyURI?
4800 */
4801 case XML_SCHEMAS_ANYURI:
William M. Brackfbf2c5e2004-02-03 17:55:56 +00004802 if (value != NULL)
4803 len = xmlUTF8Strlen(value);
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004804 break;
Daniel Veillard560c2a42003-07-06 21:13:49 +00004805 default:
4806 TODO
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004807 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004808 }
4809 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004810 if (len != facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004811 return(XML_SCHEMAV_CVC_LENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004812 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004813 if (len < facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004814 return(XML_SCHEMAV_CVC_MINLENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004815 } else {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004816 if (len > facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004817 return(XML_SCHEMAV_CVC_MAXLENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004818 }
4819 break;
4820 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00004821 case XML_SCHEMA_FACET_TOTALDIGITS:
4822 case XML_SCHEMA_FACET_FRACTIONDIGITS:
4823
4824 if ((facet->val == NULL) ||
4825 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
4826 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
4827 (facet->val->value.decimal.frac != 0)) {
4828 return(-1);
4829 }
4830 if ((val == NULL) ||
4831 ((val->type != XML_SCHEMAS_DECIMAL) &&
4832 (val->type != XML_SCHEMAS_INTEGER) &&
4833 (val->type != XML_SCHEMAS_NPINTEGER) &&
4834 (val->type != XML_SCHEMAS_NINTEGER) &&
4835 (val->type != XML_SCHEMAS_NNINTEGER) &&
4836 (val->type != XML_SCHEMAS_PINTEGER) &&
4837 (val->type != XML_SCHEMAS_INT) &&
4838 (val->type != XML_SCHEMAS_UINT) &&
4839 (val->type != XML_SCHEMAS_LONG) &&
4840 (val->type != XML_SCHEMAS_ULONG) &&
4841 (val->type != XML_SCHEMAS_SHORT) &&
4842 (val->type != XML_SCHEMAS_USHORT) &&
4843 (val->type != XML_SCHEMAS_BYTE) &&
4844 (val->type != XML_SCHEMAS_UBYTE))) {
4845 return(-1);
4846 }
4847 if (facet->type == XML_SCHEMA_FACET_TOTALDIGITS) {
4848 if (val->value.decimal.total > facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004849 return(XML_SCHEMAV_CVC_TOTALDIGITS_VALID);
Daniel Veillard560c2a42003-07-06 21:13:49 +00004850
4851 } else if (facet->type == XML_SCHEMA_FACET_FRACTIONDIGITS) {
4852 if (val->value.decimal.frac > facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004853 return(XML_SCHEMAV_CVC_FRACTIONDIGITS_VALID);
Daniel Veillard560c2a42003-07-06 21:13:49 +00004854 }
4855 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00004856 default:
4857 TODO
4858 }
4859 return(0);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00004860
Daniel Veillard4255d502002-04-16 15:50:10 +00004861}
4862
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004863/**
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004864 * xmlSchemaValidateFacet:
4865 * @base: the base type
4866 * @facet: the facet to check
4867 * @value: the lexical repr of the value to validate
4868 * @val: the precomputed value
4869 *
4870 * Check a value against a facet condition
4871 *
4872 * Returns 0 if the element is schemas valid, a positive error code
4873 * number otherwise and -1 in case of internal or API error.
4874 */
4875int
4876xmlSchemaValidateFacet(xmlSchemaTypePtr base ATTRIBUTE_UNUSED,
4877 xmlSchemaFacetPtr facet,
4878 const xmlChar *value,
4879 xmlSchemaValPtr val)
4880{
4881 /*
4882 * This tries to ensure API compatibility regarding the old
4883 * xmlSchemaValidateFacet() and the new xmlSchemaValidateFacetInternal() and
4884 * xmlSchemaValidateFacetWhtsp().
4885 */
4886 if (val != NULL)
4887 return(xmlSchemaValidateFacetInternal(facet,
4888 XML_SCHEMA_WHITESPACE_UNKNOWN, val->type, val, value,
4889 XML_SCHEMA_WHITESPACE_UNKNOWN));
4890 else {
4891 return(xmlSchemaValidateFacetInternal(facet,
4892 XML_SCHEMA_WHITESPACE_UNKNOWN, base->builtInType, val, value,
4893 XML_SCHEMA_WHITESPACE_UNKNOWN));
4894 }
4895}
4896
4897/**
4898 * xmlSchemaValidateFacetWhtsp:
4899 * @facet: the facet to check
4900 * @fws: the whitespace type of the facet's value
4901 * @valType: the built-in type of the value
4902 * @value: the lexical (or normalized for pattern) repr of the value to validate
4903 * @val: the precomputed value
4904 * @ws: the whitespace type of the value
4905 *
4906 * Check a value against a facet condition. This takes value normalization
4907 * according to the specified whitespace types into account.
4908 * Note that @value needs to be the *normalized* value if the facet
4909 * is of type "pattern".
4910 *
4911 * Returns 0 if the element is schemas valid, a positive error code
4912 * number otherwise and -1 in case of internal or API error.
4913 */
4914#if 0
4915int
4916xmlSchemaValidateFacetWhtsp(xmlSchemaFacetPtr facet,
4917 xmlSchemaWhitespaceValueType fws,
4918 xmlSchemaValType valType,
4919 xmlSchemaValPtr val,
4920 const xmlChar *value,
4921 xmlSchemaWhitespaceValueType ws)
4922{
4923 return(xmlSchemaValidateFacetInternal(facet, fws, valType,
4924 val, value, ws));
4925}
4926#endif
4927
4928/**
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004929 * xmlSchemaGetCanonValue:
4930 * @val: the precomputed value
4931 * @retValue: the returned value
4932 *
Daniel Veillardb5839c32005-02-19 18:27:14 +00004933 * Get a the cononical representation of the value.
4934 * The caller has to free the returned retValue.
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004935 *
4936 * Returns 0 if the value could be built and -1 in case of
4937 * API errors or if the value type is not supported yet.
4938 */
4939int
Daniel Veillardb5839c32005-02-19 18:27:14 +00004940xmlSchemaGetCanonValue(xmlSchemaValPtr val, const xmlChar **retValue)
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004941{
Daniel Veillardb5839c32005-02-19 18:27:14 +00004942 if ((retValue == NULL) || (val == NULL))
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004943 return (-1);
4944 *retValue = NULL;
4945 switch (val->type) {
4946 case XML_SCHEMAS_STRING:
4947 case XML_SCHEMAS_NORMSTRING:
4948 /*
4949 case XML_SCHEMAS_TOKEN:
4950 case XML_SCHEMAS_LANGUAGE:
4951 case XML_SCHEMAS_NMTOKEN:
4952 case XML_SCHEMAS_NAME:
4953 case XML_SCHEMAS_QNAME:
4954 case XML_SCHEMAS_NCNAME:
4955 case XML_SCHEMAS_ID:
4956 case XML_SCHEMAS_IDREF:
4957 case XML_SCHEMAS_ENTITY:
4958 case XML_SCHEMAS_NOTATION:
4959 case XML_SCHEMAS_ANYURI:
4960 */
4961 if (val->value.str == NULL)
4962 *retValue = NULL;
4963 else
4964 /* TODO: This is not yet correct for non-normalized values. */
4965 *retValue =
4966 BAD_CAST xmlStrdup((const xmlChar *) val->value.str);
4967 return (0);
4968 default:
4969 return (-1);
4970 }
4971 return (-1);
4972}
4973
Daniel Veillard4255d502002-04-16 15:50:10 +00004974#endif /* LIBXML_SCHEMAS_ENABLED */