blob: 52727b54b69de9fe0eb9349a4e33dd9870fc1e65 [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 *
William M. Brackec3b4b72005-03-15 15:50:17 +00001764 * Returns the number of significant digits in the number or
1765 * -1 if overflow of the capacity
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001766 */
1767static int
1768xmlSchemaParseUInt(const xmlChar **str, unsigned long *llo,
1769 unsigned long *lmi, unsigned long *lhi) {
1770 unsigned long lo = 0, mi = 0, hi = 0;
1771 const xmlChar *tmp, *cur = *str;
1772 int ret = 0, i = 0;
1773
William M. Brackec3b4b72005-03-15 15:50:17 +00001774 while (*cur == '0') { /* ignore leading zeroes */
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001775 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 */
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001926 if (val != NULL) {
1927 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
1928 if (v != NULL) {
William M. Brack273670f2005-03-11 15:55:14 +00001929 /*
1930 * If a mixed decimal, get rid of trailing zeroes
1931 */
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00001932 if (dec != -1) {
William M. Brack273670f2005-03-11 15:55:14 +00001933 while ((cptr > cval) && (*(cptr-1) == '0')) {
1934 cptr--;
1935 len--;
1936 }
1937 }
1938 *cptr = 0; /* Terminate our (preparsed) string */
1939 cptr = cval;
1940 /*
1941 * Now evaluate the significant digits of the number
1942 */
1943 xmlSchemaParseUInt((const xmlChar **)&cptr,
1944 &v->value.decimal.lo,
1945 &v->value.decimal.mi,
1946 &v->value.decimal.hi);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001947 v->value.decimal.sign = neg;
William M. Brack273670f2005-03-11 15:55:14 +00001948 if (dec == -1) {
1949 v->value.decimal.frac = 0;
1950 v->value.decimal.total = len;
1951 } else {
1952 v->value.decimal.frac = len - dec - 1;
1953 v->value.decimal.total = len - 1;
1954 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001955 *val = v;
1956 }
1957 }
1958 goto return0;
1959 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001960 case XML_SCHEMAS_TIME:
1961 case XML_SCHEMAS_GDAY:
1962 case XML_SCHEMAS_GMONTH:
1963 case XML_SCHEMAS_GMONTHDAY:
1964 case XML_SCHEMAS_GYEAR:
1965 case XML_SCHEMAS_GYEARMONTH:
1966 case XML_SCHEMAS_DATE:
1967 case XML_SCHEMAS_DATETIME:
Daniel Veillard01fa6152004-06-29 17:04:39 +00001968 ret = xmlSchemaValidateDates(type->builtInType, value, val);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001969 break;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001970 case XML_SCHEMAS_DURATION:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001971 ret = xmlSchemaValidateDuration(type, value, val);
1972 break;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001973 case XML_SCHEMAS_FLOAT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001974 case XML_SCHEMAS_DOUBLE:{
1975 const xmlChar *cur = value;
1976 int neg = 0;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001977
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001978 if (cur == NULL)
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00001979 goto return1;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001980 if ((cur[0] == 'N') && (cur[1] == 'a') && (cur[2] == 'N')) {
1981 cur += 3;
1982 if (*cur != 0)
1983 goto return1;
1984 if (val != NULL) {
1985 if (type == xmlSchemaTypeFloatDef) {
1986 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1987 if (v != NULL) {
1988 v->value.f = (float) xmlXPathNAN;
1989 } else {
1990 xmlSchemaFreeValue(v);
1991 goto error;
1992 }
1993 } else {
1994 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1995 if (v != NULL) {
1996 v->value.d = xmlXPathNAN;
1997 } else {
1998 xmlSchemaFreeValue(v);
1999 goto error;
2000 }
2001 }
2002 *val = v;
2003 }
2004 goto return0;
2005 }
2006 if (*cur == '-') {
2007 neg = 1;
2008 cur++;
2009 }
2010 if ((cur[0] == 'I') && (cur[1] == 'N') && (cur[2] == 'F')) {
2011 cur += 3;
2012 if (*cur != 0)
2013 goto return1;
2014 if (val != NULL) {
2015 if (type == xmlSchemaTypeFloatDef) {
2016 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
2017 if (v != NULL) {
2018 if (neg)
2019 v->value.f = (float) xmlXPathNINF;
2020 else
2021 v->value.f = (float) xmlXPathPINF;
2022 } else {
2023 xmlSchemaFreeValue(v);
2024 goto error;
2025 }
2026 } else {
2027 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
2028 if (v != NULL) {
2029 if (neg)
2030 v->value.d = xmlXPathNINF;
2031 else
2032 v->value.d = xmlXPathPINF;
2033 } else {
2034 xmlSchemaFreeValue(v);
2035 goto error;
2036 }
2037 }
2038 *val = v;
2039 }
2040 goto return0;
2041 }
2042 if ((neg == 0) && (*cur == '+'))
2043 cur++;
2044 if ((cur[0] == 0) || (cur[0] == '+') || (cur[0] == '-'))
2045 goto return1;
2046 while ((*cur >= '0') && (*cur <= '9')) {
2047 cur++;
2048 }
2049 if (*cur == '.') {
2050 cur++;
2051 while ((*cur >= '0') && (*cur <= '9'))
2052 cur++;
2053 }
2054 if ((*cur == 'e') || (*cur == 'E')) {
2055 cur++;
2056 if ((*cur == '-') || (*cur == '+'))
2057 cur++;
2058 while ((*cur >= '0') && (*cur <= '9'))
2059 cur++;
2060 }
2061 if (*cur != 0)
2062 goto return1;
2063 if (val != NULL) {
2064 if (type == xmlSchemaTypeFloatDef) {
2065 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
2066 if (v != NULL) {
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00002067 /*
2068 * TODO: sscanf seems not to give the correct
2069 * value for extremely high/low values.
2070 * E.g. "1E-149" results in zero.
2071 */
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002072 if (sscanf((const char *) value, "%f",
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002073 &(v->value.f)) == 1) {
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00002074 *val = v;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002075 } else {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002076 xmlSchemaFreeValue(v);
2077 goto return1;
2078 }
2079 } else {
2080 goto error;
2081 }
2082 } else {
2083 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
2084 if (v != NULL) {
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00002085 /*
2086 * TODO: sscanf seems not to give the correct
2087 * value for extremely high/low values.
2088 */
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002089 if (sscanf((const char *) value, "%lf",
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002090 &(v->value.d)) == 1) {
2091 *val = v;
2092 } else {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002093 xmlSchemaFreeValue(v);
2094 goto return1;
2095 }
2096 } else {
2097 goto error;
2098 }
2099 }
2100 }
2101 goto return0;
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00002102 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002103 case XML_SCHEMAS_BOOLEAN:{
2104 const xmlChar *cur = value;
2105
2106 if ((cur[0] == '0') && (cur[1] == 0))
2107 ret = 0;
2108 else if ((cur[0] == '1') && (cur[1] == 0))
2109 ret = 1;
2110 else if ((cur[0] == 't') && (cur[1] == 'r')
2111 && (cur[2] == 'u') && (cur[3] == 'e')
2112 && (cur[4] == 0))
2113 ret = 1;
2114 else if ((cur[0] == 'f') && (cur[1] == 'a')
2115 && (cur[2] == 'l') && (cur[3] == 's')
2116 && (cur[4] == 'e') && (cur[5] == 0))
2117 ret = 0;
2118 else
2119 goto return1;
2120 if (val != NULL) {
2121 v = xmlSchemaNewValue(XML_SCHEMAS_BOOLEAN);
2122 if (v != NULL) {
2123 v->value.b = ret;
2124 *val = v;
2125 } else {
2126 goto error;
2127 }
2128 }
2129 goto return0;
2130 }
2131 case XML_SCHEMAS_TOKEN:{
2132 const xmlChar *cur = value;
2133
William M. Brack76e95df2003-10-18 16:20:14 +00002134 if (IS_BLANK_CH(*cur))
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002135 goto return1;
2136
2137 while (*cur != 0) {
2138 if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) {
2139 goto return1;
2140 } else if (*cur == ' ') {
2141 cur++;
2142 if (*cur == 0)
2143 goto return1;
2144 if (*cur == ' ')
2145 goto return1;
2146 } else {
2147 cur++;
2148 }
2149 }
2150 if (val != NULL) {
2151 v = xmlSchemaNewValue(XML_SCHEMAS_TOKEN);
2152 if (v != NULL) {
2153 v->value.str = xmlStrdup(value);
2154 *val = v;
2155 } else {
2156 goto error;
2157 }
2158 }
2159 goto return0;
2160 }
2161 case XML_SCHEMAS_LANGUAGE:
2162 if (xmlCheckLanguageID(value) == 1) {
2163 if (val != NULL) {
2164 v = xmlSchemaNewValue(XML_SCHEMAS_LANGUAGE);
2165 if (v != NULL) {
2166 v->value.str = xmlStrdup(value);
2167 *val = v;
2168 } else {
2169 goto error;
2170 }
2171 }
2172 goto return0;
2173 }
2174 goto return1;
2175 case XML_SCHEMAS_NMTOKEN:
2176 if (xmlValidateNMToken(value, 1) == 0) {
2177 if (val != NULL) {
2178 v = xmlSchemaNewValue(XML_SCHEMAS_NMTOKEN);
2179 if (v != NULL) {
2180 v->value.str = xmlStrdup(value);
2181 *val = v;
2182 } else {
2183 goto error;
2184 }
2185 }
2186 goto return0;
2187 }
2188 goto return1;
2189 case XML_SCHEMAS_NMTOKENS:
2190 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeNmtokenDef,
2191 value, val, node);
2192 if (ret > 0)
2193 ret = 0;
2194 else
2195 ret = 1;
2196 goto done;
2197 case XML_SCHEMAS_NAME:
2198 ret = xmlValidateName(value, 1);
Daniel Veillarddf292f72005-01-16 19:00:15 +00002199 if ((ret == 0) && (val != NULL) && (value != NULL)) {
2200 v = xmlSchemaNewValue(XML_SCHEMAS_NAME);
2201 if (v != NULL) {
2202 const xmlChar *start = value, *end;
2203 while (IS_BLANK_CH(*start)) start++;
2204 end = start;
2205 while ((*end != 0) && (!IS_BLANK_CH(*end))) end++;
2206 v->value.str = xmlStrndup(start, end - start);
2207 *val = v;
2208 } else {
2209 goto error;
2210 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002211 }
2212 goto done;
2213 case XML_SCHEMAS_QNAME:{
2214 xmlChar *uri = NULL;
2215 xmlChar *local = NULL;
2216
2217 ret = xmlValidateQName(value, 1);
2218 if ((ret == 0) && (node != NULL)) {
2219 xmlChar *prefix;
2220
2221 local = xmlSplitQName2(value, &prefix);
2222 if (prefix != NULL) {
2223 xmlNsPtr ns;
2224
2225 ns = xmlSearchNs(node->doc, node, prefix);
2226 if (ns == NULL)
2227 ret = 1;
2228 else if (val != NULL)
2229 uri = xmlStrdup(ns->href);
2230 }
2231 if ((local != NULL) && ((val == NULL) || (ret != 0)))
2232 xmlFree(local);
2233 if (prefix != NULL)
2234 xmlFree(prefix);
2235 }
2236 if ((ret == 0) && (val != NULL)) {
2237 v = xmlSchemaNewValue(XML_SCHEMAS_QNAME);
2238 if (v != NULL) {
2239 if (local != NULL)
2240 v->value.qname.name = local;
2241 else
2242 v->value.qname.name = xmlStrdup(value);
2243 if (uri != NULL)
2244 v->value.qname.uri = uri;
2245
2246 *val = v;
2247 } else {
2248 if (local != NULL)
2249 xmlFree(local);
2250 if (uri != NULL)
2251 xmlFree(uri);
2252 goto error;
2253 }
2254 }
2255 goto done;
2256 }
2257 case XML_SCHEMAS_NCNAME:
2258 ret = xmlValidateNCName(value, 1);
2259 if ((ret == 0) && (val != NULL)) {
2260 v = xmlSchemaNewValue(XML_SCHEMAS_NCNAME);
2261 if (v != NULL) {
2262 v->value.str = xmlStrdup(value);
2263 *val = v;
2264 } else {
2265 goto error;
2266 }
2267 }
2268 goto done;
2269 case XML_SCHEMAS_ID:
2270 ret = xmlValidateNCName(value, 1);
2271 if ((ret == 0) && (val != NULL)) {
2272 v = xmlSchemaNewValue(XML_SCHEMAS_ID);
2273 if (v != NULL) {
2274 v->value.str = xmlStrdup(value);
2275 *val = v;
2276 } else {
2277 goto error;
2278 }
2279 }
2280 if ((ret == 0) && (node != NULL) &&
2281 (node->type == XML_ATTRIBUTE_NODE)) {
2282 xmlAttrPtr attr = (xmlAttrPtr) node;
2283
2284 /*
2285 * NOTE: the IDness might have already be declared in the DTD
2286 */
2287 if (attr->atype != XML_ATTRIBUTE_ID) {
2288 xmlIDPtr res;
2289 xmlChar *strip;
2290
2291 strip = xmlSchemaStrip(value);
2292 if (strip != NULL) {
2293 res = xmlAddID(NULL, node->doc, strip, attr);
2294 xmlFree(strip);
2295 } else
2296 res = xmlAddID(NULL, node->doc, value, attr);
2297 if (res == NULL) {
2298 ret = 2;
2299 } else {
2300 attr->atype = XML_ATTRIBUTE_ID;
2301 }
2302 }
2303 }
2304 goto done;
2305 case XML_SCHEMAS_IDREF:
2306 ret = xmlValidateNCName(value, 1);
2307 if ((ret == 0) && (val != NULL)) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00002308 v = xmlSchemaNewValue(XML_SCHEMAS_IDREF);
2309 if (v == NULL)
2310 goto error;
2311 v->value.str = xmlStrdup(value);
2312 *val = v;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002313 }
2314 if ((ret == 0) && (node != NULL) &&
2315 (node->type == XML_ATTRIBUTE_NODE)) {
2316 xmlAttrPtr attr = (xmlAttrPtr) node;
2317 xmlChar *strip;
2318
2319 strip = xmlSchemaStrip(value);
2320 if (strip != NULL) {
2321 xmlAddRef(NULL, node->doc, strip, attr);
2322 xmlFree(strip);
2323 } else
2324 xmlAddRef(NULL, node->doc, value, attr);
2325 attr->atype = XML_ATTRIBUTE_IDREF;
2326 }
2327 goto done;
2328 case XML_SCHEMAS_IDREFS:
2329 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeIdrefDef,
2330 value, val, node);
2331 if (ret < 0)
2332 ret = 2;
2333 else
2334 ret = 0;
2335 if ((ret == 0) && (node != NULL) &&
2336 (node->type == XML_ATTRIBUTE_NODE)) {
2337 xmlAttrPtr attr = (xmlAttrPtr) node;
2338
2339 attr->atype = XML_ATTRIBUTE_IDREFS;
2340 }
2341 goto done;
2342 case XML_SCHEMAS_ENTITY:{
2343 xmlChar *strip;
2344
2345 ret = xmlValidateNCName(value, 1);
2346 if ((node == NULL) || (node->doc == NULL))
2347 ret = 3;
2348 if (ret == 0) {
2349 xmlEntityPtr ent;
2350
2351 strip = xmlSchemaStrip(value);
2352 if (strip != NULL) {
2353 ent = xmlGetDocEntity(node->doc, strip);
2354 xmlFree(strip);
2355 } else {
2356 ent = xmlGetDocEntity(node->doc, value);
2357 }
2358 if ((ent == NULL) ||
2359 (ent->etype !=
2360 XML_EXTERNAL_GENERAL_UNPARSED_ENTITY))
2361 ret = 4;
2362 }
2363 if ((ret == 0) && (val != NULL)) {
2364 TODO;
2365 }
2366 if ((ret == 0) && (node != NULL) &&
2367 (node->type == XML_ATTRIBUTE_NODE)) {
2368 xmlAttrPtr attr = (xmlAttrPtr) node;
2369
2370 attr->atype = XML_ATTRIBUTE_ENTITY;
2371 }
2372 goto done;
2373 }
2374 case XML_SCHEMAS_ENTITIES:
2375 if ((node == NULL) || (node->doc == NULL))
2376 goto return3;
2377 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeEntityDef,
2378 value, val, node);
2379 if (ret <= 0)
2380 ret = 1;
2381 else
2382 ret = 0;
2383 if ((ret == 0) && (node != NULL) &&
2384 (node->type == XML_ATTRIBUTE_NODE)) {
2385 xmlAttrPtr attr = (xmlAttrPtr) node;
2386
2387 attr->atype = XML_ATTRIBUTE_ENTITIES;
2388 }
2389 goto done;
2390 case XML_SCHEMAS_NOTATION:{
2391 xmlChar *uri = NULL;
2392 xmlChar *local = NULL;
2393
2394 ret = xmlValidateQName(value, 1);
2395 if ((ret == 0) && (node != NULL)) {
2396 xmlChar *prefix;
2397
2398 local = xmlSplitQName2(value, &prefix);
2399 if (prefix != NULL) {
2400 xmlNsPtr ns;
2401
2402 ns = xmlSearchNs(node->doc, node, prefix);
2403 if (ns == NULL)
2404 ret = 1;
2405 else if (val != NULL)
2406 uri = xmlStrdup(ns->href);
2407 }
2408 if ((local != NULL) && ((val == NULL) || (ret != 0)))
2409 xmlFree(local);
2410 if (prefix != NULL)
2411 xmlFree(prefix);
2412 }
2413 if ((node == NULL) || (node->doc == NULL))
2414 ret = 3;
2415 if (ret == 0) {
2416 ret = xmlValidateNotationUse(NULL, node->doc, value);
2417 if (ret == 1)
2418 ret = 0;
2419 else
2420 ret = 1;
2421 }
2422 if ((ret == 0) && (val != NULL)) {
2423 v = xmlSchemaNewValue(XML_SCHEMAS_NOTATION);
2424 if (v != NULL) {
2425 if (local != NULL)
2426 v->value.qname.name = local;
2427 else
2428 v->value.qname.name = xmlStrdup(value);
2429 if (uri != NULL)
2430 v->value.qname.uri = uri;
2431
2432 *val = v;
2433 } else {
2434 if (local != NULL)
2435 xmlFree(local);
2436 if (uri != NULL)
2437 xmlFree(uri);
2438 goto error;
2439 }
2440 }
2441 goto done;
2442 }
2443 case XML_SCHEMAS_ANYURI:{
Daniel Veillard11c466a2004-03-14 12:20:15 +00002444 if (*value != 0) {
2445 xmlURIPtr uri = xmlParseURI((const char *) value);
2446 if (uri == NULL)
2447 goto return1;
2448 xmlFreeURI(uri);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002449 }
Daniel Veillard11c466a2004-03-14 12:20:15 +00002450
2451 if (val != NULL) {
2452 v = xmlSchemaNewValue(XML_SCHEMAS_ANYURI);
2453 if (v == NULL)
2454 goto error;
2455 v->value.str = xmlStrdup(value);
2456 *val = v;
2457 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002458 goto return0;
2459 }
2460 case XML_SCHEMAS_HEXBINARY:{
2461 const xmlChar *cur = value;
2462 xmlChar *base;
2463 int total, i = 0;
2464
Daniel Veillardf34a20e2004-08-31 08:42:17 +00002465 if (cur == NULL)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002466 goto return1;
2467
2468 while (((*cur >= '0') && (*cur <= '9')) ||
2469 ((*cur >= 'A') && (*cur <= 'F')) ||
2470 ((*cur >= 'a') && (*cur <= 'f'))) {
2471 i++;
2472 cur++;
2473 }
2474
2475 if (*cur != 0)
2476 goto return1;
2477 if ((i % 2) != 0)
2478 goto return1;
2479
2480 if (val != NULL) {
2481
2482 v = xmlSchemaNewValue(XML_SCHEMAS_HEXBINARY);
2483 if (v == NULL)
2484 goto error;
2485
2486 cur = xmlStrdup(value);
2487 if (cur == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002488 xmlSchemaTypeErrMemory(node, "allocating hexbin data");
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002489 xmlFree(v);
2490 goto return1;
2491 }
2492
2493 total = i / 2; /* number of octets */
2494
2495 base = (xmlChar *) cur;
2496 while (i-- > 0) {
2497 if (*base >= 'a')
2498 *base = *base - ('a' - 'A');
2499 base++;
2500 }
2501
2502 v->value.hex.str = (xmlChar *) cur;
2503 v->value.hex.total = total;
2504 *val = v;
2505 }
2506 goto return0;
2507 }
2508 case XML_SCHEMAS_BASE64BINARY:{
2509 /* ISSUE:
2510 *
2511 * Ignore all stray characters? (yes, currently)
2512 * Worry about long lines? (no, currently)
2513 *
2514 * rfc2045.txt:
2515 *
2516 * "The encoded output stream must be represented in lines of
2517 * no more than 76 characters each. All line breaks or other
2518 * characters not found in Table 1 must be ignored by decoding
2519 * software. In base64 data, characters other than those in
2520 * Table 1, line breaks, and other white space probably
2521 * indicate a transmission error, about which a warning
2522 * message or even a message rejection might be appropriate
2523 * under some circumstances." */
2524 const xmlChar *cur = value;
2525 xmlChar *base;
2526 int total, i = 0, pad = 0;
2527
2528 if (cur == NULL)
2529 goto return1;
2530
2531 for (; *cur; ++cur) {
2532 int decc;
2533
2534 decc = _xmlSchemaBase64Decode(*cur);
2535 if (decc < 0) ;
2536 else if (decc < 64)
2537 i++;
2538 else
2539 break;
2540 }
2541 for (; *cur; ++cur) {
2542 int decc;
2543
2544 decc = _xmlSchemaBase64Decode(*cur);
2545 if (decc < 0) ;
2546 else if (decc < 64)
2547 goto return1;
2548 if (decc == 64)
2549 pad++;
2550 }
2551
2552 /* rfc2045.txt: "Special processing is performed if fewer than
2553 * 24 bits are available at the end of the data being encoded.
2554 * A full encoding quantum is always completed at the end of a
2555 * body. When fewer than 24 input bits are available in an
2556 * input group, zero bits are added (on the right) to form an
2557 * integral number of 6-bit groups. Padding at the end of the
2558 * data is performed using the "=" character. Since all
2559 * base64 input is an integral number of octets, only the
2560 * following cases can arise: (1) the final quantum of
2561 * encoding input is an integral multiple of 24 bits; here,
2562 * the final unit of encoded output will be an integral
2563 * multiple ofindent: Standard input:701: Warning:old style
2564 * assignment ambiguity in "=*". Assuming "= *" 4 characters
2565 * with no "=" padding, (2) the final
2566 * quantum of encoding input is exactly 8 bits; here, the
2567 * final unit of encoded output will be two characters
2568 * followed by two "=" padding characters, or (3) the final
2569 * quantum of encoding input is exactly 16 bits; here, the
2570 * final unit of encoded output will be three characters
2571 * followed by one "=" padding character." */
2572
2573 total = 3 * (i / 4);
2574 if (pad == 0) {
2575 if (i % 4 != 0)
2576 goto return1;
2577 } else if (pad == 1) {
2578 int decc;
2579
2580 if (i % 4 != 3)
2581 goto return1;
2582 for (decc = _xmlSchemaBase64Decode(*cur);
2583 (decc < 0) || (decc > 63);
2584 decc = _xmlSchemaBase64Decode(*cur))
2585 --cur;
2586 /* 16bits in 24bits means 2 pad bits: nnnnnn nnmmmm mmmm00*/
2587 /* 00111100 -> 0x3c */
2588 if (decc & ~0x3c)
2589 goto return1;
2590 total += 2;
2591 } else if (pad == 2) {
2592 int decc;
2593
2594 if (i % 4 != 2)
2595 goto return1;
2596 for (decc = _xmlSchemaBase64Decode(*cur);
2597 (decc < 0) || (decc > 63);
2598 decc = _xmlSchemaBase64Decode(*cur))
2599 --cur;
2600 /* 8bits in 12bits means 4 pad bits: nnnnnn nn0000 */
2601 /* 00110000 -> 0x30 */
2602 if (decc & ~0x30)
2603 goto return1;
2604 total += 1;
2605 } else
2606 goto return1;
2607
2608 if (val != NULL) {
2609 v = xmlSchemaNewValue(XML_SCHEMAS_BASE64BINARY);
2610 if (v == NULL)
2611 goto error;
2612 base =
2613 (xmlChar *) xmlMallocAtomic((i + pad + 1) *
2614 sizeof(xmlChar));
2615 if (base == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002616 xmlSchemaTypeErrMemory(node, "allocating base64 data");
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002617 xmlFree(v);
2618 goto return1;
2619 }
2620 v->value.base64.str = base;
2621 for (cur = value; *cur; ++cur)
2622 if (_xmlSchemaBase64Decode(*cur) >= 0) {
2623 *base = *cur;
2624 ++base;
2625 }
2626 *base = 0;
2627 v->value.base64.total = total;
2628 *val = v;
2629 }
2630 goto return0;
2631 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002632 case XML_SCHEMAS_INTEGER:
2633 case XML_SCHEMAS_PINTEGER:
2634 case XML_SCHEMAS_NPINTEGER:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002635 case XML_SCHEMAS_NINTEGER:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002636 case XML_SCHEMAS_NNINTEGER:{
2637 const xmlChar *cur = value;
2638 unsigned long lo, mi, hi;
William M. Brackec3b4b72005-03-15 15:50:17 +00002639 int sign = 0;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002640
2641 if (cur == NULL)
2642 goto return1;
2643 if (*cur == '-') {
2644 sign = 1;
2645 cur++;
2646 } else if (*cur == '+')
2647 cur++;
William M. Brackec3b4b72005-03-15 15:50:17 +00002648 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2649 if (ret == -1)
2650 goto return1;
2651 if (*cur != 0)
2652 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002653 if (type->builtInType == XML_SCHEMAS_NPINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002654 if ((sign == 0) &&
2655 ((hi != 0) || (mi != 0) || (lo != 0)))
2656 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002657 } else if (type->builtInType == XML_SCHEMAS_PINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002658 if (sign == 1)
2659 goto return1;
2660 if ((hi == 0) && (mi == 0) && (lo == 0))
2661 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002662 } else if (type->builtInType == XML_SCHEMAS_NINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002663 if (sign == 0)
2664 goto return1;
2665 if ((hi == 0) && (mi == 0) && (lo == 0))
2666 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002667 } else if (type->builtInType == XML_SCHEMAS_NNINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002668 if ((sign == 1) &&
2669 ((hi != 0) || (mi != 0) || (lo != 0)))
2670 goto return1;
2671 }
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00002672 if (val != NULL) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00002673 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002674 if (v != NULL) {
2675 v->value.decimal.lo = lo;
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00002676 v->value.decimal.mi = mi;
2677 v->value.decimal.hi = hi;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002678 v->value.decimal.sign = sign;
2679 v->value.decimal.frac = 0;
William M. Brackec3b4b72005-03-15 15:50:17 +00002680 v->value.decimal.total = ret;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002681 *val = v;
2682 }
2683 }
2684 goto return0;
2685 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002686 case XML_SCHEMAS_LONG:
2687 case XML_SCHEMAS_BYTE:
2688 case XML_SCHEMAS_SHORT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002689 case XML_SCHEMAS_INT:{
2690 const xmlChar *cur = value;
2691 unsigned long lo, mi, hi;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002692 int sign = 0;
2693
2694 if (cur == NULL)
2695 goto return1;
2696 if (*cur == '-') {
2697 sign = 1;
2698 cur++;
2699 } else if (*cur == '+')
2700 cur++;
William M. Brackec3b4b72005-03-15 15:50:17 +00002701 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2702 if (ret < 0)
2703 goto return1;
2704 if (*cur != 0)
2705 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002706 if (type->builtInType == XML_SCHEMAS_LONG) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002707 if (hi >= 922) {
2708 if (hi > 922)
2709 goto return1;
2710 if (mi >= 33720368) {
2711 if (mi > 33720368)
2712 goto return1;
2713 if ((sign == 0) && (lo > 54775807))
2714 goto return1;
2715 if ((sign == 1) && (lo > 54775808))
2716 goto return1;
2717 }
2718 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002719 } else if (type->builtInType == XML_SCHEMAS_INT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002720 if (hi != 0)
2721 goto return1;
2722 if (mi >= 21) {
2723 if (mi > 21)
2724 goto return1;
2725 if ((sign == 0) && (lo > 47483647))
2726 goto return1;
2727 if ((sign == 1) && (lo > 47483648))
2728 goto return1;
2729 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002730 } else if (type->builtInType == XML_SCHEMAS_SHORT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002731 if ((mi != 0) || (hi != 0))
2732 goto return1;
2733 if ((sign == 1) && (lo > 32768))
2734 goto return1;
2735 if ((sign == 0) && (lo > 32767))
2736 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002737 } else if (type->builtInType == XML_SCHEMAS_BYTE) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002738 if ((mi != 0) || (hi != 0))
2739 goto return1;
2740 if ((sign == 1) && (lo > 128))
2741 goto return1;
2742 if ((sign == 0) && (lo > 127))
2743 goto return1;
2744 }
2745 if (val != NULL) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00002746 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002747 if (v != NULL) {
2748 v->value.decimal.lo = lo;
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00002749 v->value.decimal.mi = mi;
2750 v->value.decimal.hi = hi;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002751 v->value.decimal.sign = sign;
2752 v->value.decimal.frac = 0;
William M. Brackec3b4b72005-03-15 15:50:17 +00002753 v->value.decimal.total = ret;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002754 *val = v;
2755 }
2756 }
2757 goto return0;
2758 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002759 case XML_SCHEMAS_UINT:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002760 case XML_SCHEMAS_ULONG:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002761 case XML_SCHEMAS_USHORT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002762 case XML_SCHEMAS_UBYTE:{
2763 const xmlChar *cur = value;
2764 unsigned long lo, mi, hi;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002765
2766 if (cur == NULL)
2767 goto return1;
William M. Brackec3b4b72005-03-15 15:50:17 +00002768 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2769 if (ret < 0)
2770 goto return1;
2771 if (*cur != 0)
2772 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002773 if (type->builtInType == XML_SCHEMAS_ULONG) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002774 if (hi >= 1844) {
2775 if (hi > 1844)
2776 goto return1;
2777 if (mi >= 67440737) {
2778 if (mi > 67440737)
2779 goto return1;
2780 if (lo > 9551615)
2781 goto return1;
2782 }
2783 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002784 } else if (type->builtInType == XML_SCHEMAS_UINT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002785 if (hi != 0)
2786 goto return1;
2787 if (mi >= 42) {
2788 if (mi > 42)
2789 goto return1;
2790 if (lo > 94967295)
2791 goto return1;
2792 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002793 } else if (type->builtInType == XML_SCHEMAS_USHORT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002794 if ((mi != 0) || (hi != 0))
2795 goto return1;
2796 if (lo > 65535)
2797 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002798 } else if (type->builtInType == XML_SCHEMAS_UBYTE) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002799 if ((mi != 0) || (hi != 0))
2800 goto return1;
2801 if (lo > 255)
2802 goto return1;
2803 }
2804 if (val != NULL) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00002805 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002806 if (v != NULL) {
2807 v->value.decimal.lo = lo;
2808 v->value.decimal.mi = mi;
2809 v->value.decimal.hi = hi;
2810 v->value.decimal.sign = 0;
2811 v->value.decimal.frac = 0;
William M. Brackec3b4b72005-03-15 15:50:17 +00002812 v->value.decimal.total = ret;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002813 *val = v;
2814 }
2815 }
2816 goto return0;
2817 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002818 }
2819
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002820 done:
2821 if (norm != NULL)
2822 xmlFree(norm);
2823 return (ret);
2824 return3:
2825 if (norm != NULL)
2826 xmlFree(norm);
2827 return (3);
2828 return1:
2829 if (norm != NULL)
2830 xmlFree(norm);
2831 return (1);
2832 return0:
2833 if (norm != NULL)
2834 xmlFree(norm);
2835 return (0);
2836 error:
2837 if (norm != NULL)
2838 xmlFree(norm);
2839 return (-1);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002840}
2841
2842/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002843 * xmlSchemaValPredefTypeNode:
Daniel Veillard4255d502002-04-16 15:50:10 +00002844 * @type: the predefined type
2845 * @value: the value to check
2846 * @val: the return computed value
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002847 * @node: the node containing the value
Daniel Veillard4255d502002-04-16 15:50:10 +00002848 *
2849 * Check that a value conforms to the lexical space of the predefined type.
2850 * if true a value is computed and returned in @val.
2851 *
2852 * Returns 0 if this validates, a positive error code number otherwise
2853 * and -1 in case of internal or API error.
2854 */
2855int
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002856xmlSchemaValPredefTypeNode(xmlSchemaTypePtr type, const xmlChar *value,
2857 xmlSchemaValPtr *val, xmlNodePtr node) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002858 return(xmlSchemaValAtomicType(type, value, val, node, 0));
Daniel Veillard4255d502002-04-16 15:50:10 +00002859}
2860
2861/**
Daniel Veillardc0826a72004-08-10 14:17:33 +00002862 * xmlSchemaValPredefTypeNodeNoNorm:
2863 * @type: the predefined type
2864 * @value: the value to check
2865 * @val: the return computed value
2866 * @node: the node containing the value
2867 *
2868 * Check that a value conforms to the lexical space of the predefined type.
2869 * if true a value is computed and returned in @val.
2870 * This one does apply any normalization to the value.
2871 *
2872 * Returns 0 if this validates, a positive error code number otherwise
2873 * and -1 in case of internal or API error.
2874 */
2875int
2876xmlSchemaValPredefTypeNodeNoNorm(xmlSchemaTypePtr type, const xmlChar *value,
2877 xmlSchemaValPtr *val, xmlNodePtr node) {
2878 return(xmlSchemaValAtomicType(type, value, val, node, 1));
2879}
2880
2881/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002882 * xmlSchemaValidatePredefinedType:
2883 * @type: the predefined type
2884 * @value: the value to check
2885 * @val: the return computed value
2886 *
2887 * Check that a value conforms to the lexical space of the predefined type.
2888 * if true a value is computed and returned in @val.
2889 *
2890 * Returns 0 if this validates, a positive error code number otherwise
2891 * and -1 in case of internal or API error.
2892 */
2893int
2894xmlSchemaValidatePredefinedType(xmlSchemaTypePtr type, const xmlChar *value,
2895 xmlSchemaValPtr *val) {
2896 return(xmlSchemaValPredefTypeNode(type, value, val, NULL));
2897}
2898
2899/**
Daniel Veillard4255d502002-04-16 15:50:10 +00002900 * xmlSchemaCompareDecimals:
2901 * @x: a first decimal value
2902 * @y: a second decimal value
2903 *
2904 * Compare 2 decimals
2905 *
2906 * Returns -1 if x < y, 0 if x == y, 1 if x > y and -2 in case of error
2907 */
2908static int
2909xmlSchemaCompareDecimals(xmlSchemaValPtr x, xmlSchemaValPtr y)
2910{
2911 xmlSchemaValPtr swp;
William M. Brack273670f2005-03-11 15:55:14 +00002912 int order = 1, integx, integy, dlen;
2913 unsigned long hi, mi, lo;
Daniel Veillard4255d502002-04-16 15:50:10 +00002914
William M. Brack273670f2005-03-11 15:55:14 +00002915 /*
2916 * First test: If x is -ve and not zero
2917 */
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002918 if ((x->value.decimal.sign) &&
2919 ((x->value.decimal.lo != 0) ||
2920 (x->value.decimal.mi != 0) ||
2921 (x->value.decimal.hi != 0))) {
William M. Brack273670f2005-03-11 15:55:14 +00002922 /*
2923 * Then if y is -ve and not zero reverse the compare
2924 */
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002925 if ((y->value.decimal.sign) &&
2926 ((y->value.decimal.lo != 0) ||
2927 (y->value.decimal.mi != 0) ||
2928 (y->value.decimal.hi != 0)))
Daniel Veillard80b19092003-03-28 13:29:53 +00002929 order = -1;
William M. Brack273670f2005-03-11 15:55:14 +00002930 /*
2931 * Otherwise (y >= 0) we have the answer
2932 */
Daniel Veillard80b19092003-03-28 13:29:53 +00002933 else
2934 return (-1);
William M. Brack273670f2005-03-11 15:55:14 +00002935 /*
2936 * If x is not -ve and y is -ve we have the answer
2937 */
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002938 } else if ((y->value.decimal.sign) &&
2939 ((y->value.decimal.lo != 0) ||
2940 (y->value.decimal.mi != 0) ||
2941 (y->value.decimal.hi != 0))) {
Daniel Veillard4255d502002-04-16 15:50:10 +00002942 return (1);
Daniel Veillard80b19092003-03-28 13:29:53 +00002943 }
William M. Brack273670f2005-03-11 15:55:14 +00002944 /*
2945 * If it's not simply determined by a difference in sign,
2946 * then we need to compare the actual values of the two nums.
2947 * To do this, we start by looking at the integral parts.
2948 * If the number of integral digits differ, then we have our
2949 * answer.
2950 */
2951 integx = x->value.decimal.total - x->value.decimal.frac;
2952 integy = y->value.decimal.total - y->value.decimal.frac;
2953 if (integx > integy)
2954 return order;
2955 else if (integy > integx)
2956 return -order;
2957 /*
2958 * If the number of integral digits is the same for both numbers,
2959 * then things get a little more complicated. We need to "normalize"
2960 * the numbers in order to properly compare them. To do this, we
2961 * look at the total length of each number (length => number of
2962 * significant digits), and divide the "shorter" by 10 (decreasing
2963 * the length) until they are of equal length.
2964 */
2965 dlen = x->value.decimal.total - y->value.decimal.total;
2966 if (dlen < 0) { /* y has more digits than x */
2967 swp = x;
2968 hi = y->value.decimal.hi;
2969 mi = y->value.decimal.mi;
2970 lo = y->value.decimal.lo;
2971 dlen = -dlen;
2972 order = -order;
2973 } else { /* x has more digits than y */
2974 swp = y;
2975 hi = x->value.decimal.hi;
2976 mi = x->value.decimal.mi;
2977 lo = x->value.decimal.lo;
Daniel Veillard4255d502002-04-16 15:50:10 +00002978 }
William M. Brack273670f2005-03-11 15:55:14 +00002979 while (dlen > 8) { /* in effect, right shift by 10**8 */
2980 lo = mi;
2981 mi = hi;
2982 hi = 0;
2983 dlen -= 8;
Daniel Veillard4255d502002-04-16 15:50:10 +00002984 }
William M. Brack273670f2005-03-11 15:55:14 +00002985 while (dlen > 0) {
2986 unsigned long rem1, rem2;
2987 rem1 = (hi % 10) * 100000000L;
2988 hi = hi / 10;
2989 rem2 = (mi % 10) * 100000000L;
2990 mi = (mi + rem1) / 10;
2991 lo = (lo + rem2) / 10;
2992 dlen--;
2993 }
2994 if (hi > swp->value.decimal.hi) {
2995 return order;
2996 } else if (hi == swp->value.decimal.hi) {
2997 if (mi > swp->value.decimal.mi) {
2998 return order;
2999 } else if (mi == swp->value.decimal.mi) {
3000 if (lo > swp->value.decimal.lo) {
3001 return order;
3002 } else if (lo == swp->value.decimal.lo) {
3003 if (x->value.decimal.total == y->value.decimal.total) {
3004 return 0;
3005 } else {
3006 return order;
3007 }
3008 }
3009 }
3010 }
3011 return -order;
Daniel Veillard4255d502002-04-16 15:50:10 +00003012}
3013
3014/**
Daniel Veillard070803b2002-05-03 07:29:38 +00003015 * xmlSchemaCompareDurations:
3016 * @x: a first duration value
3017 * @y: a second duration value
3018 *
3019 * Compare 2 durations
3020 *
3021 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3022 * case of error
3023 */
3024static int
3025xmlSchemaCompareDurations(xmlSchemaValPtr x, xmlSchemaValPtr y)
3026{
3027 long carry, mon, day;
3028 double sec;
Daniel Veillard80b19092003-03-28 13:29:53 +00003029 int invert = 1;
3030 long xmon, xday, myear, minday, maxday;
Daniel Veillard070803b2002-05-03 07:29:38 +00003031 static const long dayRange [2][12] = {
3032 { 0, 28, 59, 89, 120, 150, 181, 212, 242, 273, 303, 334, },
3033 { 0, 31, 62, 92, 123, 153, 184, 215, 245, 276, 306, 337} };
3034
3035 if ((x == NULL) || (y == NULL))
Daniel Veillard5a872412002-05-22 06:40:27 +00003036 return -2;
Daniel Veillard070803b2002-05-03 07:29:38 +00003037
3038 /* months */
3039 mon = x->value.dur.mon - y->value.dur.mon;
3040
3041 /* seconds */
3042 sec = x->value.dur.sec - y->value.dur.sec;
3043 carry = (long)sec / SECS_PER_DAY;
3044 sec -= (double)(carry * SECS_PER_DAY);
3045
3046 /* days */
3047 day = x->value.dur.day - y->value.dur.day + carry;
3048
3049 /* easy test */
3050 if (mon == 0) {
3051 if (day == 0)
3052 if (sec == 0.0)
3053 return 0;
3054 else if (sec < 0.0)
3055 return -1;
3056 else
3057 return 1;
3058 else if (day < 0)
3059 return -1;
3060 else
3061 return 1;
3062 }
3063
3064 if (mon > 0) {
3065 if ((day >= 0) && (sec >= 0.0))
3066 return 1;
3067 else {
3068 xmon = mon;
3069 xday = -day;
3070 }
3071 } else if ((day <= 0) && (sec <= 0.0)) {
3072 return -1;
3073 } else {
Daniel Veillard80b19092003-03-28 13:29:53 +00003074 invert = -1;
Daniel Veillard070803b2002-05-03 07:29:38 +00003075 xmon = -mon;
3076 xday = day;
3077 }
3078
3079 myear = xmon / 12;
Daniel Veillard80b19092003-03-28 13:29:53 +00003080 if (myear == 0) {
3081 minday = 0;
3082 maxday = 0;
3083 } else {
3084 maxday = 366 * ((myear + 3) / 4) +
3085 365 * ((myear - 1) % 4);
3086 minday = maxday - 1;
3087 }
3088
Daniel Veillard070803b2002-05-03 07:29:38 +00003089 xmon = xmon % 12;
3090 minday += dayRange[0][xmon];
3091 maxday += dayRange[1][xmon];
3092
Daniel Veillard80b19092003-03-28 13:29:53 +00003093 if ((maxday == minday) && (maxday == xday))
3094 return(0); /* can this really happen ? */
Daniel Veillard070803b2002-05-03 07:29:38 +00003095 if (maxday < xday)
Daniel Veillard80b19092003-03-28 13:29:53 +00003096 return(-invert);
3097 if (minday > xday)
3098 return(invert);
Daniel Veillard070803b2002-05-03 07:29:38 +00003099
3100 /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00003101 return 2;
3102}
3103
3104/*
3105 * macros for adding date/times and durations
3106 */
3107#define FQUOTIENT(a,b) (floor(((double)a/(double)b)))
3108#define MODULO(a,b) (a - FQUOTIENT(a,b) * b)
3109#define FQUOTIENT_RANGE(a,low,high) (FQUOTIENT((a-low),(high-low)))
3110#define MODULO_RANGE(a,low,high) ((MODULO((a-low),(high-low)))+low)
3111
3112/**
Daniel Veillard669adfc2004-05-29 20:12:46 +00003113 * xmlSchemaDupVal:
3114 * @v: the #xmlSchemaValPtr value to duplicate
3115 *
3116 * Makes a copy of @v. The calling program is responsible for freeing
3117 * the returned value.
3118 *
3119 * returns a pointer to a duplicated #xmlSchemaValPtr or NULL if error.
3120 */
3121static xmlSchemaValPtr
3122xmlSchemaDupVal (xmlSchemaValPtr v)
3123{
3124 xmlSchemaValPtr ret = xmlSchemaNewValue(v->type);
3125 if (ret == NULL)
3126 return NULL;
3127
3128 memcpy(ret, v, sizeof(xmlSchemaVal));
3129 return ret;
3130}
3131
3132/**
Kasimier T. Buchcik285ebab2005-03-04 18:04:59 +00003133 * xmlSchemaCopyValue:
3134 * @val: the precomputed value to be copied
3135 *
3136 * Copies the precomputed value. This duplicates any string within.
3137 *
3138 * Returns the copy or NULL if a copy for a data-type is not implemented.
3139 */
3140xmlSchemaValPtr
3141xmlSchemaCopyValue(xmlSchemaValPtr val)
3142{
3143 xmlSchemaValPtr ret;
3144
3145 if (val == NULL)
3146 return (NULL);
3147 /*
3148 * Copy the string values.
3149 */
3150 switch (val->type) {
3151 case XML_SCHEMAS_IDREFS:
3152 case XML_SCHEMAS_ENTITIES:
3153 case XML_SCHEMAS_NMTOKENS:
3154 case XML_SCHEMAS_ANYTYPE:
3155 case XML_SCHEMAS_ANYSIMPLETYPE:
3156 return (NULL);
3157 case XML_SCHEMAS_STRING:
3158 case XML_SCHEMAS_NORMSTRING:
3159 case XML_SCHEMAS_TOKEN:
3160 case XML_SCHEMAS_LANGUAGE:
3161 case XML_SCHEMAS_NAME:
3162 case XML_SCHEMAS_NCNAME:
3163 case XML_SCHEMAS_ID:
3164 case XML_SCHEMAS_IDREF:
3165 case XML_SCHEMAS_ENTITY:
3166 case XML_SCHEMAS_NMTOKEN:
Kasimier T. Buchcik2ee855d2005-03-07 11:14:14 +00003167 case XML_SCHEMAS_ANYURI:
Kasimier T. Buchcik285ebab2005-03-04 18:04:59 +00003168 ret = xmlSchemaDupVal(val);
3169 if (val->value.str != NULL)
3170 ret->value.str = xmlStrdup(BAD_CAST val->value.str);
3171 return (ret);
Kasimier T. Buchcik2ee855d2005-03-07 11:14:14 +00003172 case XML_SCHEMAS_QNAME:
Kasimier T. Buchcik285ebab2005-03-04 18:04:59 +00003173 case XML_SCHEMAS_NOTATION:
3174 ret = xmlSchemaDupVal(val);
3175 if (val->value.qname.name != NULL)
3176 ret->value.qname.name =
3177 xmlStrdup(BAD_CAST val->value.qname.name);
3178 if (val->value.qname.uri != NULL)
3179 ret->value.qname.uri =
3180 xmlStrdup(BAD_CAST val->value.qname.uri);
3181 return (ret);
3182 case XML_SCHEMAS_HEXBINARY:
3183 ret = xmlSchemaDupVal(val);
3184 if (val->value.hex.str != NULL)
3185 ret->value.hex.str = xmlStrdup(BAD_CAST val->value.hex.str);
3186 return (ret);
3187 case XML_SCHEMAS_BASE64BINARY:
3188 ret = xmlSchemaDupVal(val);
3189 if (val->value.base64.str != NULL)
3190 ret->value.base64.str =
3191 xmlStrdup(BAD_CAST val->value.base64.str);
3192 return (ret);
3193 default:
3194 return (xmlSchemaDupVal(val));
3195 }
3196 return (NULL);
3197}
3198
3199/**
Daniel Veillard5a872412002-05-22 06:40:27 +00003200 * _xmlSchemaDateAdd:
3201 * @dt: an #xmlSchemaValPtr
3202 * @dur: an #xmlSchemaValPtr of type #XS_DURATION
3203 *
3204 * Compute a new date/time from @dt and @dur. This function assumes @dt
3205 * is either #XML_SCHEMAS_DATETIME, #XML_SCHEMAS_DATE, #XML_SCHEMAS_GYEARMONTH,
Daniel Veillard669adfc2004-05-29 20:12:46 +00003206 * or #XML_SCHEMAS_GYEAR. The returned #xmlSchemaVal is the same type as
3207 * @dt. The calling program is responsible for freeing the returned value.
Daniel Veillard5a872412002-05-22 06:40:27 +00003208 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00003209 * Returns a pointer to a new #xmlSchemaVal or NULL if error.
Daniel Veillard5a872412002-05-22 06:40:27 +00003210 */
3211static xmlSchemaValPtr
3212_xmlSchemaDateAdd (xmlSchemaValPtr dt, xmlSchemaValPtr dur)
3213{
Daniel Veillard669adfc2004-05-29 20:12:46 +00003214 xmlSchemaValPtr ret, tmp;
Daniel Veillard5a872412002-05-22 06:40:27 +00003215 long carry, tempdays, temp;
3216 xmlSchemaValDatePtr r, d;
3217 xmlSchemaValDurationPtr u;
3218
3219 if ((dt == NULL) || (dur == NULL))
3220 return NULL;
3221
3222 ret = xmlSchemaNewValue(dt->type);
3223 if (ret == NULL)
3224 return NULL;
3225
Daniel Veillard669adfc2004-05-29 20:12:46 +00003226 /* make a copy so we don't alter the original value */
3227 tmp = xmlSchemaDupVal(dt);
3228 if (tmp == NULL) {
3229 xmlSchemaFreeValue(ret);
3230 return NULL;
3231 }
3232
Daniel Veillard5a872412002-05-22 06:40:27 +00003233 r = &(ret->value.date);
Daniel Veillard669adfc2004-05-29 20:12:46 +00003234 d = &(tmp->value.date);
Daniel Veillard5a872412002-05-22 06:40:27 +00003235 u = &(dur->value.dur);
3236
3237 /* normalization */
3238 if (d->mon == 0)
3239 d->mon = 1;
3240
3241 /* normalize for time zone offset */
3242 u->sec -= (d->tzo * 60);
3243 d->tzo = 0;
3244
3245 /* normalization */
3246 if (d->day == 0)
3247 d->day = 1;
3248
3249 /* month */
3250 carry = d->mon + u->mon;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003251 r->mon = (unsigned int) MODULO_RANGE(carry, 1, 13);
3252 carry = (long) FQUOTIENT_RANGE(carry, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00003253
3254 /* year (may be modified later) */
3255 r->year = d->year + carry;
3256 if (r->year == 0) {
3257 if (d->year > 0)
3258 r->year--;
3259 else
3260 r->year++;
3261 }
3262
3263 /* time zone */
3264 r->tzo = d->tzo;
3265 r->tz_flag = d->tz_flag;
3266
3267 /* seconds */
3268 r->sec = d->sec + u->sec;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003269 carry = (long) FQUOTIENT((long)r->sec, 60);
Daniel Veillard5a872412002-05-22 06:40:27 +00003270 if (r->sec != 0.0) {
3271 r->sec = MODULO(r->sec, 60.0);
3272 }
3273
3274 /* minute */
3275 carry += d->min;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003276 r->min = (unsigned int) MODULO(carry, 60);
3277 carry = (long) FQUOTIENT(carry, 60);
Daniel Veillard5a872412002-05-22 06:40:27 +00003278
3279 /* hours */
3280 carry += d->hour;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003281 r->hour = (unsigned int) MODULO(carry, 24);
3282 carry = (long)FQUOTIENT(carry, 24);
Daniel Veillard5a872412002-05-22 06:40:27 +00003283
3284 /*
3285 * days
3286 * Note we use tempdays because the temporary values may need more
3287 * than 5 bits
3288 */
3289 if ((VALID_YEAR(r->year)) && (VALID_MONTH(r->mon)) &&
3290 (d->day > MAX_DAYINMONTH(r->year, r->mon)))
3291 tempdays = MAX_DAYINMONTH(r->year, r->mon);
3292 else if (d->day < 1)
3293 tempdays = 1;
3294 else
3295 tempdays = d->day;
3296
3297 tempdays += u->day + carry;
3298
3299 while (1) {
3300 if (tempdays < 1) {
Daniel Veillardebe25d42004-03-25 09:35:49 +00003301 long tmon = (long) MODULO_RANGE(r->mon-1, 1, 13);
3302 long tyr = r->year + (long)FQUOTIENT_RANGE(r->mon-1, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00003303 if (tyr == 0)
3304 tyr--;
3305 tempdays += MAX_DAYINMONTH(tyr, tmon);
3306 carry = -1;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003307 } else if (tempdays > (long) MAX_DAYINMONTH(r->year, r->mon)) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003308 tempdays = tempdays - MAX_DAYINMONTH(r->year, r->mon);
3309 carry = 1;
3310 } else
3311 break;
3312
3313 temp = r->mon + carry;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003314 r->mon = (unsigned int) MODULO_RANGE(temp, 1, 13);
3315 r->year = r->year + (unsigned int) FQUOTIENT_RANGE(temp, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00003316 if (r->year == 0) {
3317 if (temp < 1)
3318 r->year--;
3319 else
3320 r->year++;
3321 }
3322 }
3323
3324 r->day = tempdays;
3325
3326 /*
3327 * adjust the date/time type to the date values
3328 */
3329 if (ret->type != XML_SCHEMAS_DATETIME) {
3330 if ((r->hour) || (r->min) || (r->sec))
3331 ret->type = XML_SCHEMAS_DATETIME;
3332 else if (ret->type != XML_SCHEMAS_DATE) {
3333 if ((r->mon != 1) && (r->day != 1))
3334 ret->type = XML_SCHEMAS_DATE;
3335 else if ((ret->type != XML_SCHEMAS_GYEARMONTH) && (r->mon != 1))
3336 ret->type = XML_SCHEMAS_GYEARMONTH;
3337 }
3338 }
3339
Daniel Veillard669adfc2004-05-29 20:12:46 +00003340 xmlSchemaFreeValue(tmp);
Daniel Veillard5a872412002-05-22 06:40:27 +00003341
Daniel Veillard5a872412002-05-22 06:40:27 +00003342 return ret;
3343}
3344
3345/**
3346 * xmlSchemaDateNormalize:
Daniel Veillard669adfc2004-05-29 20:12:46 +00003347 * @dt: an #xmlSchemaValPtr of a date/time type value.
3348 * @offset: number of seconds to adjust @dt by.
Daniel Veillard5a872412002-05-22 06:40:27 +00003349 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00003350 * Normalize @dt to GMT time. The @offset parameter is subtracted from
3351 * the return value is a time-zone offset is present on @dt.
Daniel Veillard5a872412002-05-22 06:40:27 +00003352 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00003353 * Returns a normalized copy of @dt or NULL if error.
Daniel Veillard5a872412002-05-22 06:40:27 +00003354 */
3355static xmlSchemaValPtr
3356xmlSchemaDateNormalize (xmlSchemaValPtr dt, double offset)
3357{
3358 xmlSchemaValPtr dur, ret;
3359
3360 if (dt == NULL)
3361 return NULL;
3362
3363 if (((dt->type != XML_SCHEMAS_TIME) &&
3364 (dt->type != XML_SCHEMAS_DATETIME)) || (dt->value.date.tzo == 0))
3365 return xmlSchemaDupVal(dt);
3366
3367 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
3368 if (dur == NULL)
3369 return NULL;
3370
3371 dur->value.date.sec -= offset;
3372
3373 ret = _xmlSchemaDateAdd(dt, dur);
3374 if (ret == NULL)
3375 return NULL;
3376
3377 xmlSchemaFreeValue(dur);
3378
3379 /* ret->value.date.tzo = 0; */
3380 return ret;
3381}
3382
3383/**
3384 * _xmlSchemaDateCastYMToDays:
3385 * @dt: an #xmlSchemaValPtr
3386 *
3387 * Convert mon and year of @dt to total number of days. Take the
3388 * number of years since (or before) 1 AD and add the number of leap
3389 * years. This is a function because negative
3390 * years must be handled a little differently and there is no zero year.
3391 *
3392 * Returns number of days.
3393 */
3394static long
3395_xmlSchemaDateCastYMToDays (const xmlSchemaValPtr dt)
3396{
3397 long ret;
Daniel Veillard49e89632004-09-23 16:24:36 +00003398 int mon;
Daniel Veillard5a872412002-05-22 06:40:27 +00003399
Daniel Veillard49e89632004-09-23 16:24:36 +00003400 mon = dt->value.date.mon;
3401 if (mon <= 0) mon = 1; /* normalization */
3402
3403 if (dt->value.date.year <= 0)
Daniel Veillard5a872412002-05-22 06:40:27 +00003404 ret = (dt->value.date.year * 365) +
3405 (((dt->value.date.year+1)/4)-((dt->value.date.year+1)/100)+
3406 ((dt->value.date.year+1)/400)) +
Daniel Veillard49e89632004-09-23 16:24:36 +00003407 DAY_IN_YEAR(0, mon, dt->value.date.year);
Daniel Veillard5a872412002-05-22 06:40:27 +00003408 else
3409 ret = ((dt->value.date.year-1) * 365) +
3410 (((dt->value.date.year-1)/4)-((dt->value.date.year-1)/100)+
3411 ((dt->value.date.year-1)/400)) +
Daniel Veillard49e89632004-09-23 16:24:36 +00003412 DAY_IN_YEAR(0, mon, dt->value.date.year);
Daniel Veillard5a872412002-05-22 06:40:27 +00003413
3414 return ret;
3415}
3416
3417/**
3418 * TIME_TO_NUMBER:
3419 * @dt: an #xmlSchemaValPtr
3420 *
3421 * Calculates the number of seconds in the time portion of @dt.
3422 *
3423 * Returns seconds.
3424 */
3425#define TIME_TO_NUMBER(dt) \
3426 ((double)((dt->value.date.hour * SECS_PER_HOUR) + \
Daniel Veillardb3721c22003-03-31 11:22:25 +00003427 (dt->value.date.min * SECS_PER_MIN) + \
3428 (dt->value.date.tzo * SECS_PER_MIN)) + \
3429 dt->value.date.sec)
Daniel Veillard5a872412002-05-22 06:40:27 +00003430
3431/**
3432 * xmlSchemaCompareDates:
3433 * @x: a first date/time value
3434 * @y: a second date/time value
3435 *
3436 * Compare 2 date/times
3437 *
3438 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3439 * case of error
3440 */
3441static int
3442xmlSchemaCompareDates (xmlSchemaValPtr x, xmlSchemaValPtr y)
3443{
3444 unsigned char xmask, ymask, xor_mask, and_mask;
3445 xmlSchemaValPtr p1, p2, q1, q2;
3446 long p1d, p2d, q1d, q2d;
3447
3448 if ((x == NULL) || (y == NULL))
3449 return -2;
3450
3451 if (x->value.date.tz_flag) {
3452
3453 if (!y->value.date.tz_flag) {
3454 p1 = xmlSchemaDateNormalize(x, 0);
3455 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3456 /* normalize y + 14:00 */
3457 q1 = xmlSchemaDateNormalize(y, (14 * SECS_PER_HOUR));
3458
3459 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003460 if (p1d < q1d) {
3461 xmlSchemaFreeValue(p1);
3462 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003463 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003464 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003465 double sec;
3466
3467 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00003468 if (sec < 0.0) {
3469 xmlSchemaFreeValue(p1);
3470 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003471 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003472 } else {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003473 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003474 /* normalize y - 14:00 */
3475 q2 = xmlSchemaDateNormalize(y, -(14 * SECS_PER_HOUR));
3476 q2d = _xmlSchemaDateCastYMToDays(q2) + q2->value.date.day;
3477 if (p1d > q2d)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003478 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003479 else if (p1d == q2d) {
3480 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q2);
3481 if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003482 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003483 else
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003484 ret = 2; /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00003485 }
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003486 xmlSchemaFreeValue(p1);
3487 xmlSchemaFreeValue(q1);
3488 xmlSchemaFreeValue(q2);
3489 if (ret != 0)
3490 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003491 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00003492 } else {
3493 xmlSchemaFreeValue(p1);
3494 xmlSchemaFreeValue(q1);
3495 }
Daniel Veillard5a872412002-05-22 06:40:27 +00003496 }
3497 } else if (y->value.date.tz_flag) {
3498 q1 = xmlSchemaDateNormalize(y, 0);
3499 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
3500
3501 /* normalize x - 14:00 */
3502 p1 = xmlSchemaDateNormalize(x, -(14 * SECS_PER_HOUR));
3503 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3504
Daniel Veillardfdc91562002-07-01 21:52:03 +00003505 if (p1d < q1d) {
3506 xmlSchemaFreeValue(p1);
3507 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003508 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003509 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003510 double sec;
3511
3512 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00003513 if (sec < 0.0) {
3514 xmlSchemaFreeValue(p1);
3515 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003516 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003517 } else {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003518 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003519 /* normalize x + 14:00 */
3520 p2 = xmlSchemaDateNormalize(x, (14 * SECS_PER_HOUR));
3521 p2d = _xmlSchemaDateCastYMToDays(p2) + p2->value.date.day;
3522
Daniel Veillard6560a422003-03-27 21:25:38 +00003523 if (p2d > q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003524 ret = 1;
Daniel Veillard6560a422003-03-27 21:25:38 +00003525 } else if (p2d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003526 sec = TIME_TO_NUMBER(p2) - TIME_TO_NUMBER(q1);
3527 if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003528 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003529 else
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003530 ret = 2; /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00003531 }
Daniel Veillard6560a422003-03-27 21:25:38 +00003532 xmlSchemaFreeValue(p1);
3533 xmlSchemaFreeValue(q1);
3534 xmlSchemaFreeValue(p2);
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003535 if (ret != 0)
3536 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003537 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00003538 } else {
3539 xmlSchemaFreeValue(p1);
3540 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003541 }
3542 }
3543
3544 /*
3545 * if the same type then calculate the difference
3546 */
3547 if (x->type == y->type) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003548 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003549 q1 = xmlSchemaDateNormalize(y, 0);
3550 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
3551
3552 p1 = xmlSchemaDateNormalize(x, 0);
3553 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3554
Daniel Veillardfdc91562002-07-01 21:52:03 +00003555 if (p1d < q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003556 ret = -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003557 } else if (p1d > q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003558 ret = 1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003559 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00003560 double sec;
3561
3562 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
3563 if (sec < 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003564 ret = -1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003565 else if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003566 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003567
3568 }
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003569 xmlSchemaFreeValue(p1);
3570 xmlSchemaFreeValue(q1);
3571 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003572 }
3573
3574 switch (x->type) {
3575 case XML_SCHEMAS_DATETIME:
3576 xmask = 0xf;
3577 break;
3578 case XML_SCHEMAS_DATE:
3579 xmask = 0x7;
3580 break;
3581 case XML_SCHEMAS_GYEAR:
3582 xmask = 0x1;
3583 break;
3584 case XML_SCHEMAS_GMONTH:
3585 xmask = 0x2;
3586 break;
3587 case XML_SCHEMAS_GDAY:
3588 xmask = 0x3;
3589 break;
3590 case XML_SCHEMAS_GYEARMONTH:
3591 xmask = 0x3;
3592 break;
3593 case XML_SCHEMAS_GMONTHDAY:
3594 xmask = 0x6;
3595 break;
3596 case XML_SCHEMAS_TIME:
3597 xmask = 0x8;
3598 break;
3599 default:
3600 xmask = 0;
3601 break;
3602 }
3603
3604 switch (y->type) {
3605 case XML_SCHEMAS_DATETIME:
3606 ymask = 0xf;
3607 break;
3608 case XML_SCHEMAS_DATE:
3609 ymask = 0x7;
3610 break;
3611 case XML_SCHEMAS_GYEAR:
3612 ymask = 0x1;
3613 break;
3614 case XML_SCHEMAS_GMONTH:
3615 ymask = 0x2;
3616 break;
3617 case XML_SCHEMAS_GDAY:
3618 ymask = 0x3;
3619 break;
3620 case XML_SCHEMAS_GYEARMONTH:
3621 ymask = 0x3;
3622 break;
3623 case XML_SCHEMAS_GMONTHDAY:
3624 ymask = 0x6;
3625 break;
3626 case XML_SCHEMAS_TIME:
3627 ymask = 0x8;
3628 break;
3629 default:
3630 ymask = 0;
3631 break;
3632 }
3633
3634 xor_mask = xmask ^ ymask; /* mark type differences */
3635 and_mask = xmask & ymask; /* mark field specification */
3636
3637 /* year */
3638 if (xor_mask & 1)
3639 return 2; /* indeterminate */
3640 else if (and_mask & 1) {
3641 if (x->value.date.year < y->value.date.year)
3642 return -1;
3643 else if (x->value.date.year > y->value.date.year)
3644 return 1;
3645 }
3646
3647 /* month */
3648 if (xor_mask & 2)
3649 return 2; /* indeterminate */
3650 else if (and_mask & 2) {
3651 if (x->value.date.mon < y->value.date.mon)
3652 return -1;
3653 else if (x->value.date.mon > y->value.date.mon)
3654 return 1;
3655 }
3656
3657 /* day */
3658 if (xor_mask & 4)
3659 return 2; /* indeterminate */
3660 else if (and_mask & 4) {
3661 if (x->value.date.day < y->value.date.day)
3662 return -1;
3663 else if (x->value.date.day > y->value.date.day)
3664 return 1;
3665 }
3666
3667 /* time */
3668 if (xor_mask & 8)
3669 return 2; /* indeterminate */
3670 else if (and_mask & 8) {
3671 if (x->value.date.hour < y->value.date.hour)
3672 return -1;
3673 else if (x->value.date.hour > y->value.date.hour)
3674 return 1;
3675 else if (x->value.date.min < y->value.date.min)
3676 return -1;
3677 else if (x->value.date.min > y->value.date.min)
3678 return 1;
3679 else if (x->value.date.sec < y->value.date.sec)
3680 return -1;
3681 else if (x->value.date.sec > y->value.date.sec)
3682 return 1;
3683 }
3684
Daniel Veillard070803b2002-05-03 07:29:38 +00003685 return 0;
3686}
3687
3688/**
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003689 * xmlSchemaComparePreserveReplaceStrings:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003690 * @xv: a first string value
3691 * @yv: a second string value
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003692 * @invert: inverts the result if x < y or x > y.
3693 *
3694 * Compare 2 string for their normalized values.
3695 * @x is a string with whitespace of "preserve", @y is
3696 * a string with a whitespace of "replace". I.e. @x could
3697 * be an "xsd:string" and @y an "xsd:normalizedString".
3698 *
3699 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
3700 * case of error
3701 */
3702static int
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003703xmlSchemaComparePreserveReplaceStrings(const xmlChar *xv,
3704 const xmlChar *yv,
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003705 int invert)
3706{
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003707 int tmp;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003708
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003709 while ((*xv != 0) && (*yv != 0)) {
3710 if (IS_WSP_REPLACE_CH(*yv)) {
3711 if (! IS_WSP_SPACE_CH(*xv)) {
3712 if ((*xv - 0x20) < 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003713 if (invert)
3714 return(1);
3715 else
3716 return(-1);
3717 } else {
3718 if (invert)
3719 return(-1);
3720 else
3721 return(1);
3722 }
3723 }
3724 } else {
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003725 tmp = *xv - *yv;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003726 if (tmp < 0) {
3727 if (invert)
3728 return(1);
3729 else
3730 return(-1);
3731 }
3732 if (tmp > 0) {
3733 if (invert)
3734 return(-1);
3735 else
3736 return(1);
3737 }
3738 }
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003739 xv++;
3740 yv++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003741 }
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003742 if (*xv != 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003743 if (invert)
3744 return(-1);
3745 else
3746 return(1);
3747 }
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003748 if (*yv != 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003749 if (invert)
3750 return(1);
3751 else
3752 return(-1);
3753 }
3754 return(0);
3755}
3756
3757/**
3758 * xmlSchemaComparePreserveCollapseStrings:
3759 * @x: a first string value
3760 * @y: a second string value
3761 *
3762 * Compare 2 string for their normalized values.
3763 * @x is a string with whitespace of "preserve", @y is
3764 * a string with a whitespace of "collapse". I.e. @x could
3765 * be an "xsd:string" and @y an "xsd:normalizedString".
3766 *
3767 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
3768 * case of error
3769 */
3770static int
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003771xmlSchemaComparePreserveCollapseStrings(const xmlChar *xv,
3772 const xmlChar *yv,
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003773 int invert)
3774{
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003775 int tmp;
3776
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003777 /*
3778 * Skip leading blank chars of the collapsed string.
3779 */
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003780 while (IS_WSP_SPACE_CH(*yv) || IS_WSP_REPLACE_CH(*yv))
3781 yv++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003782
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003783 while ((*xv != 0) && (*yv != 0)) {
3784 if (IS_WSP_SPACE_CH(*yv) || IS_WSP_REPLACE_CH(*yv)) {
3785 if (! IS_WSP_SPACE_CH(*xv)) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003786 /*
3787 * The utf2 character would have been replaced to 0x20.
3788 */
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003789 if ((*xv - 0x20) < 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003790 if (invert)
3791 return(1);
3792 else
3793 return(-1);
3794 } else {
3795 if (invert)
3796 return(-1);
3797 else
3798 return(1);
3799 }
3800 }
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003801 xv++;
3802 yv++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003803 /*
3804 * Skip contiguous blank chars of the collapsed string.
3805 */
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003806 while (IS_WSP_SPACE_CH(*yv) || IS_WSP_REPLACE_CH(*yv))
3807 yv++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003808 } else {
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003809 tmp = *xv++ - *yv++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003810 if (tmp < 0) {
3811 if (invert)
3812 return(1);
3813 else
3814 return(-1);
3815 }
3816 if (tmp > 0) {
3817 if (invert)
3818 return(-1);
3819 else
3820 return(1);
3821 }
3822 }
3823 }
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003824 if (*xv != 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003825 if (invert)
3826 return(-1);
3827 else
3828 return(1);
3829 }
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003830 if (*yv != 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003831 /*
3832 * Skip trailing blank chars of the collapsed string.
3833 */
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003834 while (IS_WSP_SPACE_CH(*yv) || IS_WSP_REPLACE_CH(*yv))
3835 yv++;
3836 if (*yv != 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003837 if (invert)
3838 return(1);
3839 else
3840 return(-1);
3841 }
3842 }
3843 return(0);
3844}
3845
3846/**
3847 * xmlSchemaComparePreserveCollapseStrings:
3848 * @x: a first string value
3849 * @y: a second string value
3850 *
3851 * Compare 2 string for their normalized values.
3852 * @x is a string with whitespace of "preserve", @y is
3853 * a string with a whitespace of "collapse". I.e. @x could
3854 * be an "xsd:string" and @y an "xsd:normalizedString".
3855 *
3856 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
3857 * case of error
3858 */
3859static int
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003860xmlSchemaCompareReplaceCollapseStrings(const xmlChar *xv,
3861 const xmlChar *yv,
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003862 int invert)
3863{
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003864 int tmp;
3865
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003866 /*
3867 * Skip leading blank chars of the collapsed string.
3868 */
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003869 while (IS_WSP_SPACE_CH(*yv) || IS_WSP_REPLACE_CH(*yv))
3870 yv++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003871
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003872 while ((*xv != 0) && (*yv != 0)) {
3873 if (IS_WSP_SPACE_CH(*yv) || IS_WSP_REPLACE_CH(*yv)) {
3874 if (! (IS_WSP_SPACE_CH(*xv) || IS_WSP_REPLACE_CH(*xv))) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003875 /*
3876 * The utf2 character would have been replaced to 0x20.
3877 */
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003878 if ((*xv - 0x20) < 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003879 if (invert)
3880 return(1);
3881 else
3882 return(-1);
3883 } else {
3884 if (invert)
3885 return(-1);
3886 else
3887 return(1);
3888 }
3889 }
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003890 xv++;
3891 yv++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003892 /*
3893 * Skip contiguous blank chars of the collapsed string.
3894 */
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003895 while (IS_WSP_SPACE_CH(*yv) || IS_WSP_REPLACE_CH(*yv))
3896 yv++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003897 } else {
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003898 if (IS_WSP_SPACE_CH(*xv) || IS_WSP_REPLACE_CH(*xv)) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003899 /*
3900 * The utf1 character would have been replaced to 0x20.
3901 */
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003902 if ((0x20 - *yv) < 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003903 if (invert)
3904 return(1);
3905 else
3906 return(-1);
3907 } else {
3908 if (invert)
3909 return(-1);
3910 else
3911 return(1);
3912 }
3913 }
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003914 tmp = *xv++ - *yv++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003915 if (tmp < 0)
3916 return(-1);
3917 if (tmp > 0)
3918 return(1);
3919 }
3920 }
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003921 if (*xv != 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003922 if (invert)
3923 return(-1);
3924 else
3925 return(1);
3926 }
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003927 if (*yv != 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003928 /*
3929 * Skip trailing blank chars of the collapsed string.
3930 */
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003931 while (IS_WSP_SPACE_CH(*yv) || IS_WSP_REPLACE_CH(*yv))
3932 yv++;
3933 if (*yv != 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003934 if (invert)
3935 return(1);
3936 else
3937 return(-1);
3938 }
3939 }
3940 return(0);
3941}
3942
3943
3944/**
3945 * xmlSchemaCompareReplacedStrings:
3946 * @x: a first string value
3947 * @y: a second string value
3948 *
3949 * Compare 2 string for their normalized values.
3950 *
3951 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
3952 * case of error
3953 */
3954static int
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003955xmlSchemaCompareReplacedStrings(const xmlChar *xv,
3956 const xmlChar *yv)
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003957{
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003958 int tmp;
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003959
3960 while ((*xv != 0) && (*yv != 0)) {
3961 if (IS_WSP_SPACE_CH(*yv) || IS_WSP_REPLACE_CH(*yv)) {
3962 if (! (IS_WSP_SPACE_CH(*xv) || IS_WSP_REPLACE_CH(*xv))) {
3963 if ((*xv - 0x20) < 0)
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003964 return(-1);
3965 else
3966 return(1);
3967 }
3968 } else {
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003969 if (IS_WSP_SPACE_CH(*xv) || IS_WSP_REPLACE_CH(*xv)) {
3970 if ((0x20 - *yv) < 0)
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003971 return(-1);
3972 else
3973 return(1);
3974 }
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003975 tmp = *xv - *yv;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003976 if (tmp < 0)
3977 return(-1);
3978 if (tmp > 0)
3979 return(1);
3980 }
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003981 xv++;
3982 yv++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003983 }
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003984 if (*xv != 0)
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003985 return(1);
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003986 if (*yv != 0)
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003987 return(-1);
3988 return(0);
3989}
3990
3991/**
Daniel Veillardc4c21552003-03-29 10:53:38 +00003992 * xmlSchemaCompareNormStrings:
3993 * @x: a first string value
3994 * @y: a second string value
3995 *
3996 * Compare 2 string for their normalized values.
3997 *
3998 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
3999 * case of error
4000 */
4001static int
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004002xmlSchemaCompareNormStrings(const xmlChar *xv,
4003 const xmlChar *yv) {
Daniel Veillardc4c21552003-03-29 10:53:38 +00004004 int tmp;
Daniel Veillardc4c21552003-03-29 10:53:38 +00004005
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004006 while (IS_BLANK_CH(*xv)) xv++;
4007 while (IS_BLANK_CH(*yv)) yv++;
4008 while ((*xv != 0) && (*yv != 0)) {
4009 if (IS_BLANK_CH(*xv)) {
4010 if (!IS_BLANK_CH(*yv)) {
4011 tmp = *xv - *yv;
Daniel Veillardc4c21552003-03-29 10:53:38 +00004012 return(tmp);
4013 }
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004014 while (IS_BLANK_CH(*xv)) xv++;
4015 while (IS_BLANK_CH(*yv)) yv++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00004016 } else {
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004017 tmp = *xv++ - *yv++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00004018 if (tmp < 0)
4019 return(-1);
4020 if (tmp > 0)
4021 return(1);
4022 }
4023 }
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004024 if (*xv != 0) {
4025 while (IS_BLANK_CH(*xv)) xv++;
4026 if (*xv != 0)
Daniel Veillardc4c21552003-03-29 10:53:38 +00004027 return(1);
4028 }
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004029 if (*yv != 0) {
4030 while (IS_BLANK_CH(*yv)) yv++;
4031 if (*yv != 0)
Daniel Veillardc4c21552003-03-29 10:53:38 +00004032 return(-1);
4033 }
4034 return(0);
4035}
4036
4037/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00004038 * xmlSchemaCompareFloats:
4039 * @x: a first float or double value
4040 * @y: a second float or double value
4041 *
4042 * Compare 2 values
4043 *
4044 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
4045 * case of error
4046 */
4047static int
4048xmlSchemaCompareFloats(xmlSchemaValPtr x, xmlSchemaValPtr y) {
4049 double d1, d2;
4050
4051 if ((x == NULL) || (y == NULL))
4052 return(-2);
4053
4054 /*
4055 * Cast everything to doubles.
4056 */
4057 if (x->type == XML_SCHEMAS_DOUBLE)
4058 d1 = x->value.d;
4059 else if (x->type == XML_SCHEMAS_FLOAT)
4060 d1 = x->value.f;
4061 else
4062 return(-2);
4063
4064 if (y->type == XML_SCHEMAS_DOUBLE)
4065 d2 = y->value.d;
4066 else if (y->type == XML_SCHEMAS_FLOAT)
4067 d2 = y->value.f;
4068 else
4069 return(-2);
4070
4071 /*
4072 * Check for special cases.
4073 */
4074 if (xmlXPathIsNaN(d1)) {
4075 if (xmlXPathIsNaN(d2))
4076 return(0);
4077 return(1);
4078 }
4079 if (xmlXPathIsNaN(d2))
4080 return(-1);
4081 if (d1 == xmlXPathPINF) {
4082 if (d2 == xmlXPathPINF)
4083 return(0);
4084 return(1);
4085 }
4086 if (d2 == xmlXPathPINF)
4087 return(-1);
4088 if (d1 == xmlXPathNINF) {
4089 if (d2 == xmlXPathNINF)
4090 return(0);
4091 return(-1);
4092 }
4093 if (d2 == xmlXPathNINF)
4094 return(1);
4095
4096 /*
4097 * basic tests, the last one we should have equality, but
4098 * portability is more important than speed and handling
4099 * NaN or Inf in a portable way is always a challenge, so ...
4100 */
4101 if (d1 < d2)
4102 return(-1);
4103 if (d1 > d2)
4104 return(1);
4105 if (d1 == d2)
4106 return(0);
4107 return(2);
4108}
4109
4110/**
Daniel Veillard4255d502002-04-16 15:50:10 +00004111 * xmlSchemaCompareValues:
4112 * @x: a first value
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004113 * @xvalue: the first value as a string (optional)
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004114 * @xwtsp: the whitespace type
Daniel Veillard4255d502002-04-16 15:50:10 +00004115 * @y: a second value
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004116 * @xvalue: the second value as a string (optional)
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004117 * @ywtsp: the whitespace type
Daniel Veillard4255d502002-04-16 15:50:10 +00004118 *
4119 * Compare 2 values
4120 *
Daniel Veillard5a872412002-05-22 06:40:27 +00004121 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
4122 * case of error
Daniel Veillard4255d502002-04-16 15:50:10 +00004123 */
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004124static int
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004125xmlSchemaCompareValuesInternal(xmlSchemaValType xtype,
4126 xmlSchemaValPtr x,
4127 const xmlChar *xvalue,
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004128 xmlSchemaWhitespaceValueType xws,
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004129 xmlSchemaValType ytype,
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004130 xmlSchemaValPtr y,
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004131 const xmlChar *yvalue,
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004132 xmlSchemaWhitespaceValueType yws) {
Daniel Veillard4255d502002-04-16 15:50:10 +00004133 if ((x == NULL) || (y == NULL))
4134 return(-2);
4135
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004136 switch (xtype) {
Daniel Veillard80b19092003-03-28 13:29:53 +00004137 case XML_SCHEMAS_UNKNOWN:
William M. Brack2f2a6632004-08-20 23:09:47 +00004138 case XML_SCHEMAS_ANYTYPE:
Daniel Veillard80b19092003-03-28 13:29:53 +00004139 return(-2);
4140 case XML_SCHEMAS_INTEGER:
4141 case XML_SCHEMAS_NPINTEGER:
4142 case XML_SCHEMAS_NINTEGER:
4143 case XML_SCHEMAS_NNINTEGER:
4144 case XML_SCHEMAS_PINTEGER:
4145 case XML_SCHEMAS_INT:
4146 case XML_SCHEMAS_UINT:
4147 case XML_SCHEMAS_LONG:
4148 case XML_SCHEMAS_ULONG:
4149 case XML_SCHEMAS_SHORT:
4150 case XML_SCHEMAS_USHORT:
4151 case XML_SCHEMAS_BYTE:
4152 case XML_SCHEMAS_UBYTE:
Daniel Veillard4255d502002-04-16 15:50:10 +00004153 case XML_SCHEMAS_DECIMAL:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004154 if ((x == NULL) || (y == NULL))
4155 return(-2);
4156 if (ytype == xtype)
Daniel Veillard80b19092003-03-28 13:29:53 +00004157 return(xmlSchemaCompareDecimals(x, y));
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004158 if ((ytype == XML_SCHEMAS_DECIMAL) ||
4159 (ytype == XML_SCHEMAS_INTEGER) ||
4160 (ytype == XML_SCHEMAS_NPINTEGER) ||
4161 (ytype == XML_SCHEMAS_NINTEGER) ||
4162 (ytype == XML_SCHEMAS_NNINTEGER) ||
4163 (ytype == XML_SCHEMAS_PINTEGER) ||
4164 (ytype == XML_SCHEMAS_INT) ||
4165 (ytype == XML_SCHEMAS_UINT) ||
4166 (ytype == XML_SCHEMAS_LONG) ||
4167 (ytype == XML_SCHEMAS_ULONG) ||
4168 (ytype == XML_SCHEMAS_SHORT) ||
4169 (ytype == XML_SCHEMAS_USHORT) ||
4170 (ytype == XML_SCHEMAS_BYTE) ||
4171 (ytype == XML_SCHEMAS_UBYTE))
Daniel Veillard4255d502002-04-16 15:50:10 +00004172 return(xmlSchemaCompareDecimals(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00004173 return(-2);
Daniel Veillard070803b2002-05-03 07:29:38 +00004174 case XML_SCHEMAS_DURATION:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004175 if ((x == NULL) || (y == NULL))
4176 return(-2);
Daniel Veillard070803b2002-05-03 07:29:38 +00004177 if (y->type == XML_SCHEMAS_DURATION)
4178 return(xmlSchemaCompareDurations(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00004179 return(-2);
4180 case XML_SCHEMAS_TIME:
4181 case XML_SCHEMAS_GDAY:
4182 case XML_SCHEMAS_GMONTH:
4183 case XML_SCHEMAS_GMONTHDAY:
4184 case XML_SCHEMAS_GYEAR:
4185 case XML_SCHEMAS_GYEARMONTH:
4186 case XML_SCHEMAS_DATE:
4187 case XML_SCHEMAS_DATETIME:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004188 if ((x == NULL) || (y == NULL))
4189 return(-2);
4190 if ((ytype == XML_SCHEMAS_DATETIME) ||
4191 (ytype == XML_SCHEMAS_TIME) ||
4192 (ytype == XML_SCHEMAS_GDAY) ||
4193 (ytype == XML_SCHEMAS_GMONTH) ||
4194 (ytype == XML_SCHEMAS_GMONTHDAY) ||
4195 (ytype == XML_SCHEMAS_GYEAR) ||
4196 (ytype == XML_SCHEMAS_DATE) ||
4197 (ytype == XML_SCHEMAS_GYEARMONTH))
Daniel Veillard5a872412002-05-22 06:40:27 +00004198 return (xmlSchemaCompareDates(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00004199 return (-2);
Kasimier T. Buchcik2ee855d2005-03-07 11:14:14 +00004200 /*
4201 * Note that we will support comparison of string types against
4202 * anySimpleType as well.
4203 */
4204 case XML_SCHEMAS_ANYSIMPLETYPE:
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004205 case XML_SCHEMAS_STRING:
4206 case XML_SCHEMAS_NORMSTRING:
Daniel Veillard80b19092003-03-28 13:29:53 +00004207 case XML_SCHEMAS_TOKEN:
4208 case XML_SCHEMAS_LANGUAGE:
4209 case XML_SCHEMAS_NMTOKEN:
Daniel Veillard80b19092003-03-28 13:29:53 +00004210 case XML_SCHEMAS_NAME:
Daniel Veillard80b19092003-03-28 13:29:53 +00004211 case XML_SCHEMAS_NCNAME:
4212 case XML_SCHEMAS_ID:
4213 case XML_SCHEMAS_IDREF:
Daniel Veillard80b19092003-03-28 13:29:53 +00004214 case XML_SCHEMAS_ENTITY:
Daniel Veillard80b19092003-03-28 13:29:53 +00004215 case XML_SCHEMAS_NOTATION:
4216 case XML_SCHEMAS_ANYURI:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004217 {
4218 const xmlChar *xv, *yv;
4219
4220 if (x == NULL)
4221 xv = xvalue;
4222 else
4223 xv = x->value.str;
4224 if (y == NULL)
4225 yv = yvalue;
4226 else
4227 yv = y->value.str;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004228 /*
4229 * TODO: Compare those against QName.
4230 */
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004231 if (ytype == XML_SCHEMAS_QNAME) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004232 TODO
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004233 if (y == NULL)
4234 return(-2);
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004235 return (-2);
4236 }
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004237 if ((ytype == XML_SCHEMAS_ANYSIMPLETYPE) ||
4238 (ytype == XML_SCHEMAS_STRING) ||
4239 (ytype == XML_SCHEMAS_NORMSTRING) ||
4240 (ytype == XML_SCHEMAS_TOKEN) ||
4241 (ytype == XML_SCHEMAS_LANGUAGE) ||
4242 (ytype == XML_SCHEMAS_NMTOKEN) ||
4243 (ytype == XML_SCHEMAS_NAME) ||
4244 (ytype == XML_SCHEMAS_NCNAME) ||
4245 (ytype == XML_SCHEMAS_ID) ||
4246 (ytype == XML_SCHEMAS_IDREF) ||
4247 (ytype == XML_SCHEMAS_ENTITY) ||
4248 (ytype == XML_SCHEMAS_NOTATION) ||
4249 (ytype == XML_SCHEMAS_ANYURI)) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004250
4251 if (xws == XML_SCHEMA_WHITESPACE_PRESERVE) {
4252
4253 if (yws == XML_SCHEMA_WHITESPACE_PRESERVE) {
4254 /* TODO: What about x < y or x > y. */
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004255 if (xmlStrEqual(xv, yv))
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004256 return (0);
4257 else
4258 return (2);
4259 } else if (yws == XML_SCHEMA_WHITESPACE_REPLACE)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004260 return (xmlSchemaComparePreserveReplaceStrings(xv, yv, 0));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004261 else if (yws == XML_SCHEMA_WHITESPACE_COLLAPSE)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004262 return (xmlSchemaComparePreserveCollapseStrings(xv, yv, 0));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004263
4264 } else if (xws == XML_SCHEMA_WHITESPACE_REPLACE) {
4265
4266 if (yws == XML_SCHEMA_WHITESPACE_PRESERVE)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004267 return (xmlSchemaComparePreserveReplaceStrings(yv, xv, 1));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004268 if (yws == XML_SCHEMA_WHITESPACE_REPLACE)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004269 return (xmlSchemaCompareReplacedStrings(xv, yv));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004270 if (yws == XML_SCHEMA_WHITESPACE_COLLAPSE)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004271 return (xmlSchemaCompareReplaceCollapseStrings(xv, yv, 0));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004272
4273 } else if (xws == XML_SCHEMA_WHITESPACE_COLLAPSE) {
4274
4275 if (yws == XML_SCHEMA_WHITESPACE_PRESERVE)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004276 return (xmlSchemaComparePreserveCollapseStrings(yv, xv, 1));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004277 if (yws == XML_SCHEMA_WHITESPACE_REPLACE)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004278 return (xmlSchemaCompareReplaceCollapseStrings(yv, xv, 1));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004279 if (yws == XML_SCHEMA_WHITESPACE_COLLAPSE)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004280 return (xmlSchemaCompareNormStrings(xv, yv));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004281 } else
4282 return (-2);
4283
4284 }
Daniel Veillardc4c21552003-03-29 10:53:38 +00004285 return (-2);
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004286 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004287 case XML_SCHEMAS_QNAME:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004288 if ((x == NULL) || (y == NULL))
4289 return(-2);
4290 if (ytype == XML_SCHEMAS_QNAME) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004291 if ((xmlStrEqual(x->value.qname.name, y->value.qname.name)) &&
4292 (xmlStrEqual(x->value.qname.uri, y->value.qname.uri)))
4293 return(0);
4294 return(2);
4295 }
4296 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00004297 case XML_SCHEMAS_FLOAT:
4298 case XML_SCHEMAS_DOUBLE:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004299 if ((x == NULL) || (y == NULL))
4300 return(-2);
4301 if ((ytype == XML_SCHEMAS_FLOAT) ||
4302 (ytype == XML_SCHEMAS_DOUBLE))
Daniel Veillardb6c7f412003-03-29 16:41:55 +00004303 return (xmlSchemaCompareFloats(x, y));
4304 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00004305 case XML_SCHEMAS_BOOLEAN:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004306 if ((x == NULL) || (y == NULL))
4307 return(-2);
4308 if (ytype == XML_SCHEMAS_BOOLEAN) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00004309 if (x->value.b == y->value.b)
4310 return(0);
4311 if (x->value.b == 0)
4312 return(-1);
4313 return(1);
4314 }
4315 return (-2);
Daniel Veillard560c2a42003-07-06 21:13:49 +00004316 case XML_SCHEMAS_HEXBINARY:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004317 if ((x == NULL) || (y == NULL))
4318 return(-2);
4319 if (ytype == XML_SCHEMAS_HEXBINARY) {
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004320 if (x->value.hex.total == y->value.hex.total) {
4321 int ret = xmlStrcmp(x->value.hex.str, y->value.hex.str);
4322 if (ret > 0)
4323 return(1);
4324 else if (ret == 0)
4325 return(0);
4326 }
4327 else if (x->value.hex.total > y->value.hex.total)
4328 return(1);
4329
4330 return(-1);
4331 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00004332 return (-2);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00004333 case XML_SCHEMAS_BASE64BINARY:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004334 if ((x == NULL) || (y == NULL))
4335 return(-2);
4336 if (ytype == XML_SCHEMAS_BASE64BINARY) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00004337 if (x->value.base64.total == y->value.base64.total) {
4338 int ret = xmlStrcmp(x->value.base64.str,
4339 y->value.base64.str);
4340 if (ret > 0)
4341 return(1);
4342 else if (ret == 0)
4343 return(0);
4344 }
4345 else if (x->value.base64.total > y->value.base64.total)
4346 return(1);
4347 else
4348 return(-1);
4349 }
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004350 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00004351 case XML_SCHEMAS_IDREFS:
4352 case XML_SCHEMAS_ENTITIES:
4353 case XML_SCHEMAS_NMTOKENS:
4354 TODO
4355 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00004356 }
Daniel Veillard5a872412002-05-22 06:40:27 +00004357 return -2;
Daniel Veillard4255d502002-04-16 15:50:10 +00004358}
4359
4360/**
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004361 * xmlSchemaCompareValues:
4362 * @x: a first value
4363 * @y: a second value
4364 *
4365 * Compare 2 values
4366 *
4367 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
4368 * case of error
4369 */
4370int
4371xmlSchemaCompareValues(xmlSchemaValPtr x, xmlSchemaValPtr y) {
4372 xmlSchemaWhitespaceValueType xws, yws;
4373
Daniel Veillard5e094142005-02-18 19:36:12 +00004374 if ((x == NULL) || (y == NULL))
4375 return(-2);
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004376 if (x->type == XML_SCHEMAS_STRING)
4377 xws = XML_SCHEMA_WHITESPACE_PRESERVE;
4378 else if (x->type == XML_SCHEMAS_NORMSTRING)
4379 xws = XML_SCHEMA_WHITESPACE_REPLACE;
4380 else
4381 xws = XML_SCHEMA_WHITESPACE_COLLAPSE;
4382
4383 if (y->type == XML_SCHEMAS_STRING)
4384 yws = XML_SCHEMA_WHITESPACE_PRESERVE;
4385 else if (x->type == XML_SCHEMAS_NORMSTRING)
4386 yws = XML_SCHEMA_WHITESPACE_REPLACE;
4387 else
4388 yws = XML_SCHEMA_WHITESPACE_COLLAPSE;
4389
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004390 return(xmlSchemaCompareValuesInternal(x->type, x, NULL, xws, y->type,
4391 y, NULL, yws));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004392}
4393
4394/**
4395 * xmlSchemaCompareValuesWhtsp:
4396 * @x: a first value
4397 * @xws: the whitespace value of x
4398 * @y: a second value
4399 * @yws: the whitespace value of y
4400 *
4401 * Compare 2 values
4402 *
4403 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
4404 * case of error
4405 */
4406int
4407xmlSchemaCompareValuesWhtsp(xmlSchemaValPtr x,
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004408 xmlSchemaWhitespaceValueType xws,
4409 xmlSchemaValPtr y,
4410 xmlSchemaWhitespaceValueType yws)
4411{
4412 return(xmlSchemaCompareValuesInternal(x->type, x, NULL, xws, y->type,
4413 y, NULL, yws));
4414}
4415
4416/**
4417 * xmlSchemaCompareValuesWhtspExt:
4418 * @x: a first value
4419 * @xws: the whitespace value of x
4420 * @y: a second value
4421 * @yws: the whitespace value of y
4422 *
4423 * Compare 2 values
4424 *
4425 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
4426 * case of error
4427 */
4428static int
4429xmlSchemaCompareValuesWhtspExt(xmlSchemaValType xtype,
4430 xmlSchemaValPtr x,
4431 const xmlChar *xvalue,
4432 xmlSchemaWhitespaceValueType xws,
4433 xmlSchemaValType ytype,
4434 xmlSchemaValPtr y,
4435 const xmlChar *yvalue,
4436 xmlSchemaWhitespaceValueType yws)
4437{
4438 return(xmlSchemaCompareValuesInternal(xtype, x, xvalue, xws, ytype, y,
4439 yvalue, yws));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004440}
4441
4442/**
Daniel Veillardc4c21552003-03-29 10:53:38 +00004443 * xmlSchemaNormLen:
4444 * @value: a string
4445 *
4446 * Computes the UTF8 length of the normalized value of the string
4447 *
4448 * Returns the length or -1 in case of error.
4449 */
4450static int
4451xmlSchemaNormLen(const xmlChar *value) {
4452 const xmlChar *utf;
4453 int ret = 0;
4454
4455 if (value == NULL)
4456 return(-1);
4457 utf = value;
William M. Brack76e95df2003-10-18 16:20:14 +00004458 while (IS_BLANK_CH(*utf)) utf++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00004459 while (*utf != 0) {
4460 if (utf[0] & 0x80) {
4461 if ((utf[1] & 0xc0) != 0x80)
4462 return(-1);
4463 if ((utf[0] & 0xe0) == 0xe0) {
4464 if ((utf[2] & 0xc0) != 0x80)
4465 return(-1);
4466 if ((utf[0] & 0xf0) == 0xf0) {
4467 if ((utf[0] & 0xf8) != 0xf0 || (utf[3] & 0xc0) != 0x80)
4468 return(-1);
4469 utf += 4;
4470 } else {
4471 utf += 3;
4472 }
4473 } else {
4474 utf += 2;
4475 }
William M. Brack76e95df2003-10-18 16:20:14 +00004476 } else if (IS_BLANK_CH(*utf)) {
4477 while (IS_BLANK_CH(*utf)) utf++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00004478 if (*utf == 0)
4479 break;
4480 } else {
4481 utf++;
4482 }
4483 ret++;
4484 }
4485 return(ret);
4486}
4487
Daniel Veillard6927b102004-10-27 17:29:04 +00004488/**
4489 * xmlSchemaGetFacetValueAsULong:
4490 * @facet: an schemas type facet
4491 *
4492 * Extract the value of a facet
4493 *
4494 * Returns the value as a long
4495 */
Daniel Veillardc0826a72004-08-10 14:17:33 +00004496unsigned long
4497xmlSchemaGetFacetValueAsULong(xmlSchemaFacetPtr facet)
4498{
4499 /*
4500 * TODO: Check if this is a decimal.
4501 */
William M. Brack094dd862004-11-14 14:28:34 +00004502 if (facet == NULL)
4503 return 0;
Daniel Veillardc0826a72004-08-10 14:17:33 +00004504 return ((unsigned long) facet->val->value.decimal.lo);
4505}
4506
Daniel Veillardc4c21552003-03-29 10:53:38 +00004507/**
Daniel Veillard01fa6152004-06-29 17:04:39 +00004508 * xmlSchemaValidateListSimpleTypeFacet:
4509 * @facet: the facet to check
4510 * @value: the lexical repr of the value to validate
4511 * @actualLen: the number of list items
4512 * @expectedLen: the resulting expected number of list items
4513 *
4514 * Checks the value of a list simple type against a facet.
4515 *
4516 * Returns 0 if the value is valid, a positive error code
4517 * number otherwise and -1 in case of an internal error.
4518 */
4519int
4520xmlSchemaValidateListSimpleTypeFacet(xmlSchemaFacetPtr facet,
4521 const xmlChar *value,
4522 unsigned long actualLen,
4523 unsigned long *expectedLen)
4524{
Daniel Veillardce682bc2004-11-05 17:22:25 +00004525 if (facet == NULL)
4526 return(-1);
Daniel Veillard01fa6152004-06-29 17:04:39 +00004527 /*
4528 * TODO: Check if this will work with large numbers.
4529 * (compare value.decimal.mi and value.decimal.hi as well?).
4530 */
4531 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
4532 if (actualLen != facet->val->value.decimal.lo) {
Daniel Veillardc0826a72004-08-10 14:17:33 +00004533 if (expectedLen != 0)
4534 *expectedLen = facet->val->value.decimal.lo;
Daniel Veillard01fa6152004-06-29 17:04:39 +00004535 return (XML_SCHEMAV_CVC_LENGTH_VALID);
4536 }
4537 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
4538 if (actualLen < facet->val->value.decimal.lo) {
Daniel Veillardc0826a72004-08-10 14:17:33 +00004539 if (expectedLen != 0)
4540 *expectedLen = facet->val->value.decimal.lo;
Daniel Veillard01fa6152004-06-29 17:04:39 +00004541 return (XML_SCHEMAV_CVC_MINLENGTH_VALID);
4542 }
4543 } else if (facet->type == XML_SCHEMA_FACET_MAXLENGTH) {
4544 if (actualLen > facet->val->value.decimal.lo) {
Daniel Veillardc0826a72004-08-10 14:17:33 +00004545 if (expectedLen != 0)
4546 *expectedLen = facet->val->value.decimal.lo;
Daniel Veillard01fa6152004-06-29 17:04:39 +00004547 return (XML_SCHEMAV_CVC_MAXLENGTH_VALID);
4548 }
4549 } else
4550 /*
4551 * NOTE: That we can pass NULL as xmlSchemaValPtr to
4552 * xmlSchemaValidateFacet, since the remaining facet types
4553 * are: XML_SCHEMA_FACET_PATTERN, XML_SCHEMA_FACET_ENUMERATION.
4554 */
4555 return(xmlSchemaValidateFacet(NULL, facet, value, NULL));
4556 return (0);
4557}
4558
4559/**
Daniel Veillard6927b102004-10-27 17:29:04 +00004560 * xmlSchemaValidateLengthFacet:
Daniel Veillardc0826a72004-08-10 14:17:33 +00004561 * @type: the built-in type
4562 * @facet: the facet to check
4563 * @value: the lexical repr. of the value to be validated
4564 * @val: the precomputed value
4565 * @length: the actual length of the value
4566 *
4567 * Checka a value against a "length", "minLength" and "maxLength"
4568 * facet; sets @length to the computed length of @value.
4569 *
4570 * Returns 0 if the value is valid, a positive error code
4571 * otherwise and -1 in case of an internal or API error.
4572 */
4573int
4574xmlSchemaValidateLengthFacet(xmlSchemaTypePtr type,
4575 xmlSchemaFacetPtr facet,
4576 const xmlChar *value,
4577 xmlSchemaValPtr val,
4578 unsigned long *length)
4579{
4580 unsigned int len = 0;
4581
Daniel Veillardce682bc2004-11-05 17:22:25 +00004582 if ((length == NULL) || (facet == NULL) || (type == NULL))
4583 return (-1);
Daniel Veillardc0826a72004-08-10 14:17:33 +00004584 *length = 0;
4585 if ((facet->type != XML_SCHEMA_FACET_LENGTH) &&
4586 (facet->type != XML_SCHEMA_FACET_MAXLENGTH) &&
4587 (facet->type != XML_SCHEMA_FACET_MINLENGTH))
4588 return (-1);
4589
4590 if ((facet->val == NULL) ||
4591 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
4592 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
4593 (facet->val->value.decimal.frac != 0)) {
4594 return(-1);
4595 }
4596 if ((val != NULL) && (val->type == XML_SCHEMAS_HEXBINARY))
4597 len = val->value.hex.total;
4598 else if ((val != NULL) && (val->type == XML_SCHEMAS_BASE64BINARY))
4599 len = val->value.base64.total;
4600 else {
4601 switch (type->builtInType) {
4602 case XML_SCHEMAS_IDREF:
4603 case XML_SCHEMAS_NORMSTRING:
4604 case XML_SCHEMAS_TOKEN:
4605 case XML_SCHEMAS_LANGUAGE:
4606 case XML_SCHEMAS_NMTOKEN:
4607 case XML_SCHEMAS_NAME:
4608 case XML_SCHEMAS_NCNAME:
4609 case XML_SCHEMAS_ID:
4610 len = xmlSchemaNormLen(value);
4611 break;
4612 case XML_SCHEMAS_STRING:
4613 /*
4614 * FIXME: What exactly to do with anyURI?
4615 */
4616 case XML_SCHEMAS_ANYURI:
4617 if (value != NULL)
4618 len = xmlUTF8Strlen(value);
4619 break;
4620 default:
4621 TODO
4622 }
4623 }
4624 *length = (unsigned long) len;
4625 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
4626 if (len != facet->val->value.decimal.lo)
4627 return(XML_SCHEMAV_CVC_LENGTH_VALID);
4628 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
4629 if (len < facet->val->value.decimal.lo)
4630 return(XML_SCHEMAV_CVC_MINLENGTH_VALID);
4631 } else {
4632 if (len > facet->val->value.decimal.lo)
4633 return(XML_SCHEMAV_CVC_MAXLENGTH_VALID);
4634 }
4635
4636 return (0);
4637}
4638
4639/**
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004640 * xmlSchemaValidateFacetInternal:
Daniel Veillard01c13b52002-12-10 15:19:08 +00004641 * @base: the base type
Daniel Veillard4255d502002-04-16 15:50:10 +00004642 * @facet: the facet to check
4643 * @value: the lexical repr of the value to validate
4644 * @val: the precomputed value
4645 *
4646 * Check a value against a facet condition
4647 *
4648 * Returns 0 if the element is schemas valid, a positive error code
4649 * number otherwise and -1 in case of internal or API error.
4650 */
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004651static int
4652xmlSchemaValidateFacetInternal(xmlSchemaFacetPtr facet,
4653 xmlSchemaWhitespaceValueType fws,
4654 xmlSchemaValType valType,
4655 xmlSchemaValPtr val,
4656 const xmlChar *value,
4657 xmlSchemaWhitespaceValueType ws)
Daniel Veillard4255d502002-04-16 15:50:10 +00004658{
4659 int ret;
4660
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004661 if (facet == NULL)
4662 return(-1);
4663
Daniel Veillard4255d502002-04-16 15:50:10 +00004664 switch (facet->type) {
4665 case XML_SCHEMA_FACET_PATTERN:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004666 /*
4667 * NOTE that for patterns, the @value needs to be the normalized
4668 * value, *not* the lexical initial value or the canonical value.
4669 */
4670 if (value == NULL)
4671 return(-1);
Daniel Veillard4255d502002-04-16 15:50:10 +00004672 ret = xmlRegexpExec(facet->regexp, value);
4673 if (ret == 1)
4674 return(0);
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004675 if (ret == 0)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004676 return(XML_SCHEMAV_CVC_PATTERN_VALID);
Daniel Veillard4255d502002-04-16 15:50:10 +00004677 return(ret);
4678 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
4679 ret = xmlSchemaCompareValues(val, facet->val);
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004680 if (ret == -2)
Daniel Veillard4255d502002-04-16 15:50:10 +00004681 return(-1);
Daniel Veillard4255d502002-04-16 15:50:10 +00004682 if (ret == -1)
4683 return(0);
Daniel Veillard01fa6152004-06-29 17:04:39 +00004684 return(XML_SCHEMAV_CVC_MAXEXCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00004685 case XML_SCHEMA_FACET_MAXINCLUSIVE:
4686 ret = xmlSchemaCompareValues(val, facet->val);
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004687 if (ret == -2)
Daniel Veillard070803b2002-05-03 07:29:38 +00004688 return(-1);
Daniel Veillard070803b2002-05-03 07:29:38 +00004689 if ((ret == -1) || (ret == 0))
4690 return(0);
Daniel Veillard01fa6152004-06-29 17:04:39 +00004691 return(XML_SCHEMAV_CVC_MAXINCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00004692 case XML_SCHEMA_FACET_MINEXCLUSIVE:
4693 ret = xmlSchemaCompareValues(val, facet->val);
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004694 if (ret == -2)
Daniel Veillard070803b2002-05-03 07:29:38 +00004695 return(-1);
Daniel Veillard070803b2002-05-03 07:29:38 +00004696 if (ret == 1)
4697 return(0);
Daniel Veillard01fa6152004-06-29 17:04:39 +00004698 return(XML_SCHEMAV_CVC_MINEXCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00004699 case XML_SCHEMA_FACET_MININCLUSIVE:
4700 ret = xmlSchemaCompareValues(val, facet->val);
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004701 if (ret == -2)
Daniel Veillard070803b2002-05-03 07:29:38 +00004702 return(-1);
Daniel Veillard070803b2002-05-03 07:29:38 +00004703 if ((ret == 1) || (ret == 0))
4704 return(0);
Daniel Veillard01fa6152004-06-29 17:04:39 +00004705 return(XML_SCHEMAV_CVC_MININCLUSIVE_VALID);
Daniel Veillard8651f532002-04-17 09:06:27 +00004706 case XML_SCHEMA_FACET_WHITESPACE:
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004707 /* TODO whitespaces */
Daniel Veillard01fa6152004-06-29 17:04:39 +00004708 /*
4709 * NOTE: Whitespace should be handled to normalize
4710 * the value to be validated against a the facets;
4711 * not to normalize the value in-between.
4712 */
Daniel Veillard8651f532002-04-17 09:06:27 +00004713 return(0);
Daniel Veillard88c58912002-04-23 07:12:20 +00004714 case XML_SCHEMA_FACET_ENUMERATION:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004715 if (fws == XML_SCHEMA_WHITESPACE_UNKNOWN) {
4716 if ((facet->value != NULL) &&
4717 (xmlStrEqual(facet->value, value)))
4718 return(0);
4719 } else {
4720 ret = xmlSchemaCompareValuesWhtspExt(facet->val->type,
4721 facet->val, facet->value, fws, valType, val,
4722 value, ws);
4723 if (ret == -2)
4724 return(-1);
4725 if (ret == 0)
4726 return(0);
4727 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00004728 return(XML_SCHEMAV_CVC_ENUMERATION_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004729 case XML_SCHEMA_FACET_LENGTH:
4730 case XML_SCHEMA_FACET_MAXLENGTH:
4731 case XML_SCHEMA_FACET_MINLENGTH: {
4732 unsigned int len = 0;
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004733 /* TODO: Take the whitespace of the value into account. */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004734
4735 if ((facet->val == NULL) ||
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004736 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
4737 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004738 (facet->val->value.decimal.frac != 0)) {
4739 return(-1);
4740 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00004741 if ((val != NULL) && (val->type == XML_SCHEMAS_HEXBINARY))
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004742 len = val->value.hex.total;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00004743 else if ((val != NULL) && (val->type == XML_SCHEMAS_BASE64BINARY))
4744 len = val->value.base64.total;
4745 else {
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004746 switch (valType) {
Daniel Veillard560c2a42003-07-06 21:13:49 +00004747 case XML_SCHEMAS_IDREF:
4748 case XML_SCHEMAS_NORMSTRING:
4749 case XML_SCHEMAS_TOKEN:
4750 case XML_SCHEMAS_LANGUAGE:
4751 case XML_SCHEMAS_NMTOKEN:
4752 case XML_SCHEMAS_NAME:
4753 case XML_SCHEMAS_NCNAME:
4754 case XML_SCHEMAS_ID:
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004755 len = xmlSchemaNormLen(value);
4756 break;
Daniel Veillard560c2a42003-07-06 21:13:49 +00004757 case XML_SCHEMAS_STRING:
Daniel Veillard01fa6152004-06-29 17:04:39 +00004758 /*
4759 * FIXME: What exactly to do with anyURI?
4760 */
4761 case XML_SCHEMAS_ANYURI:
William M. Brackfbf2c5e2004-02-03 17:55:56 +00004762 if (value != NULL)
4763 len = xmlUTF8Strlen(value);
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004764 break;
Daniel Veillard560c2a42003-07-06 21:13:49 +00004765 default:
4766 TODO
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004767 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004768 }
4769 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004770 if (len != facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004771 return(XML_SCHEMAV_CVC_LENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004772 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004773 if (len < facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004774 return(XML_SCHEMAV_CVC_MINLENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004775 } else {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004776 if (len > facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004777 return(XML_SCHEMAV_CVC_MAXLENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004778 }
4779 break;
4780 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00004781 case XML_SCHEMA_FACET_TOTALDIGITS:
4782 case XML_SCHEMA_FACET_FRACTIONDIGITS:
4783
4784 if ((facet->val == NULL) ||
4785 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
4786 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
4787 (facet->val->value.decimal.frac != 0)) {
4788 return(-1);
4789 }
4790 if ((val == NULL) ||
4791 ((val->type != XML_SCHEMAS_DECIMAL) &&
4792 (val->type != XML_SCHEMAS_INTEGER) &&
4793 (val->type != XML_SCHEMAS_NPINTEGER) &&
4794 (val->type != XML_SCHEMAS_NINTEGER) &&
4795 (val->type != XML_SCHEMAS_NNINTEGER) &&
4796 (val->type != XML_SCHEMAS_PINTEGER) &&
4797 (val->type != XML_SCHEMAS_INT) &&
4798 (val->type != XML_SCHEMAS_UINT) &&
4799 (val->type != XML_SCHEMAS_LONG) &&
4800 (val->type != XML_SCHEMAS_ULONG) &&
4801 (val->type != XML_SCHEMAS_SHORT) &&
4802 (val->type != XML_SCHEMAS_USHORT) &&
4803 (val->type != XML_SCHEMAS_BYTE) &&
4804 (val->type != XML_SCHEMAS_UBYTE))) {
4805 return(-1);
4806 }
4807 if (facet->type == XML_SCHEMA_FACET_TOTALDIGITS) {
4808 if (val->value.decimal.total > facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004809 return(XML_SCHEMAV_CVC_TOTALDIGITS_VALID);
Daniel Veillard560c2a42003-07-06 21:13:49 +00004810
4811 } else if (facet->type == XML_SCHEMA_FACET_FRACTIONDIGITS) {
4812 if (val->value.decimal.frac > facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004813 return(XML_SCHEMAV_CVC_FRACTIONDIGITS_VALID);
Daniel Veillard560c2a42003-07-06 21:13:49 +00004814 }
4815 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00004816 default:
4817 TODO
4818 }
4819 return(0);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00004820
Daniel Veillard4255d502002-04-16 15:50:10 +00004821}
4822
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004823/**
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004824 * xmlSchemaValidateFacet:
4825 * @base: the base type
4826 * @facet: the facet to check
4827 * @value: the lexical repr of the value to validate
4828 * @val: the precomputed value
4829 *
4830 * Check a value against a facet condition
4831 *
4832 * Returns 0 if the element is schemas valid, a positive error code
4833 * number otherwise and -1 in case of internal or API error.
4834 */
4835int
4836xmlSchemaValidateFacet(xmlSchemaTypePtr base ATTRIBUTE_UNUSED,
4837 xmlSchemaFacetPtr facet,
4838 const xmlChar *value,
4839 xmlSchemaValPtr val)
4840{
4841 /*
4842 * This tries to ensure API compatibility regarding the old
4843 * xmlSchemaValidateFacet() and the new xmlSchemaValidateFacetInternal() and
4844 * xmlSchemaValidateFacetWhtsp().
4845 */
4846 if (val != NULL)
4847 return(xmlSchemaValidateFacetInternal(facet,
4848 XML_SCHEMA_WHITESPACE_UNKNOWN, val->type, val, value,
4849 XML_SCHEMA_WHITESPACE_UNKNOWN));
4850 else {
4851 return(xmlSchemaValidateFacetInternal(facet,
4852 XML_SCHEMA_WHITESPACE_UNKNOWN, base->builtInType, val, value,
4853 XML_SCHEMA_WHITESPACE_UNKNOWN));
4854 }
4855}
4856
4857/**
4858 * xmlSchemaValidateFacetWhtsp:
4859 * @facet: the facet to check
4860 * @fws: the whitespace type of the facet's value
4861 * @valType: the built-in type of the value
4862 * @value: the lexical (or normalized for pattern) repr of the value to validate
4863 * @val: the precomputed value
4864 * @ws: the whitespace type of the value
4865 *
4866 * Check a value against a facet condition. This takes value normalization
4867 * according to the specified whitespace types into account.
4868 * Note that @value needs to be the *normalized* value if the facet
4869 * is of type "pattern".
4870 *
4871 * Returns 0 if the element is schemas valid, a positive error code
4872 * number otherwise and -1 in case of internal or API error.
4873 */
4874#if 0
4875int
4876xmlSchemaValidateFacetWhtsp(xmlSchemaFacetPtr facet,
4877 xmlSchemaWhitespaceValueType fws,
4878 xmlSchemaValType valType,
4879 xmlSchemaValPtr val,
4880 const xmlChar *value,
4881 xmlSchemaWhitespaceValueType ws)
4882{
4883 return(xmlSchemaValidateFacetInternal(facet, fws, valType,
4884 val, value, ws));
4885}
4886#endif
4887
4888/**
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004889 * xmlSchemaGetCanonValue:
4890 * @val: the precomputed value
4891 * @retValue: the returned value
4892 *
Daniel Veillardb5839c32005-02-19 18:27:14 +00004893 * Get a the cononical representation of the value.
4894 * The caller has to free the returned retValue.
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004895 *
4896 * Returns 0 if the value could be built and -1 in case of
4897 * API errors or if the value type is not supported yet.
4898 */
4899int
Daniel Veillardb5839c32005-02-19 18:27:14 +00004900xmlSchemaGetCanonValue(xmlSchemaValPtr val, const xmlChar **retValue)
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004901{
Daniel Veillardb5839c32005-02-19 18:27:14 +00004902 if ((retValue == NULL) || (val == NULL))
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004903 return (-1);
4904 *retValue = NULL;
4905 switch (val->type) {
4906 case XML_SCHEMAS_STRING:
4907 case XML_SCHEMAS_NORMSTRING:
4908 /*
4909 case XML_SCHEMAS_TOKEN:
4910 case XML_SCHEMAS_LANGUAGE:
4911 case XML_SCHEMAS_NMTOKEN:
4912 case XML_SCHEMAS_NAME:
4913 case XML_SCHEMAS_QNAME:
4914 case XML_SCHEMAS_NCNAME:
4915 case XML_SCHEMAS_ID:
4916 case XML_SCHEMAS_IDREF:
4917 case XML_SCHEMAS_ENTITY:
4918 case XML_SCHEMAS_NOTATION:
4919 case XML_SCHEMAS_ANYURI:
4920 */
4921 if (val->value.str == NULL)
4922 *retValue = NULL;
4923 else
4924 /* TODO: This is not yet correct for non-normalized values. */
4925 *retValue =
4926 BAD_CAST xmlStrdup((const xmlChar *) val->value.str);
4927 return (0);
4928 default:
4929 return (-1);
4930 }
4931 return (-1);
4932}
4933
Daniel Veillard4255d502002-04-16 15:50:10 +00004934#endif /* LIBXML_SCHEMAS_ENABLED */