blob: 42e69c4374c2613cf654d1576bc0497263eef50d [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
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +000053#define IS_WSP_BLANK_CH(c) IS_BLANK_CH(c)
54
Daniel Veillard070803b2002-05-03 07:29:38 +000055/* Date value */
56typedef struct _xmlSchemaValDate xmlSchemaValDate;
57typedef xmlSchemaValDate *xmlSchemaValDatePtr;
58struct _xmlSchemaValDate {
59 long year;
60 unsigned int mon :4; /* 1 <= mon <= 12 */
61 unsigned int day :5; /* 1 <= day <= 31 */
62 unsigned int hour :5; /* 0 <= hour <= 23 */
63 unsigned int min :6; /* 0 <= min <= 59 */
64 double sec;
Daniel Veillarda77cf712003-05-09 23:09:55 +000065 unsigned int tz_flag :1; /* is tzo explicitely set? */
Daniel Veillard070803b2002-05-03 07:29:38 +000066 int tzo :11; /* -1440 <= tzo <= 1440 */
67};
68
69/* Duration value */
70typedef struct _xmlSchemaValDuration xmlSchemaValDuration;
71typedef xmlSchemaValDuration *xmlSchemaValDurationPtr;
72struct _xmlSchemaValDuration {
73 long mon; /* mon stores years also */
74 long day;
75 double sec; /* sec stores min and hour also */
76};
77
Daniel Veillard4255d502002-04-16 15:50:10 +000078typedef struct _xmlSchemaValDecimal xmlSchemaValDecimal;
79typedef xmlSchemaValDecimal *xmlSchemaValDecimalPtr;
80struct _xmlSchemaValDecimal {
81 /* would use long long but not portable */
Daniel Veillarde637c4a2003-03-30 21:10:09 +000082 unsigned long lo;
83 unsigned long mi;
84 unsigned long hi;
Daniel Veillard4255d502002-04-16 15:50:10 +000085 unsigned int extra;
Daniel Veillard5a872412002-05-22 06:40:27 +000086 unsigned int sign:1;
William M. Brackc1939562003-08-05 15:52:22 +000087 unsigned int frac:7;
88 unsigned int total:8;
Daniel Veillard4255d502002-04-16 15:50:10 +000089};
90
Daniel Veillarde637c4a2003-03-30 21:10:09 +000091typedef struct _xmlSchemaValQName xmlSchemaValQName;
92typedef xmlSchemaValQName *xmlSchemaValQNamePtr;
93struct _xmlSchemaValQName {
94 xmlChar *name;
95 xmlChar *uri;
96};
97
Daniel Veillard70bcb0e2003-08-08 14:00:28 +000098typedef struct _xmlSchemaValHex xmlSchemaValHex;
99typedef xmlSchemaValHex *xmlSchemaValHexPtr;
100struct _xmlSchemaValHex {
101 xmlChar *str;
102 unsigned int total;
103};
104
Daniel Veillard1ac24d32003-08-27 14:15:15 +0000105typedef struct _xmlSchemaValBase64 xmlSchemaValBase64;
106typedef xmlSchemaValBase64 *xmlSchemaValBase64Ptr;
107struct _xmlSchemaValBase64 {
108 xmlChar *str;
109 unsigned int total;
110};
111
Daniel Veillard4255d502002-04-16 15:50:10 +0000112struct _xmlSchemaVal {
113 xmlSchemaValType type;
114 union {
Daniel Veillard5a872412002-05-22 06:40:27 +0000115 xmlSchemaValDecimal decimal;
Daniel Veillard070803b2002-05-03 07:29:38 +0000116 xmlSchemaValDate date;
117 xmlSchemaValDuration dur;
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000118 xmlSchemaValQName qname;
Daniel Veillard70bcb0e2003-08-08 14:00:28 +0000119 xmlSchemaValHex hex;
Daniel Veillard1ac24d32003-08-27 14:15:15 +0000120 xmlSchemaValBase64 base64;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000121 float f;
122 double d;
Daniel Veillardc5a70f22003-02-06 23:41:59 +0000123 int b;
Daniel Veillardc4c21552003-03-29 10:53:38 +0000124 xmlChar *str;
Daniel Veillard4255d502002-04-16 15:50:10 +0000125 } value;
126};
127
128static int xmlSchemaTypesInitialized = 0;
129static xmlHashTablePtr xmlSchemaTypesBank = NULL;
130
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000131/*
132 * Basic types
133 */
Daniel Veillard4255d502002-04-16 15:50:10 +0000134static xmlSchemaTypePtr xmlSchemaTypeStringDef = NULL;
135static xmlSchemaTypePtr xmlSchemaTypeAnyTypeDef = NULL;
136static xmlSchemaTypePtr xmlSchemaTypeAnySimpleTypeDef = NULL;
137static xmlSchemaTypePtr xmlSchemaTypeDecimalDef = NULL;
Daniel Veillard070803b2002-05-03 07:29:38 +0000138static xmlSchemaTypePtr xmlSchemaTypeDatetimeDef = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +0000139static xmlSchemaTypePtr xmlSchemaTypeDateDef = NULL;
Daniel Veillard070803b2002-05-03 07:29:38 +0000140static xmlSchemaTypePtr xmlSchemaTypeTimeDef = NULL;
141static xmlSchemaTypePtr xmlSchemaTypeGYearDef = NULL;
142static xmlSchemaTypePtr xmlSchemaTypeGYearMonthDef = NULL;
143static xmlSchemaTypePtr xmlSchemaTypeGDayDef = NULL;
144static xmlSchemaTypePtr xmlSchemaTypeGMonthDayDef = NULL;
145static xmlSchemaTypePtr xmlSchemaTypeGMonthDef = NULL;
146static xmlSchemaTypePtr xmlSchemaTypeDurationDef = NULL;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000147static xmlSchemaTypePtr xmlSchemaTypeFloatDef = NULL;
Daniel Veillardc5a70f22003-02-06 23:41:59 +0000148static xmlSchemaTypePtr xmlSchemaTypeBooleanDef = NULL;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000149static xmlSchemaTypePtr xmlSchemaTypeDoubleDef = NULL;
Daniel Veillard560c2a42003-07-06 21:13:49 +0000150static xmlSchemaTypePtr xmlSchemaTypeHexBinaryDef = NULL;
Daniel Veillard1ac24d32003-08-27 14:15:15 +0000151static xmlSchemaTypePtr xmlSchemaTypeBase64BinaryDef = NULL;
Daniel Veillarde5b110b2003-02-04 14:43:39 +0000152static xmlSchemaTypePtr xmlSchemaTypeAnyURIDef = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +0000153
154/*
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000155 * Derived types
156 */
157static xmlSchemaTypePtr xmlSchemaTypePositiveIntegerDef = NULL;
158static xmlSchemaTypePtr xmlSchemaTypeNonPositiveIntegerDef = NULL;
159static xmlSchemaTypePtr xmlSchemaTypeNegativeIntegerDef = NULL;
160static xmlSchemaTypePtr xmlSchemaTypeNonNegativeIntegerDef = NULL;
161static xmlSchemaTypePtr xmlSchemaTypeIntegerDef = NULL;
162static xmlSchemaTypePtr xmlSchemaTypeLongDef = NULL;
163static xmlSchemaTypePtr xmlSchemaTypeIntDef = NULL;
164static xmlSchemaTypePtr xmlSchemaTypeShortDef = NULL;
165static xmlSchemaTypePtr xmlSchemaTypeByteDef = NULL;
166static xmlSchemaTypePtr xmlSchemaTypeUnsignedLongDef = NULL;
167static xmlSchemaTypePtr xmlSchemaTypeUnsignedIntDef = NULL;
168static xmlSchemaTypePtr xmlSchemaTypeUnsignedShortDef = NULL;
169static xmlSchemaTypePtr xmlSchemaTypeUnsignedByteDef = NULL;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000170static xmlSchemaTypePtr xmlSchemaTypeNormStringDef = NULL;
171static xmlSchemaTypePtr xmlSchemaTypeTokenDef = NULL;
172static xmlSchemaTypePtr xmlSchemaTypeLanguageDef = NULL;
173static xmlSchemaTypePtr xmlSchemaTypeNameDef = NULL;
174static xmlSchemaTypePtr xmlSchemaTypeQNameDef = NULL;
Daniel Veillarde5b110b2003-02-04 14:43:39 +0000175static xmlSchemaTypePtr xmlSchemaTypeNCNameDef = NULL;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000176static xmlSchemaTypePtr xmlSchemaTypeIdDef = NULL;
177static xmlSchemaTypePtr xmlSchemaTypeIdrefDef = NULL;
178static xmlSchemaTypePtr xmlSchemaTypeIdrefsDef = NULL;
Daniel Veillarda1a9d042003-03-18 16:53:17 +0000179static xmlSchemaTypePtr xmlSchemaTypeEntityDef = NULL;
180static xmlSchemaTypePtr xmlSchemaTypeEntitiesDef = NULL;
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000181static xmlSchemaTypePtr xmlSchemaTypeNotationDef = NULL;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000182static xmlSchemaTypePtr xmlSchemaTypeNmtokenDef = NULL;
183static xmlSchemaTypePtr xmlSchemaTypeNmtokensDef = NULL;
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000184
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000185/************************************************************************
186 * *
187 * Datatype error handlers *
188 * *
189 ************************************************************************/
190/**
191 * xmlSchemaTypeErrMemory:
192 * @extra: extra informations
193 *
194 * Handle an out of memory condition
195 */
196static void
197xmlSchemaTypeErrMemory(xmlNodePtr node, const char *extra)
198{
199 __xmlSimpleError(XML_FROM_DATATYPE, XML_ERR_NO_MEMORY, node, NULL, extra);
200}
201
202/************************************************************************
203 * *
204 * Base types support *
205 * *
206 ************************************************************************/
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000207/*
Daniel Veillard4255d502002-04-16 15:50:10 +0000208 * xmlSchemaInitBasicType:
209 * @name: the type name
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000210 * @type: the value type associated
Daniel Veillard4255d502002-04-16 15:50:10 +0000211 *
Daniel Veillard01fa6152004-06-29 17:04:39 +0000212 * Initialize one primitive built-in type
Daniel Veillard4255d502002-04-16 15:50:10 +0000213 */
214static xmlSchemaTypePtr
Daniel Veillard01fa6152004-06-29 17:04:39 +0000215xmlSchemaInitBasicType(const char *name, xmlSchemaValType type,
216 xmlSchemaTypePtr baseType) {
Daniel Veillard4255d502002-04-16 15:50:10 +0000217 xmlSchemaTypePtr ret;
218
219 ret = (xmlSchemaTypePtr) xmlMalloc(sizeof(xmlSchemaType));
220 if (ret == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000221 xmlSchemaTypeErrMemory(NULL, "could not initialize basic types");
Daniel Veillard4255d502002-04-16 15:50:10 +0000222 return(NULL);
223 }
224 memset(ret, 0, sizeof(xmlSchemaType));
Daniel Veillardbe9c6322003-11-22 20:37:51 +0000225 ret->name = (const xmlChar *)name;
Daniel Veillard4255d502002-04-16 15:50:10 +0000226 ret->type = XML_SCHEMA_TYPE_BASIC;
Daniel Veillard01fa6152004-06-29 17:04:39 +0000227 ret->baseType = baseType;
228 /*
229 * Hack to reflect the variety.
230 */
231 if ((type == XML_SCHEMAS_IDREFS) ||
232 (type == XML_SCHEMAS_NMTOKENS) ||
233 (type == XML_SCHEMAS_ENTITIES))
234 ret->flags |= XML_SCHEMAS_TYPE_VARIETY_LIST;
William M. Brack2f2a6632004-08-20 23:09:47 +0000235 else if ((type != XML_SCHEMAS_ANYTYPE) &&
236 (type != XML_SCHEMAS_ANYSIMPLETYPE))
Daniel Veillard01fa6152004-06-29 17:04:39 +0000237 ret->flags |= XML_SCHEMAS_TYPE_VARIETY_ATOMIC;
Daniel Veillard4255d502002-04-16 15:50:10 +0000238 ret->contentType = XML_SCHEMA_CONTENT_BASIC;
Daniel Veillard01fa6152004-06-29 17:04:39 +0000239 switch (type) {
240 case XML_SCHEMAS_STRING:
241 case XML_SCHEMAS_DECIMAL:
242 case XML_SCHEMAS_DATE:
243 case XML_SCHEMAS_DATETIME:
244 case XML_SCHEMAS_TIME:
245 case XML_SCHEMAS_GYEAR:
246 case XML_SCHEMAS_GYEARMONTH:
247 case XML_SCHEMAS_GMONTH:
248 case XML_SCHEMAS_GMONTHDAY:
249 case XML_SCHEMAS_GDAY:
250 case XML_SCHEMAS_DURATION:
251 case XML_SCHEMAS_FLOAT:
252 case XML_SCHEMAS_DOUBLE:
253 case XML_SCHEMAS_BOOLEAN:
254 case XML_SCHEMAS_ANYURI:
255 case XML_SCHEMAS_HEXBINARY:
256 case XML_SCHEMAS_BASE64BINARY:
257 case XML_SCHEMAS_QNAME:
258 case XML_SCHEMAS_NOTATION:
259 ret->flags |= XML_SCHEMAS_TYPE_BUILTIN_PRIMITIVE;
William M. Brack96d2eff2004-06-30 11:48:47 +0000260 default:
261 break;
Daniel Veillard01fa6152004-06-29 17:04:39 +0000262 }
263
Daniel Veillard4255d502002-04-16 15:50:10 +0000264 xmlHashAddEntry2(xmlSchemaTypesBank, ret->name,
265 XML_SCHEMAS_NAMESPACE_NAME, ret);
Daniel Veillard01fa6152004-06-29 17:04:39 +0000266 ret->builtInType = type;
Daniel Veillard4255d502002-04-16 15:50:10 +0000267 return(ret);
268}
269
270/*
271 * xmlSchemaInitTypes:
272 *
273 * Initialize the default XML Schemas type library
274 */
275void
Daniel Veillard6560a422003-03-27 21:25:38 +0000276xmlSchemaInitTypes(void)
277{
Daniel Veillard4255d502002-04-16 15:50:10 +0000278 if (xmlSchemaTypesInitialized != 0)
Daniel Veillard6560a422003-03-27 21:25:38 +0000279 return;
Daniel Veillard4255d502002-04-16 15:50:10 +0000280 xmlSchemaTypesBank = xmlHashCreate(40);
Daniel Veillard6560a422003-03-27 21:25:38 +0000281
Daniel Veillard01fa6152004-06-29 17:04:39 +0000282
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000283 /*
Daniel Veillard01fa6152004-06-29 17:04:39 +0000284 * 3.4.7 Built-in Complex Type Definition
285 */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000286 xmlSchemaTypeAnyTypeDef = xmlSchemaInitBasicType("anyType",
William M. Brack2f2a6632004-08-20 23:09:47 +0000287 XML_SCHEMAS_ANYTYPE,
Daniel Veillard01fa6152004-06-29 17:04:39 +0000288 NULL);
289 xmlSchemaTypeAnyTypeDef->baseType = xmlSchemaTypeAnyTypeDef;
290 xmlSchemaTypeAnyTypeDef->contentType = XML_SCHEMA_CONTENT_MIXED;
291 {
292 xmlSchemaWildcardPtr wild;
293
294 wild = (xmlSchemaWildcardPtr) xmlMalloc(sizeof(xmlSchemaWildcard));
295 if (wild == NULL) {
William M. Brack2f2a6632004-08-20 23:09:47 +0000296 xmlSchemaTypeErrMemory(NULL, "could not create an attribute wildcard on anyType");
Daniel Veillard01fa6152004-06-29 17:04:39 +0000297 return;
298 }
299 memset(wild, 0, sizeof(xmlSchemaWildcard));
300 wild->any = 1;
301 wild->processContents = XML_SCHEMAS_ANY_LAX;
302 wild->minOccurs = 1;
303 wild->maxOccurs = 1;
304 xmlSchemaTypeAnyTypeDef->attributeWildcard = wild;
305 }
306 xmlSchemaTypeAnySimpleTypeDef = xmlSchemaInitBasicType("anySimpleType",
William M. Brack2f2a6632004-08-20 23:09:47 +0000307 XML_SCHEMAS_ANYSIMPLETYPE,
Daniel Veillard01fa6152004-06-29 17:04:39 +0000308 xmlSchemaTypeAnyTypeDef);
309 /*
310 * primitive datatypes
311 */
312 xmlSchemaTypeStringDef = xmlSchemaInitBasicType("string",
313 XML_SCHEMAS_STRING,
314 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000315 xmlSchemaTypeDecimalDef = xmlSchemaInitBasicType("decimal",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000316 XML_SCHEMAS_DECIMAL,
317 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000318 xmlSchemaTypeDateDef = xmlSchemaInitBasicType("date",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000319 XML_SCHEMAS_DATE,
320 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000321 xmlSchemaTypeDatetimeDef = xmlSchemaInitBasicType("dateTime",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000322 XML_SCHEMAS_DATETIME,
323 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000324 xmlSchemaTypeTimeDef = xmlSchemaInitBasicType("time",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000325 XML_SCHEMAS_TIME,
326 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000327 xmlSchemaTypeGYearDef = xmlSchemaInitBasicType("gYear",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000328 XML_SCHEMAS_GYEAR,
329 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000330 xmlSchemaTypeGYearMonthDef = xmlSchemaInitBasicType("gYearMonth",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000331 XML_SCHEMAS_GYEARMONTH,
332 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000333 xmlSchemaTypeGMonthDef = xmlSchemaInitBasicType("gMonth",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000334 XML_SCHEMAS_GMONTH,
335 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000336 xmlSchemaTypeGMonthDayDef = xmlSchemaInitBasicType("gMonthDay",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000337 XML_SCHEMAS_GMONTHDAY,
338 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000339 xmlSchemaTypeGDayDef = xmlSchemaInitBasicType("gDay",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000340 XML_SCHEMAS_GDAY,
341 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000342 xmlSchemaTypeDurationDef = xmlSchemaInitBasicType("duration",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000343 XML_SCHEMAS_DURATION,
344 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000345 xmlSchemaTypeFloatDef = xmlSchemaInitBasicType("float",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000346 XML_SCHEMAS_FLOAT,
347 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000348 xmlSchemaTypeDoubleDef = xmlSchemaInitBasicType("double",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000349 XML_SCHEMAS_DOUBLE,
350 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000351 xmlSchemaTypeBooleanDef = xmlSchemaInitBasicType("boolean",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000352 XML_SCHEMAS_BOOLEAN,
353 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000354 xmlSchemaTypeAnyURIDef = xmlSchemaInitBasicType("anyURI",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000355 XML_SCHEMAS_ANYURI,
356 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard560c2a42003-07-06 21:13:49 +0000357 xmlSchemaTypeHexBinaryDef = xmlSchemaInitBasicType("hexBinary",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000358 XML_SCHEMAS_HEXBINARY,
359 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard1ac24d32003-08-27 14:15:15 +0000360 xmlSchemaTypeBase64BinaryDef
Daniel Veillard01fa6152004-06-29 17:04:39 +0000361 = xmlSchemaInitBasicType("base64Binary", XML_SCHEMAS_BASE64BINARY,
362 xmlSchemaTypeAnySimpleTypeDef);
363 xmlSchemaTypeNotationDef = xmlSchemaInitBasicType("NOTATION",
364 XML_SCHEMAS_NOTATION,
365 xmlSchemaTypeAnySimpleTypeDef);
366 xmlSchemaTypeQNameDef = xmlSchemaInitBasicType("QName",
367 XML_SCHEMAS_QNAME,
368 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard4255d502002-04-16 15:50:10 +0000369
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000370 /*
371 * derived datatypes
372 */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000373 xmlSchemaTypeIntegerDef = xmlSchemaInitBasicType("integer",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000374 XML_SCHEMAS_INTEGER,
375 xmlSchemaTypeDecimalDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000376 xmlSchemaTypeNonPositiveIntegerDef =
377 xmlSchemaInitBasicType("nonPositiveInteger",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000378 XML_SCHEMAS_NPINTEGER,
379 xmlSchemaTypeIntegerDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000380 xmlSchemaTypeNegativeIntegerDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000381 xmlSchemaInitBasicType("negativeInteger", XML_SCHEMAS_NINTEGER,
382 xmlSchemaTypeNonPositiveIntegerDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000383 xmlSchemaTypeLongDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000384 xmlSchemaInitBasicType("long", XML_SCHEMAS_LONG,
385 xmlSchemaTypeIntegerDef);
386 xmlSchemaTypeIntDef = xmlSchemaInitBasicType("int", XML_SCHEMAS_INT,
387 xmlSchemaTypeLongDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000388 xmlSchemaTypeShortDef = xmlSchemaInitBasicType("short",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000389 XML_SCHEMAS_SHORT,
390 xmlSchemaTypeIntDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000391 xmlSchemaTypeByteDef = xmlSchemaInitBasicType("byte",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000392 XML_SCHEMAS_BYTE,
393 xmlSchemaTypeShortDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000394 xmlSchemaTypeNonNegativeIntegerDef =
395 xmlSchemaInitBasicType("nonNegativeInteger",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000396 XML_SCHEMAS_NNINTEGER,
397 xmlSchemaTypeIntegerDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000398 xmlSchemaTypeUnsignedLongDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000399 xmlSchemaInitBasicType("unsignedLong", XML_SCHEMAS_ULONG,
400 xmlSchemaTypeNonNegativeIntegerDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000401 xmlSchemaTypeUnsignedIntDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000402 xmlSchemaInitBasicType("unsignedInt", XML_SCHEMAS_UINT,
403 xmlSchemaTypeUnsignedLongDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000404 xmlSchemaTypeUnsignedShortDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000405 xmlSchemaInitBasicType("unsignedShort", XML_SCHEMAS_USHORT,
406 xmlSchemaTypeUnsignedIntDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000407 xmlSchemaTypeUnsignedByteDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000408 xmlSchemaInitBasicType("unsignedByte", XML_SCHEMAS_UBYTE,
409 xmlSchemaTypeUnsignedShortDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000410 xmlSchemaTypePositiveIntegerDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000411 xmlSchemaInitBasicType("positiveInteger", XML_SCHEMAS_PINTEGER,
412 xmlSchemaTypeNonNegativeIntegerDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000413 xmlSchemaTypeNormStringDef = xmlSchemaInitBasicType("normalizedString",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000414 XML_SCHEMAS_NORMSTRING,
415 xmlSchemaTypeStringDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000416 xmlSchemaTypeTokenDef = xmlSchemaInitBasicType("token",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000417 XML_SCHEMAS_TOKEN,
418 xmlSchemaTypeNormStringDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000419 xmlSchemaTypeLanguageDef = xmlSchemaInitBasicType("language",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000420 XML_SCHEMAS_LANGUAGE,
421 xmlSchemaTypeTokenDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000422 xmlSchemaTypeNameDef = xmlSchemaInitBasicType("Name",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000423 XML_SCHEMAS_NAME,
424 xmlSchemaTypeTokenDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000425 xmlSchemaTypeNmtokenDef = xmlSchemaInitBasicType("NMTOKEN",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000426 XML_SCHEMAS_NMTOKEN,
427 xmlSchemaTypeTokenDef);
428 xmlSchemaTypeNCNameDef = xmlSchemaInitBasicType("NCName",
429 XML_SCHEMAS_NCNAME,
430 xmlSchemaTypeNameDef);
431 xmlSchemaTypeIdDef = xmlSchemaInitBasicType("ID", XML_SCHEMAS_ID,
432 xmlSchemaTypeNCNameDef);
433 xmlSchemaTypeIdrefDef = xmlSchemaInitBasicType("IDREF",
434 XML_SCHEMAS_IDREF,
435 xmlSchemaTypeNCNameDef);
436 xmlSchemaTypeIdrefsDef = xmlSchemaInitBasicType("IDREFS",
437 XML_SCHEMAS_IDREFS,
438 xmlSchemaTypeIdrefDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000439 xmlSchemaTypeNmtokensDef = xmlSchemaInitBasicType("NMTOKENS",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000440 XML_SCHEMAS_NMTOKENS,
441 xmlSchemaTypeNmtokenDef);
442 xmlSchemaTypeEntityDef = xmlSchemaInitBasicType("ENTITY",
443 XML_SCHEMAS_ENTITY,
444 xmlSchemaTypeNCNameDef);
445 xmlSchemaTypeEntitiesDef = xmlSchemaInitBasicType("ENTITIES",
446 XML_SCHEMAS_ENTITIES,
447 xmlSchemaTypeNCNameDef);
Daniel Veillard4255d502002-04-16 15:50:10 +0000448 xmlSchemaTypesInitialized = 1;
449}
450
451/**
452 * xmlSchemaCleanupTypes:
453 *
454 * Cleanup the default XML Schemas type library
455 */
456void
457xmlSchemaCleanupTypes(void) {
458 if (xmlSchemaTypesInitialized == 0)
459 return;
Daniel Veillard01fa6152004-06-29 17:04:39 +0000460 xmlSchemaFreeWildcard(xmlSchemaTypeAnyTypeDef->attributeWildcard);
Daniel Veillard4255d502002-04-16 15:50:10 +0000461 xmlHashFree(xmlSchemaTypesBank, (xmlHashDeallocator) xmlSchemaFreeType);
462 xmlSchemaTypesInitialized = 0;
463}
464
465/**
Daniel Veillard6927b102004-10-27 17:29:04 +0000466 * xmlSchemaIsBuiltInTypeFacet:
Daniel Veillard01fa6152004-06-29 17:04:39 +0000467 * @type: the built-in type
468 * @facetType: the facet type
469 *
470 * Evaluates if a specific facet can be
471 * used in conjunction with a type.
472 *
473 * Returns 1 if the facet can be used with the given built-in type,
474 * 0 otherwise and -1 in case the type is not a built-in type.
475 */
476int
477xmlSchemaIsBuiltInTypeFacet(xmlSchemaTypePtr type, int facetType)
478{
Daniel Veillardce682bc2004-11-05 17:22:25 +0000479 if (type == NULL)
480 return (-1);
Daniel Veillard01fa6152004-06-29 17:04:39 +0000481 if (type->type != XML_SCHEMA_TYPE_BASIC)
482 return (-1);
483 switch (type->builtInType) {
484 case XML_SCHEMAS_BOOLEAN:
485 if ((facetType == XML_SCHEMA_FACET_PATTERN) ||
486 (facetType == XML_SCHEMA_FACET_WHITESPACE))
487 return (1);
488 else
489 return (0);
490 case XML_SCHEMAS_STRING:
491 case XML_SCHEMAS_NOTATION:
492 case XML_SCHEMAS_QNAME:
493 case XML_SCHEMAS_ANYURI:
494 case XML_SCHEMAS_BASE64BINARY:
495 case XML_SCHEMAS_HEXBINARY:
496 if ((facetType == XML_SCHEMA_FACET_LENGTH) ||
497 (facetType == XML_SCHEMA_FACET_MINLENGTH) ||
498 (facetType == XML_SCHEMA_FACET_MAXLENGTH) ||
499 (facetType == XML_SCHEMA_FACET_PATTERN) ||
500 (facetType == XML_SCHEMA_FACET_ENUMERATION) ||
501 (facetType == XML_SCHEMA_FACET_WHITESPACE))
502 return (1);
503 else
504 return (0);
505 case XML_SCHEMAS_DECIMAL:
506 if ((facetType == XML_SCHEMA_FACET_TOTALDIGITS) ||
507 (facetType == XML_SCHEMA_FACET_FRACTIONDIGITS) ||
508 (facetType == XML_SCHEMA_FACET_PATTERN) ||
509 (facetType == XML_SCHEMA_FACET_WHITESPACE) ||
510 (facetType == XML_SCHEMA_FACET_ENUMERATION) ||
511 (facetType == XML_SCHEMA_FACET_MAXINCLUSIVE) ||
512 (facetType == XML_SCHEMA_FACET_MAXEXCLUSIVE) ||
513 (facetType == XML_SCHEMA_FACET_MININCLUSIVE) ||
514 (facetType == XML_SCHEMA_FACET_MINEXCLUSIVE))
515 return (1);
516 else
517 return (0);
518 case XML_SCHEMAS_TIME:
519 case XML_SCHEMAS_GDAY:
520 case XML_SCHEMAS_GMONTH:
521 case XML_SCHEMAS_GMONTHDAY:
522 case XML_SCHEMAS_GYEAR:
523 case XML_SCHEMAS_GYEARMONTH:
524 case XML_SCHEMAS_DATE:
525 case XML_SCHEMAS_DATETIME:
526 case XML_SCHEMAS_DURATION:
527 case XML_SCHEMAS_FLOAT:
528 case XML_SCHEMAS_DOUBLE:
529 if ((facetType == XML_SCHEMA_FACET_PATTERN) ||
530 (facetType == XML_SCHEMA_FACET_ENUMERATION) ||
531 (facetType == XML_SCHEMA_FACET_WHITESPACE) ||
532 (facetType == XML_SCHEMA_FACET_MAXINCLUSIVE) ||
533 (facetType == XML_SCHEMA_FACET_MAXEXCLUSIVE) ||
534 (facetType == XML_SCHEMA_FACET_MININCLUSIVE) ||
535 (facetType == XML_SCHEMA_FACET_MINEXCLUSIVE))
536 return (1);
537 else
538 return (0);
539 default:
Daniel Veillardc7e3cc42004-09-28 12:33:52 +0000540 break;
Daniel Veillard01fa6152004-06-29 17:04:39 +0000541 }
542 return (0);
543}
544
545/**
546 * xmlSchemaGetBuiltInType:
547 * @type: the type of the built in type
548 *
549 * Gives you the type struct for a built-in
550 * type by its type id.
551 *
552 * Returns the type if found, NULL otherwise.
553 */
554xmlSchemaTypePtr
555xmlSchemaGetBuiltInType(xmlSchemaValType type)
556{
557 if (xmlSchemaTypesInitialized == 0)
558 xmlSchemaInitTypes();
559 switch (type) {
560
561 case XML_SCHEMAS_ANYSIMPLETYPE:
562 return (xmlSchemaTypeAnySimpleTypeDef);
563 case XML_SCHEMAS_STRING:
564 return (xmlSchemaTypeStringDef);
565 case XML_SCHEMAS_NORMSTRING:
566 return (xmlSchemaTypeNormStringDef);
567 case XML_SCHEMAS_DECIMAL:
568 return (xmlSchemaTypeDecimalDef);
569 case XML_SCHEMAS_TIME:
570 return (xmlSchemaTypeTimeDef);
571 case XML_SCHEMAS_GDAY:
572 return (xmlSchemaTypeGDayDef);
573 case XML_SCHEMAS_GMONTH:
574 return (xmlSchemaTypeGMonthDef);
575 case XML_SCHEMAS_GMONTHDAY:
576 return (xmlSchemaTypeGMonthDayDef);
577 case XML_SCHEMAS_GYEAR:
578 return (xmlSchemaTypeGYearDef);
579 case XML_SCHEMAS_GYEARMONTH:
580 return (xmlSchemaTypeGYearMonthDef);
581 case XML_SCHEMAS_DATE:
582 return (xmlSchemaTypeDateDef);
583 case XML_SCHEMAS_DATETIME:
584 return (xmlSchemaTypeDatetimeDef);
585 case XML_SCHEMAS_DURATION:
586 return (xmlSchemaTypeDurationDef);
587 case XML_SCHEMAS_FLOAT:
588 return (xmlSchemaTypeFloatDef);
589 case XML_SCHEMAS_DOUBLE:
590 return (xmlSchemaTypeDoubleDef);
591 case XML_SCHEMAS_BOOLEAN:
592 return (xmlSchemaTypeBooleanDef);
593 case XML_SCHEMAS_TOKEN:
594 return (xmlSchemaTypeTokenDef);
595 case XML_SCHEMAS_LANGUAGE:
596 return (xmlSchemaTypeLanguageDef);
597 case XML_SCHEMAS_NMTOKEN:
598 return (xmlSchemaTypeNmtokenDef);
599 case XML_SCHEMAS_NMTOKENS:
600 return (xmlSchemaTypeNmtokensDef);
601 case XML_SCHEMAS_NAME:
602 return (xmlSchemaTypeNameDef);
603 case XML_SCHEMAS_QNAME:
604 return (xmlSchemaTypeQNameDef);
605 case XML_SCHEMAS_NCNAME:
606 return (xmlSchemaTypeNCNameDef);
607 case XML_SCHEMAS_ID:
608 return (xmlSchemaTypeIdDef);
609 case XML_SCHEMAS_IDREF:
610 return (xmlSchemaTypeIdrefDef);
611 case XML_SCHEMAS_IDREFS:
612 return (xmlSchemaTypeIdrefsDef);
613 case XML_SCHEMAS_ENTITY:
614 return (xmlSchemaTypeEntityDef);
615 case XML_SCHEMAS_ENTITIES:
616 return (xmlSchemaTypeEntitiesDef);
617 case XML_SCHEMAS_NOTATION:
618 return (xmlSchemaTypeNotationDef);
619 case XML_SCHEMAS_ANYURI:
620 return (xmlSchemaTypeAnyURIDef);
621 case XML_SCHEMAS_INTEGER:
622 return (xmlSchemaTypeIntegerDef);
623 case XML_SCHEMAS_NPINTEGER:
624 return (xmlSchemaTypeNonPositiveIntegerDef);
625 case XML_SCHEMAS_NINTEGER:
626 return (xmlSchemaTypeNegativeIntegerDef);
627 case XML_SCHEMAS_NNINTEGER:
628 return (xmlSchemaTypeNonNegativeIntegerDef);
629 case XML_SCHEMAS_PINTEGER:
630 return (xmlSchemaTypePositiveIntegerDef);
631 case XML_SCHEMAS_INT:
632 return (xmlSchemaTypeIntDef);
633 case XML_SCHEMAS_UINT:
634 return (xmlSchemaTypeUnsignedIntDef);
635 case XML_SCHEMAS_LONG:
636 return (xmlSchemaTypeLongDef);
637 case XML_SCHEMAS_ULONG:
638 return (xmlSchemaTypeUnsignedLongDef);
639 case XML_SCHEMAS_SHORT:
640 return (xmlSchemaTypeShortDef);
641 case XML_SCHEMAS_USHORT:
642 return (xmlSchemaTypeUnsignedShortDef);
643 case XML_SCHEMAS_BYTE:
644 return (xmlSchemaTypeByteDef);
645 case XML_SCHEMAS_UBYTE:
646 return (xmlSchemaTypeUnsignedByteDef);
647 case XML_SCHEMAS_HEXBINARY:
648 return (xmlSchemaTypeHexBinaryDef);
649 case XML_SCHEMAS_BASE64BINARY:
650 return (xmlSchemaTypeBase64BinaryDef);
651 case XML_SCHEMAS_ANYTYPE:
652 return (xmlSchemaTypeAnyTypeDef);
653 default:
654 return (NULL);
655 }
656}
657
658/**
Daniel Veillard4255d502002-04-16 15:50:10 +0000659 * xmlSchemaNewValue:
660 * @type: the value type
661 *
662 * Allocate a new simple type value
663 *
664 * Returns a pointer to the new value or NULL in case of error
665 */
666static xmlSchemaValPtr
667xmlSchemaNewValue(xmlSchemaValType type) {
668 xmlSchemaValPtr value;
669
670 value = (xmlSchemaValPtr) xmlMalloc(sizeof(xmlSchemaVal));
671 if (value == NULL) {
672 return(NULL);
673 }
674 memset(value, 0, sizeof(xmlSchemaVal));
675 value->type = type;
676 return(value);
677}
678
679/**
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +0000680 * xmlSchemaNewStringValue:
681 * @type: the value type
Daniel Veillardb5839c32005-02-19 18:27:14 +0000682 * @value: the value
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +0000683 *
684 * Allocate a new simple type value. The type can be
Kasimier T. Buchcik2ee855d2005-03-07 11:14:14 +0000685 * of XML_SCHEMAS_STRING.
686 * WARNING: This one is intended to be expanded for other
687 * string based types. We need this for anySimpleType as well.
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +0000688 *
689 * Returns a pointer to the new value or NULL in case of error
690 */
691xmlSchemaValPtr
692xmlSchemaNewStringValue(xmlSchemaValType type,
693 const xmlChar *value)
694{
695 xmlSchemaValPtr val;
696
697 if (type != XML_SCHEMAS_STRING)
698 return(NULL);
699 val = (xmlSchemaValPtr) xmlMalloc(sizeof(xmlSchemaVal));
700 if (val == NULL) {
701 return(NULL);
702 }
703 memset(val, 0, sizeof(xmlSchemaVal));
704 val->type = type;
705 val->value.str = (xmlChar *) value;
706 return(val);
707}
708
Kasimier T. Buchcikb06b4de2005-02-17 19:00:23 +0000709/**
710 * xmlSchemaNewNOTATIONValue:
Daniel Veillardb5839c32005-02-19 18:27:14 +0000711 * @name: the notation name
712 * @ns: the notation namespace name or NULL
Kasimier T. Buchcikb06b4de2005-02-17 19:00:23 +0000713 *
714 * Allocate a new NOTATION value.
715 *
716 * Returns a pointer to the new value or NULL in case of error
717 */
718xmlSchemaValPtr
719xmlSchemaNewNOTATIONValue(const xmlChar *name,
720 const xmlChar *ns)
721{
722 xmlSchemaValPtr val;
723
724 val = xmlSchemaNewValue(XML_SCHEMAS_NOTATION);
725 if (val == NULL)
726 return (NULL);
727
William M. Brack12d37ab2005-02-21 13:54:07 +0000728 val->value.qname.name = (xmlChar *)name;
Kasimier T. Buchcikb06b4de2005-02-17 19:00:23 +0000729 if (ns != NULL)
William M. Brack12d37ab2005-02-21 13:54:07 +0000730 val->value.qname.uri = (xmlChar *)ns;
Kasimier T. Buchcikb06b4de2005-02-17 19:00:23 +0000731 return(val);
732}
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +0000733
734/**
Daniel Veillard4255d502002-04-16 15:50:10 +0000735 * xmlSchemaFreeValue:
736 * @value: the value to free
737 *
738 * Cleanup the default XML Schemas type library
739 */
740void
741xmlSchemaFreeValue(xmlSchemaValPtr value) {
742 if (value == NULL)
743 return;
Daniel Veillardc4c21552003-03-29 10:53:38 +0000744 switch (value->type) {
745 case XML_SCHEMAS_STRING:
746 case XML_SCHEMAS_NORMSTRING:
747 case XML_SCHEMAS_TOKEN:
748 case XML_SCHEMAS_LANGUAGE:
749 case XML_SCHEMAS_NMTOKEN:
750 case XML_SCHEMAS_NMTOKENS:
751 case XML_SCHEMAS_NAME:
Daniel Veillardc4c21552003-03-29 10:53:38 +0000752 case XML_SCHEMAS_NCNAME:
753 case XML_SCHEMAS_ID:
754 case XML_SCHEMAS_IDREF:
755 case XML_SCHEMAS_IDREFS:
756 case XML_SCHEMAS_ENTITY:
Kasimier T. Buchcikb06b4de2005-02-17 19:00:23 +0000757 case XML_SCHEMAS_ENTITIES:
Daniel Veillardc4c21552003-03-29 10:53:38 +0000758 case XML_SCHEMAS_ANYURI:
759 if (value->value.str != NULL)
760 xmlFree(value->value.str);
761 break;
Kasimier T. Buchcikb06b4de2005-02-17 19:00:23 +0000762 case XML_SCHEMAS_NOTATION:
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000763 case XML_SCHEMAS_QNAME:
764 if (value->value.qname.uri != NULL)
765 xmlFree(value->value.qname.uri);
766 if (value->value.qname.name != NULL)
767 xmlFree(value->value.qname.name);
768 break;
Daniel Veillard70bcb0e2003-08-08 14:00:28 +0000769 case XML_SCHEMAS_HEXBINARY:
770 if (value->value.hex.str != NULL)
771 xmlFree(value->value.hex.str);
772 break;
Daniel Veillard1ac24d32003-08-27 14:15:15 +0000773 case XML_SCHEMAS_BASE64BINARY:
774 if (value->value.base64.str != NULL)
775 xmlFree(value->value.base64.str);
776 break;
Daniel Veillardc4c21552003-03-29 10:53:38 +0000777 default:
778 break;
779 }
Daniel Veillard4255d502002-04-16 15:50:10 +0000780 xmlFree(value);
781}
782
783/**
784 * xmlSchemaGetPredefinedType:
785 * @name: the type name
786 * @ns: the URI of the namespace usually "http://www.w3.org/2001/XMLSchema"
787 *
788 * Lookup a type in the default XML Schemas type library
789 *
790 * Returns the type if found, NULL otherwise
791 */
792xmlSchemaTypePtr
793xmlSchemaGetPredefinedType(const xmlChar *name, const xmlChar *ns) {
794 if (xmlSchemaTypesInitialized == 0)
795 xmlSchemaInitTypes();
796 if (name == NULL)
797 return(NULL);
798 return((xmlSchemaTypePtr) xmlHashLookup2(xmlSchemaTypesBank, name, ns));
799}
Daniel Veillard070803b2002-05-03 07:29:38 +0000800
Daniel Veillard01fa6152004-06-29 17:04:39 +0000801/**
802 * xmlSchemaGetBuiltInListSimpleTypeItemType:
803 * @type: the built-in simple type.
804 *
Daniel Veillard6927b102004-10-27 17:29:04 +0000805 * Lookup function
806 *
Daniel Veillardc0826a72004-08-10 14:17:33 +0000807 * Returns the item type of @type as defined by the built-in datatype
808 * hierarchy of XML Schema Part 2: Datatypes, or NULL in case of an error.
Daniel Veillard01fa6152004-06-29 17:04:39 +0000809 */
810xmlSchemaTypePtr
811xmlSchemaGetBuiltInListSimpleTypeItemType(xmlSchemaTypePtr type)
812{
Daniel Veillard42595322004-11-08 10:52:06 +0000813 if ((type == NULL) || (type->type != XML_SCHEMA_TYPE_BASIC))
Daniel Veillard01fa6152004-06-29 17:04:39 +0000814 return (NULL);
815 switch (type->builtInType) {
816 case XML_SCHEMAS_NMTOKENS:
817 return (xmlSchemaTypeNmtokenDef );
818 case XML_SCHEMAS_IDREFS:
819 return (xmlSchemaTypeIdrefDef);
820 case XML_SCHEMAS_ENTITIES:
821 return (xmlSchemaTypeEntityDef);
822 default:
823 return (NULL);
824 }
825}
826
Daniel Veillard070803b2002-05-03 07:29:38 +0000827/****************************************************************
828 * *
829 * Convenience macros and functions *
830 * *
831 ****************************************************************/
832
833#define IS_TZO_CHAR(c) \
834 ((c == 0) || (c == 'Z') || (c == '+') || (c == '-'))
835
836#define VALID_YEAR(yr) (yr != 0)
837#define VALID_MONTH(mon) ((mon >= 1) && (mon <= 12))
838/* VALID_DAY should only be used when month is unknown */
839#define VALID_DAY(day) ((day >= 1) && (day <= 31))
840#define VALID_HOUR(hr) ((hr >= 0) && (hr <= 23))
841#define VALID_MIN(min) ((min >= 0) && (min <= 59))
842#define VALID_SEC(sec) ((sec >= 0) && (sec < 60))
843#define VALID_TZO(tzo) ((tzo > -1440) && (tzo < 1440))
844#define IS_LEAP(y) \
845 (((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0))
846
Daniel Veillardebe25d42004-03-25 09:35:49 +0000847static const unsigned int daysInMonth[12] =
Daniel Veillard070803b2002-05-03 07:29:38 +0000848 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
Daniel Veillardebe25d42004-03-25 09:35:49 +0000849static const unsigned int daysInMonthLeap[12] =
Daniel Veillard070803b2002-05-03 07:29:38 +0000850 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
851
Daniel Veillard5a872412002-05-22 06:40:27 +0000852#define MAX_DAYINMONTH(yr,mon) \
853 (IS_LEAP(yr) ? daysInMonthLeap[mon - 1] : daysInMonth[mon - 1])
854
Daniel Veillard070803b2002-05-03 07:29:38 +0000855#define VALID_MDAY(dt) \
856 (IS_LEAP(dt->year) ? \
857 (dt->day <= daysInMonthLeap[dt->mon - 1]) : \
858 (dt->day <= daysInMonth[dt->mon - 1]))
859
860#define VALID_DATE(dt) \
861 (VALID_YEAR(dt->year) && VALID_MONTH(dt->mon) && VALID_MDAY(dt))
862
863#define VALID_TIME(dt) \
864 (VALID_HOUR(dt->hour) && VALID_MIN(dt->min) && \
865 VALID_SEC(dt->sec) && VALID_TZO(dt->tzo))
866
867#define VALID_DATETIME(dt) \
868 (VALID_DATE(dt) && VALID_TIME(dt))
869
870#define SECS_PER_MIN (60)
871#define SECS_PER_HOUR (60 * SECS_PER_MIN)
872#define SECS_PER_DAY (24 * SECS_PER_HOUR)
873
Daniel Veillard5a872412002-05-22 06:40:27 +0000874static const long dayInYearByMonth[12] =
875 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
876static const long dayInLeapYearByMonth[12] =
877 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 };
878
879#define DAY_IN_YEAR(day, month, year) \
880 ((IS_LEAP(year) ? \
881 dayInLeapYearByMonth[month - 1] : \
882 dayInYearByMonth[month - 1]) + day)
883
884#ifdef DEBUG
885#define DEBUG_DATE(dt) \
886 xmlGenericError(xmlGenericErrorContext, \
887 "type=%o %04ld-%02u-%02uT%02u:%02u:%03f", \
888 dt->type,dt->value.date.year,dt->value.date.mon, \
889 dt->value.date.day,dt->value.date.hour,dt->value.date.min, \
890 dt->value.date.sec); \
891 if (dt->value.date.tz_flag) \
892 if (dt->value.date.tzo != 0) \
893 xmlGenericError(xmlGenericErrorContext, \
894 "%+05d\n",dt->value.date.tzo); \
895 else \
896 xmlGenericError(xmlGenericErrorContext, "Z\n"); \
897 else \
898 xmlGenericError(xmlGenericErrorContext,"\n")
899#else
900#define DEBUG_DATE(dt)
901#endif
902
Daniel Veillard070803b2002-05-03 07:29:38 +0000903/**
904 * _xmlSchemaParseGYear:
905 * @dt: pointer to a date structure
906 * @str: pointer to the string to analyze
907 *
908 * Parses a xs:gYear without time zone and fills in the appropriate
909 * field of the @dt structure. @str is updated to point just after the
910 * xs:gYear. It is supposed that @dt->year is big enough to contain
911 * the year.
912 *
913 * Returns 0 or the error code
914 */
915static int
916_xmlSchemaParseGYear (xmlSchemaValDatePtr dt, const xmlChar **str) {
917 const xmlChar *cur = *str, *firstChar;
918 int isneg = 0, digcnt = 0;
919
920 if (((*cur < '0') || (*cur > '9')) &&
921 (*cur != '-') && (*cur != '+'))
922 return -1;
923
924 if (*cur == '-') {
925 isneg = 1;
926 cur++;
927 }
928
929 firstChar = cur;
930
931 while ((*cur >= '0') && (*cur <= '9')) {
932 dt->year = dt->year * 10 + (*cur - '0');
933 cur++;
934 digcnt++;
935 }
936
937 /* year must be at least 4 digits (CCYY); over 4
938 * digits cannot have a leading zero. */
939 if ((digcnt < 4) || ((digcnt > 4) && (*firstChar == '0')))
940 return 1;
941
942 if (isneg)
943 dt->year = - dt->year;
944
945 if (!VALID_YEAR(dt->year))
946 return 2;
947
948 *str = cur;
949 return 0;
950}
951
952/**
953 * PARSE_2_DIGITS:
954 * @num: the integer to fill in
955 * @cur: an #xmlChar *
956 * @invalid: an integer
957 *
958 * Parses a 2-digits integer and updates @num with the value. @cur is
959 * updated to point just after the integer.
960 * In case of error, @invalid is set to %TRUE, values of @num and
961 * @cur are undefined.
962 */
963#define PARSE_2_DIGITS(num, cur, invalid) \
964 if ((cur[0] < '0') || (cur[0] > '9') || \
965 (cur[1] < '0') || (cur[1] > '9')) \
966 invalid = 1; \
967 else \
968 num = (cur[0] - '0') * 10 + (cur[1] - '0'); \
969 cur += 2;
970
971/**
972 * PARSE_FLOAT:
973 * @num: the double to fill in
974 * @cur: an #xmlChar *
975 * @invalid: an integer
976 *
977 * Parses a float and updates @num with the value. @cur is
978 * updated to point just after the float. The float must have a
979 * 2-digits integer part and may or may not have a decimal part.
980 * In case of error, @invalid is set to %TRUE, values of @num and
981 * @cur are undefined.
982 */
983#define PARSE_FLOAT(num, cur, invalid) \
984 PARSE_2_DIGITS(num, cur, invalid); \
985 if (!invalid && (*cur == '.')) { \
986 double mult = 1; \
987 cur++; \
988 if ((*cur < '0') || (*cur > '9')) \
989 invalid = 1; \
990 while ((*cur >= '0') && (*cur <= '9')) { \
991 mult /= 10; \
992 num += (*cur - '0') * mult; \
993 cur++; \
994 } \
995 }
996
997/**
998 * _xmlSchemaParseGMonth:
999 * @dt: pointer to a date structure
1000 * @str: pointer to the string to analyze
1001 *
1002 * Parses a xs:gMonth without time zone and fills in the appropriate
1003 * field of the @dt structure. @str is updated to point just after the
1004 * xs:gMonth.
1005 *
1006 * Returns 0 or the error code
1007 */
1008static int
1009_xmlSchemaParseGMonth (xmlSchemaValDatePtr dt, const xmlChar **str) {
1010 const xmlChar *cur = *str;
1011 int ret = 0;
1012
1013 PARSE_2_DIGITS(dt->mon, cur, ret);
1014 if (ret != 0)
1015 return ret;
1016
1017 if (!VALID_MONTH(dt->mon))
1018 return 2;
1019
1020 *str = cur;
1021 return 0;
1022}
1023
1024/**
1025 * _xmlSchemaParseGDay:
1026 * @dt: pointer to a date structure
1027 * @str: pointer to the string to analyze
1028 *
1029 * Parses a xs:gDay without time zone and fills in the appropriate
1030 * field of the @dt structure. @str is updated to point just after the
1031 * xs:gDay.
1032 *
1033 * Returns 0 or the error code
1034 */
1035static int
1036_xmlSchemaParseGDay (xmlSchemaValDatePtr dt, const xmlChar **str) {
1037 const xmlChar *cur = *str;
1038 int ret = 0;
1039
1040 PARSE_2_DIGITS(dt->day, cur, ret);
1041 if (ret != 0)
1042 return ret;
1043
1044 if (!VALID_DAY(dt->day))
1045 return 2;
1046
1047 *str = cur;
1048 return 0;
1049}
1050
1051/**
1052 * _xmlSchemaParseTime:
1053 * @dt: pointer to a date structure
1054 * @str: pointer to the string to analyze
1055 *
1056 * Parses a xs:time without time zone and fills in the appropriate
1057 * fields of the @dt structure. @str is updated to point just after the
1058 * xs:time.
1059 * In case of error, values of @dt fields are undefined.
1060 *
1061 * Returns 0 or the error code
1062 */
1063static int
1064_xmlSchemaParseTime (xmlSchemaValDatePtr dt, const xmlChar **str) {
1065 const xmlChar *cur = *str;
1066 unsigned int hour = 0; /* use temp var in case str is not xs:time */
1067 int ret = 0;
1068
1069 PARSE_2_DIGITS(hour, cur, ret);
1070 if (ret != 0)
1071 return ret;
1072
1073 if (*cur != ':')
1074 return 1;
1075 cur++;
1076
1077 /* the ':' insures this string is xs:time */
1078 dt->hour = hour;
1079
1080 PARSE_2_DIGITS(dt->min, cur, ret);
1081 if (ret != 0)
1082 return ret;
1083
1084 if (*cur != ':')
1085 return 1;
1086 cur++;
1087
1088 PARSE_FLOAT(dt->sec, cur, ret);
1089 if (ret != 0)
1090 return ret;
1091
1092 if (!VALID_TIME(dt))
1093 return 2;
1094
1095 *str = cur;
1096 return 0;
1097}
1098
1099/**
1100 * _xmlSchemaParseTimeZone:
1101 * @dt: pointer to a date structure
1102 * @str: pointer to the string to analyze
1103 *
1104 * Parses a time zone without time zone and fills in the appropriate
1105 * field of the @dt structure. @str is updated to point just after the
1106 * time zone.
1107 *
1108 * Returns 0 or the error code
1109 */
1110static int
1111_xmlSchemaParseTimeZone (xmlSchemaValDatePtr dt, const xmlChar **str) {
1112 const xmlChar *cur = *str;
1113 int ret = 0;
1114
1115 if (str == NULL)
1116 return -1;
1117
1118 switch (*cur) {
1119 case 0:
1120 dt->tz_flag = 0;
1121 dt->tzo = 0;
1122 break;
1123
1124 case 'Z':
1125 dt->tz_flag = 1;
1126 dt->tzo = 0;
1127 cur++;
1128 break;
1129
1130 case '+':
1131 case '-': {
1132 int isneg = 0, tmp = 0;
1133 isneg = (*cur == '-');
1134
1135 cur++;
1136
1137 PARSE_2_DIGITS(tmp, cur, ret);
1138 if (ret != 0)
1139 return ret;
1140 if (!VALID_HOUR(tmp))
1141 return 2;
1142
1143 if (*cur != ':')
1144 return 1;
1145 cur++;
1146
1147 dt->tzo = tmp * 60;
1148
1149 PARSE_2_DIGITS(tmp, cur, ret);
1150 if (ret != 0)
1151 return ret;
1152 if (!VALID_MIN(tmp))
1153 return 2;
1154
1155 dt->tzo += tmp;
1156 if (isneg)
1157 dt->tzo = - dt->tzo;
1158
1159 if (!VALID_TZO(dt->tzo))
1160 return 2;
1161
Daniel Veillard5a872412002-05-22 06:40:27 +00001162 dt->tz_flag = 1;
Daniel Veillard070803b2002-05-03 07:29:38 +00001163 break;
1164 }
1165 default:
1166 return 1;
1167 }
1168
1169 *str = cur;
1170 return 0;
1171}
1172
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001173/**
1174 * _xmlSchemaBase64Decode:
1175 * @ch: a character
1176 *
1177 * Converts a base64 encoded character to its base 64 value.
1178 *
1179 * Returns 0-63 (value), 64 (pad), or -1 (not recognized)
1180 */
1181static int
1182_xmlSchemaBase64Decode (const xmlChar ch) {
1183 if (('A' <= ch) && (ch <= 'Z')) return ch - 'A';
1184 if (('a' <= ch) && (ch <= 'z')) return ch - 'a' + 26;
1185 if (('0' <= ch) && (ch <= '9')) return ch - '0' + 52;
1186 if ('+' == ch) return 62;
1187 if ('/' == ch) return 63;
1188 if ('=' == ch) return 64;
1189 return -1;
1190}
1191
Daniel Veillard070803b2002-05-03 07:29:38 +00001192/****************************************************************
1193 * *
1194 * XML Schema Dates/Times Datatypes Handling *
1195 * *
1196 ****************************************************************/
1197
1198/**
1199 * PARSE_DIGITS:
1200 * @num: the integer to fill in
1201 * @cur: an #xmlChar *
1202 * @num_type: an integer flag
1203 *
1204 * Parses a digits integer and updates @num with the value. @cur is
1205 * updated to point just after the integer.
1206 * In case of error, @num_type is set to -1, values of @num and
1207 * @cur are undefined.
1208 */
1209#define PARSE_DIGITS(num, cur, num_type) \
1210 if ((*cur < '0') || (*cur > '9')) \
1211 num_type = -1; \
1212 else \
1213 while ((*cur >= '0') && (*cur <= '9')) { \
1214 num = num * 10 + (*cur - '0'); \
1215 cur++; \
1216 }
1217
1218/**
1219 * PARSE_NUM:
1220 * @num: the double to fill in
1221 * @cur: an #xmlChar *
1222 * @num_type: an integer flag
1223 *
1224 * Parses a float or integer and updates @num with the value. @cur is
1225 * updated to point just after the number. If the number is a float,
1226 * then it must have an integer part and a decimal part; @num_type will
1227 * be set to 1. If there is no decimal part, @num_type is set to zero.
1228 * In case of error, @num_type is set to -1, values of @num and
1229 * @cur are undefined.
1230 */
1231#define PARSE_NUM(num, cur, num_type) \
1232 num = 0; \
1233 PARSE_DIGITS(num, cur, num_type); \
1234 if (!num_type && (*cur == '.')) { \
1235 double mult = 1; \
1236 cur++; \
1237 if ((*cur < '0') || (*cur > '9')) \
1238 num_type = -1; \
1239 else \
1240 num_type = 1; \
1241 while ((*cur >= '0') && (*cur <= '9')) { \
1242 mult /= 10; \
1243 num += (*cur - '0') * mult; \
1244 cur++; \
1245 } \
1246 }
1247
1248/**
Daniel Veillard5a872412002-05-22 06:40:27 +00001249 * xmlSchemaValidateDates:
Daniel Veillard455cc072003-03-31 10:13:23 +00001250 * @type: the expected type or XML_SCHEMAS_UNKNOWN
Daniel Veillard070803b2002-05-03 07:29:38 +00001251 * @dateTime: string to analyze
1252 * @val: the return computed value
1253 *
1254 * Check that @dateTime conforms to the lexical space of one of the date types.
1255 * if true a value is computed and returned in @val.
1256 *
1257 * Returns 0 if this validates, a positive error code number otherwise
1258 * and -1 in case of internal or API error.
1259 */
1260static int
Daniel Veillard455cc072003-03-31 10:13:23 +00001261xmlSchemaValidateDates (xmlSchemaValType type,
Daniel Veillard118aed72002-09-24 14:13:13 +00001262 const xmlChar *dateTime, xmlSchemaValPtr *val) {
Daniel Veillard070803b2002-05-03 07:29:38 +00001263 xmlSchemaValPtr dt;
1264 int ret;
1265 const xmlChar *cur = dateTime;
1266
1267#define RETURN_TYPE_IF_VALID(t) \
1268 if (IS_TZO_CHAR(*cur)) { \
1269 ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur); \
1270 if (ret == 0) { \
1271 if (*cur != 0) \
1272 goto error; \
1273 dt->type = t; \
Daniel Veillard455cc072003-03-31 10:13:23 +00001274 goto done; \
Daniel Veillard070803b2002-05-03 07:29:38 +00001275 } \
1276 }
1277
1278 if (dateTime == NULL)
1279 return -1;
1280
1281 if ((*cur != '-') && (*cur < '0') && (*cur > '9'))
1282 return 1;
1283
1284 dt = xmlSchemaNewValue(XML_SCHEMAS_UNKNOWN);
1285 if (dt == NULL)
1286 return -1;
1287
1288 if ((cur[0] == '-') && (cur[1] == '-')) {
1289 /*
1290 * It's an incomplete date (xs:gMonthDay, xs:gMonth or
1291 * xs:gDay)
1292 */
1293 cur += 2;
1294
1295 /* is it an xs:gDay? */
1296 if (*cur == '-') {
Daniel Veillard455cc072003-03-31 10:13:23 +00001297 if (type == XML_SCHEMAS_GMONTH)
1298 goto error;
Daniel Veillard070803b2002-05-03 07:29:38 +00001299 ++cur;
1300 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
1301 if (ret != 0)
1302 goto error;
1303
1304 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GDAY);
1305
1306 goto error;
1307 }
1308
1309 /*
1310 * it should be an xs:gMonthDay or xs:gMonth
1311 */
1312 ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
1313 if (ret != 0)
1314 goto error;
1315
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001316 /*
1317 * a '-' char could indicate this type is xs:gMonthDay or
1318 * a negative time zone offset. Check for xs:gMonthDay first.
1319 * Also the first three char's of a negative tzo (-MM:SS) can
1320 * appear to be a valid day; so even if the day portion
1321 * of the xs:gMonthDay verifies, we must insure it was not
1322 * a tzo.
1323 */
1324 if (*cur == '-') {
1325 const xmlChar *rewnd = cur;
1326 cur++;
Daniel Veillard070803b2002-05-03 07:29:38 +00001327
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001328 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
1329 if ((ret == 0) && ((*cur == 0) || (*cur != ':'))) {
1330
1331 /*
1332 * we can use the VALID_MDAY macro to validate the month
1333 * and day because the leap year test will flag year zero
1334 * as a leap year (even though zero is an invalid year).
1335 */
1336 if (VALID_MDAY((&(dt->value.date)))) {
1337
1338 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTHDAY);
1339
1340 goto error;
1341 }
1342 }
1343
1344 /*
1345 * not xs:gMonthDay so rewind and check if just xs:gMonth
1346 * with an optional time zone.
1347 */
1348 cur = rewnd;
1349 }
1350
1351 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTH);
Daniel Veillard070803b2002-05-03 07:29:38 +00001352
1353 goto error;
1354 }
1355
1356 /*
1357 * It's a right-truncated date or an xs:time.
1358 * Try to parse an xs:time then fallback on right-truncated dates.
1359 */
1360 if ((*cur >= '0') && (*cur <= '9')) {
1361 ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
1362 if (ret == 0) {
1363 /* it's an xs:time */
1364 RETURN_TYPE_IF_VALID(XML_SCHEMAS_TIME);
1365 }
1366 }
1367
1368 /* fallback on date parsing */
1369 cur = dateTime;
1370
1371 ret = _xmlSchemaParseGYear(&(dt->value.date), &cur);
1372 if (ret != 0)
1373 goto error;
1374
1375 /* is it an xs:gYear? */
1376 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEAR);
1377
1378 if (*cur != '-')
1379 goto error;
1380 cur++;
1381
1382 ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
1383 if (ret != 0)
1384 goto error;
1385
1386 /* is it an xs:gYearMonth? */
1387 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEARMONTH);
1388
1389 if (*cur != '-')
1390 goto error;
1391 cur++;
1392
1393 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
1394 if ((ret != 0) || !VALID_DATE((&(dt->value.date))))
1395 goto error;
1396
1397 /* is it an xs:date? */
1398 RETURN_TYPE_IF_VALID(XML_SCHEMAS_DATE);
1399
1400 if (*cur != 'T')
1401 goto error;
1402 cur++;
1403
1404 /* it should be an xs:dateTime */
1405 ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
1406 if (ret != 0)
1407 goto error;
1408
1409 ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur);
1410 if ((ret != 0) || (*cur != 0) || !VALID_DATETIME((&(dt->value.date))))
1411 goto error;
1412
Daniel Veillard455cc072003-03-31 10:13:23 +00001413
Daniel Veillard070803b2002-05-03 07:29:38 +00001414 dt->type = XML_SCHEMAS_DATETIME;
1415
Daniel Veillard455cc072003-03-31 10:13:23 +00001416done:
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001417#if 1
1418 if ((type != XML_SCHEMAS_UNKNOWN) && (type != dt->type))
1419 goto error;
1420#else
1421 /*
1422 * insure the parsed type is equal to or less significant (right
1423 * truncated) than the desired type.
1424 */
1425 if ((type != XML_SCHEMAS_UNKNOWN) && (type != dt->type)) {
1426
1427 /* time only matches time */
1428 if ((type == XML_SCHEMAS_TIME) && (dt->type == XML_SCHEMAS_TIME))
1429 goto error;
1430
1431 if ((type == XML_SCHEMAS_DATETIME) &&
1432 ((dt->type != XML_SCHEMAS_DATE) ||
1433 (dt->type != XML_SCHEMAS_GYEARMONTH) ||
1434 (dt->type != XML_SCHEMAS_GYEAR)))
1435 goto error;
1436
1437 if ((type == XML_SCHEMAS_DATE) &&
1438 ((dt->type != XML_SCHEMAS_GYEAR) ||
1439 (dt->type != XML_SCHEMAS_GYEARMONTH)))
1440 goto error;
1441
1442 if ((type == XML_SCHEMAS_GYEARMONTH) && (dt->type != XML_SCHEMAS_GYEAR))
1443 goto error;
1444
1445 if ((type == XML_SCHEMAS_GMONTHDAY) && (dt->type != XML_SCHEMAS_GMONTH))
1446 goto error;
1447 }
Daniel Veillard455cc072003-03-31 10:13:23 +00001448#endif
1449
Daniel Veillard070803b2002-05-03 07:29:38 +00001450 if (val != NULL)
1451 *val = dt;
Daniel Veillard80b19092003-03-28 13:29:53 +00001452 else
1453 xmlSchemaFreeValue(dt);
Daniel Veillard070803b2002-05-03 07:29:38 +00001454
1455 return 0;
1456
1457error:
1458 if (dt != NULL)
1459 xmlSchemaFreeValue(dt);
1460 return 1;
1461}
1462
1463/**
Daniel Veillard5a872412002-05-22 06:40:27 +00001464 * xmlSchemaValidateDuration:
Daniel Veillard070803b2002-05-03 07:29:38 +00001465 * @type: the predefined type
1466 * @duration: string to analyze
1467 * @val: the return computed value
1468 *
1469 * Check that @duration conforms to the lexical space of the duration type.
1470 * if true a value is computed and returned in @val.
1471 *
1472 * Returns 0 if this validates, a positive error code number otherwise
1473 * and -1 in case of internal or API error.
1474 */
1475static int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00001476xmlSchemaValidateDuration (xmlSchemaTypePtr type ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +00001477 const xmlChar *duration, xmlSchemaValPtr *val) {
Daniel Veillard070803b2002-05-03 07:29:38 +00001478 const xmlChar *cur = duration;
1479 xmlSchemaValPtr dur;
1480 int isneg = 0;
1481 unsigned int seq = 0;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001482 double num;
1483 int num_type = 0; /* -1 = invalid, 0 = int, 1 = floating */
1484 const xmlChar desig[] = {'Y', 'M', 'D', 'H', 'M', 'S'};
1485 const double multi[] = { 0.0, 0.0, 86400.0, 3600.0, 60.0, 1.0, 0.0};
Daniel Veillard070803b2002-05-03 07:29:38 +00001486
1487 if (duration == NULL)
1488 return -1;
1489
1490 if (*cur == '-') {
1491 isneg = 1;
1492 cur++;
1493 }
1494
1495 /* duration must start with 'P' (after sign) */
1496 if (*cur++ != 'P')
1497 return 1;
1498
Daniel Veillard80b19092003-03-28 13:29:53 +00001499 if (*cur == 0)
1500 return 1;
1501
Daniel Veillard070803b2002-05-03 07:29:38 +00001502 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
1503 if (dur == NULL)
1504 return -1;
1505
1506 while (*cur != 0) {
Daniel Veillard070803b2002-05-03 07:29:38 +00001507
1508 /* input string should be empty or invalid date/time item */
1509 if (seq >= sizeof(desig))
1510 goto error;
1511
1512 /* T designator must be present for time items */
1513 if (*cur == 'T') {
1514 if (seq <= 3) {
1515 seq = 3;
1516 cur++;
1517 } else
1518 return 1;
1519 } else if (seq == 3)
1520 goto error;
1521
1522 /* parse the number portion of the item */
1523 PARSE_NUM(num, cur, num_type);
1524
1525 if ((num_type == -1) || (*cur == 0))
1526 goto error;
1527
1528 /* update duration based on item type */
1529 while (seq < sizeof(desig)) {
1530 if (*cur == desig[seq]) {
1531
1532 /* verify numeric type; only seconds can be float */
1533 if ((num_type != 0) && (seq < (sizeof(desig)-1)))
1534 goto error;
1535
1536 switch (seq) {
1537 case 0:
1538 dur->value.dur.mon = (long)num * 12;
1539 break;
1540 case 1:
1541 dur->value.dur.mon += (long)num;
1542 break;
1543 default:
1544 /* convert to seconds using multiplier */
1545 dur->value.dur.sec += num * multi[seq];
1546 seq++;
1547 break;
1548 }
1549
1550 break; /* exit loop */
1551 }
1552 /* no date designators found? */
1553 if (++seq == 3)
1554 goto error;
1555 }
1556 cur++;
1557 }
1558
1559 if (isneg) {
1560 dur->value.dur.mon = -dur->value.dur.mon;
1561 dur->value.dur.day = -dur->value.dur.day;
1562 dur->value.dur.sec = -dur->value.dur.sec;
1563 }
1564
1565 if (val != NULL)
1566 *val = dur;
Daniel Veillard80b19092003-03-28 13:29:53 +00001567 else
1568 xmlSchemaFreeValue(dur);
Daniel Veillard070803b2002-05-03 07:29:38 +00001569
1570 return 0;
1571
1572error:
1573 if (dur != NULL)
1574 xmlSchemaFreeValue(dur);
1575 return 1;
1576}
1577
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001578/**
1579 * xmlSchemaStrip:
1580 * @value: a value
1581 *
1582 * Removes the leading and ending spaces of a string
1583 *
1584 * Returns the new string or NULL if no change was required.
1585 */
1586static xmlChar *
1587xmlSchemaStrip(const xmlChar *value) {
1588 const xmlChar *start = value, *end, *f;
1589
1590 if (value == NULL) return(NULL);
William M. Brack76e95df2003-10-18 16:20:14 +00001591 while ((*start != 0) && (IS_BLANK_CH(*start))) start++;
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001592 end = start;
1593 while (*end != 0) end++;
1594 f = end;
1595 end--;
William M. Brack76e95df2003-10-18 16:20:14 +00001596 while ((end > start) && (IS_BLANK_CH(*end))) end--;
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001597 end++;
1598 if ((start == value) && (f == end)) return(NULL);
1599 return(xmlStrndup(start, end - start));
1600}
Daniel Veillard96a4b252003-02-06 08:22:32 +00001601
1602/**
Kasimier T. Buchcik91feaf82004-11-12 14:04:58 +00001603 * xmlSchemaWhiteSpaceReplace:
1604 * @value: a value
1605 *
1606 * Replaces 0xd, 0x9 and 0xa with a space.
1607 *
1608 * Returns the new string or NULL if no change was required.
1609 */
1610xmlChar *
1611xmlSchemaWhiteSpaceReplace(const xmlChar *value) {
1612 const xmlChar *cur = value;
1613 xmlChar *ret = NULL, *mcur;
1614
1615 if (value == NULL)
1616 return(NULL);
1617
1618 while ((*cur != 0) &&
1619 (((*cur) != 0xd) && ((*cur) != 0x9) && ((*cur) != 0xa))) {
1620 cur++;
1621 }
1622 if (*cur == 0)
1623 return (NULL);
1624 ret = xmlStrdup(value);
1625 /* TODO FIXME: I guess gcc will bark at this. */
1626 mcur = (xmlChar *) (ret + (cur - value));
1627 do {
1628 if ( ((*mcur) == 0xd) || ((*mcur) == 0x9) || ((*mcur) == 0xa) )
1629 *mcur = ' ';
1630 mcur++;
1631 } while (*mcur != 0);
1632 return(ret);
1633}
1634
1635/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001636 * xmlSchemaCollapseString:
1637 * @value: a value
1638 *
1639 * Removes and normalize white spaces in the string
1640 *
1641 * Returns the new string or NULL if no change was required.
1642 */
Daniel Veillard01fa6152004-06-29 17:04:39 +00001643xmlChar *
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001644xmlSchemaCollapseString(const xmlChar *value) {
1645 const xmlChar *start = value, *end, *f;
1646 xmlChar *g;
1647 int col = 0;
1648
1649 if (value == NULL) return(NULL);
William M. Brack76e95df2003-10-18 16:20:14 +00001650 while ((*start != 0) && (IS_BLANK_CH(*start))) start++;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001651 end = start;
1652 while (*end != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00001653 if ((*end == ' ') && (IS_BLANK_CH(end[1]))) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001654 col = end - start;
1655 break;
1656 } else if ((*end == 0xa) || (*end == 0x9) || (*end == 0xd)) {
1657 col = end - start;
1658 break;
1659 }
1660 end++;
1661 }
1662 if (col == 0) {
1663 f = end;
1664 end--;
William M. Brack76e95df2003-10-18 16:20:14 +00001665 while ((end > start) && (IS_BLANK_CH(*end))) end--;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001666 end++;
1667 if ((start == value) && (f == end)) return(NULL);
1668 return(xmlStrndup(start, end - start));
1669 }
1670 start = xmlStrdup(start);
1671 if (start == NULL) return(NULL);
1672 g = (xmlChar *) (start + col);
1673 end = g;
1674 while (*end != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00001675 if (IS_BLANK_CH(*end)) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001676 end++;
William M. Brack76e95df2003-10-18 16:20:14 +00001677 while (IS_BLANK_CH(*end)) end++;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001678 if (*end != 0)
1679 *g++ = ' ';
1680 } else
1681 *g++ = *end++;
1682 }
1683 *g = 0;
1684 return((xmlChar *) start);
1685}
1686
1687/**
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001688 * xmlSchemaValAtomicListNode:
1689 * @type: the predefined atomic type for a token in the list
1690 * @value: the list value to check
1691 * @ret: the return computed value
1692 * @node: the node containing the value
1693 *
1694 * Check that a value conforms to the lexical space of the predefined
1695 * list type. if true a value is computed and returned in @ret.
1696 *
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001697 * Returns the number of items if this validates, a negative error code
1698 * number otherwise
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001699 */
1700static int
1701xmlSchemaValAtomicListNode(xmlSchemaTypePtr type, const xmlChar *value,
1702 xmlSchemaValPtr *ret, xmlNodePtr node) {
1703 xmlChar *val, *cur, *endval;
1704 int nb_values = 0;
Daniel Veillard580ced82003-03-21 21:22:48 +00001705 int tmp = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001706
1707 if (value == NULL) {
1708 return(-1);
1709 }
1710 val = xmlStrdup(value);
1711 if (val == NULL) {
1712 return(-1);
1713 }
Daniel Veillard6fc5db02005-01-16 00:05:58 +00001714 if (ret != NULL) {
1715 *ret = NULL;
1716 }
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001717 cur = val;
1718 /*
1719 * Split the list
1720 */
William M. Brack76e95df2003-10-18 16:20:14 +00001721 while (IS_BLANK_CH(*cur)) *cur++ = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001722 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00001723 if (IS_BLANK_CH(*cur)) {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001724 *cur = 0;
1725 cur++;
William M. Brack76e95df2003-10-18 16:20:14 +00001726 while (IS_BLANK_CH(*cur)) *cur++ = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001727 } else {
1728 nb_values++;
1729 cur++;
William M. Brack76e95df2003-10-18 16:20:14 +00001730 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001731 }
1732 }
1733 if (nb_values == 0) {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001734 xmlFree(val);
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001735 return(nb_values);
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001736 }
1737 endval = cur;
1738 cur = val;
1739 while ((*cur == 0) && (cur != endval)) cur++;
1740 while (cur != endval) {
1741 tmp = xmlSchemaValPredefTypeNode(type, cur, NULL, node);
1742 if (tmp != 0)
1743 break;
1744 while (*cur != 0) cur++;
1745 while ((*cur == 0) && (cur != endval)) cur++;
1746 }
Daniel Veillard6fc5db02005-01-16 00:05:58 +00001747 /* TODO what return value ? c.f. bug #158628
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001748 if (ret != NULL) {
1749 TODO
Daniel Veillard6fc5db02005-01-16 00:05:58 +00001750 } */
1751 xmlFree(val);
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001752 if (tmp == 0)
1753 return(nb_values);
1754 return(-1);
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001755}
1756
1757/**
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001758 * xmlSchemaParseUInt:
1759 * @str: pointer to the string R/W
1760 * @llo: pointer to the low result
1761 * @lmi: pointer to the mid result
1762 * @lhi: pointer to the high result
1763 *
1764 * Parse an unsigned long into 3 fields.
1765 *
William M. Brackec3b4b72005-03-15 15:50:17 +00001766 * Returns the number of significant digits in the number or
1767 * -1 if overflow of the capacity
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001768 */
1769static int
1770xmlSchemaParseUInt(const xmlChar **str, unsigned long *llo,
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00001771 unsigned long *lmi, unsigned long *lhi) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001772 unsigned long lo = 0, mi = 0, hi = 0;
1773 const xmlChar *tmp, *cur = *str;
1774 int ret = 0, i = 0;
1775
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00001776 while (*cur == '0') { /* ignore leading zeroes */
1777 cur++;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001778 }
1779 tmp = cur;
1780 while ((*tmp != 0) && (*tmp >= '0') && (*tmp <= '9')) {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00001781 i++;tmp++;ret++;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001782 }
1783 if (i > 24) {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00001784 *str = tmp;
1785 return(-1);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001786 }
1787 while (i > 16) {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00001788 hi = hi * 10 + (*cur++ - '0');
1789 i--;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001790 }
1791 while (i > 8) {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00001792 mi = mi * 10 + (*cur++ - '0');
1793 i--;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001794 }
1795 while (i > 0) {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00001796 lo = lo * 10 + (*cur++ - '0');
1797 i--;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001798 }
1799
1800 *str = cur;
1801 *llo = lo;
1802 *lmi = mi;
1803 *lhi = hi;
1804 return(ret);
1805}
1806
1807/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001808 * xmlSchemaValAtomicType:
1809 * @type: the predefined type
1810 * @value: the value to check
1811 * @val: the return computed value
1812 * @node: the node containing the value
1813 * flags: flags to control the vlidation
1814 *
1815 * Check that a value conforms to the lexical space of the atomic type.
1816 * if true a value is computed and returned in @val.
Daniel Veillard01fa6152004-06-29 17:04:39 +00001817 * This checks the value space for list types as well (IDREFS, NMTOKENS).
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001818 *
1819 * Returns 0 if this validates, a positive error code number otherwise
1820 * and -1 in case of internal or API error.
1821 */
1822static int
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001823xmlSchemaValAtomicType(xmlSchemaTypePtr type, const xmlChar * value,
1824 xmlSchemaValPtr * val, xmlNodePtr node, int flags)
1825{
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001826 xmlSchemaValPtr v;
1827 xmlChar *norm = NULL;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001828 int ret = 0;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001829
1830 if (xmlSchemaTypesInitialized == 0)
Daniel Veillard01fa6152004-06-29 17:04:39 +00001831 xmlSchemaInitTypes();
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001832 if (type == NULL)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001833 return (-1);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001834
Daniel Veillardeebd6332004-08-26 10:30:44 +00001835 /*
1836 * validating a non existant text node is similar to validating
1837 * an empty one.
1838 */
1839 if (value == NULL)
1840 value = BAD_CAST "";
1841
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001842 if (val != NULL)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001843 *val = NULL;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001844 if ((flags == 0) && (value != NULL)) {
Kasimier T. Buchcik91feaf82004-11-12 14:04:58 +00001845
Daniel Veillard01fa6152004-06-29 17:04:39 +00001846 if ((type->builtInType != XML_SCHEMAS_STRING) &&
Kasimier T. Buchcik91feaf82004-11-12 14:04:58 +00001847 (type->builtInType != XML_SCHEMAS_ANYTYPE) &&
1848 (type->builtInType != XML_SCHEMAS_ANYSIMPLETYPE)) {
1849 if (type->builtInType == XML_SCHEMAS_NORMSTRING)
1850 norm = xmlSchemaWhiteSpaceReplace(value);
1851 else
1852 norm = xmlSchemaCollapseString(value);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001853 if (norm != NULL)
1854 value = norm;
1855 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001856 }
1857
Daniel Veillard01fa6152004-06-29 17:04:39 +00001858 switch (type->builtInType) {
William M. Brack2f2a6632004-08-20 23:09:47 +00001859 case XML_SCHEMAS_UNKNOWN:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001860 goto error;
William M. Brack2f2a6632004-08-20 23:09:47 +00001861 case XML_SCHEMAS_ANYTYPE:
1862 case XML_SCHEMAS_ANYSIMPLETYPE:
1863 goto return0;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001864 case XML_SCHEMAS_STRING:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001865 goto return0;
Daniel Veillard1516d5b2004-01-22 07:27:45 +00001866 case XML_SCHEMAS_NORMSTRING:{
1867 const xmlChar *cur = value;
1868
1869 while (*cur != 0) {
1870 if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) {
1871 goto return1;
1872 } else {
1873 cur++;
1874 }
1875 }
1876 if (val != NULL) {
1877 v = xmlSchemaNewValue(XML_SCHEMAS_NORMSTRING);
1878 if (v != NULL) {
1879 v->value.str = xmlStrdup(value);
1880 *val = v;
1881 } else {
1882 goto error;
1883 }
1884 }
1885 goto return0;
1886 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001887 case XML_SCHEMAS_DECIMAL:{
William M. Brack273670f2005-03-11 15:55:14 +00001888 const xmlChar *cur = value;
1889 unsigned int len, neg = 0;
1890 xmlChar cval[25];
1891 xmlChar *cptr = cval;
1892 int dec = -1;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001893
1894 if (cur == NULL)
1895 goto return1;
William M. Brack273670f2005-03-11 15:55:14 +00001896 /* First we handle an optional sign */
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001897 if (*cur == '+')
1898 cur++;
1899 else if (*cur == '-') {
1900 neg = 1;
1901 cur++;
1902 }
William M. Brack273670f2005-03-11 15:55:14 +00001903 /*
1904 * Next we "pre-parse" the number, in preparation for calling
1905 * the common routine xmlSchemaParseUInt. We get rid of any
1906 * leading zeroes (because we have reserved only 25 chars),
1907 * and note the position of any decimal point.
1908 */
1909 len = 0;
1910 while (len < 24) {
1911 if ((*cur >= '0') && (*cur <= '9')) {
1912 *cptr++ = *cur;
1913 len++;
1914 } else if (*cur == '.') {
1915 if (dec != -1)
1916 goto return1; /* multiple decimal points */
1917 if (!len) { /* num starts with '.' */
1918 *cptr++ = '0';
1919 len++;
1920 }
1921 dec = len++;
1922 } else
1923 break;
1924 cur++;
1925 }
1926 if (*cur != 0)
1927 goto return1; /* error if any extraneous chars */
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00001928
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001929 if (val != NULL) {
1930 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
1931 if (v != NULL) {
William M. Brack273670f2005-03-11 15:55:14 +00001932 /*
1933 * If a mixed decimal, get rid of trailing zeroes
1934 */
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00001935 if (dec != -1) {
William M. Brack273670f2005-03-11 15:55:14 +00001936 while ((cptr > cval) && (*(cptr-1) == '0')) {
1937 cptr--;
1938 len--;
1939 }
1940 }
1941 *cptr = 0; /* Terminate our (preparsed) string */
1942 cptr = cval;
1943 /*
1944 * Now evaluate the significant digits of the number
1945 */
1946 xmlSchemaParseUInt((const xmlChar **)&cptr,
1947 &v->value.decimal.lo,
1948 &v->value.decimal.mi,
1949 &v->value.decimal.hi);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001950 v->value.decimal.sign = neg;
William M. Brack273670f2005-03-11 15:55:14 +00001951 if (dec == -1) {
1952 v->value.decimal.frac = 0;
1953 v->value.decimal.total = len;
1954 } else {
1955 v->value.decimal.frac = len - dec - 1;
1956 v->value.decimal.total = len - 1;
1957 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001958 *val = v;
1959 }
1960 }
1961 goto return0;
1962 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001963 case XML_SCHEMAS_TIME:
1964 case XML_SCHEMAS_GDAY:
1965 case XML_SCHEMAS_GMONTH:
1966 case XML_SCHEMAS_GMONTHDAY:
1967 case XML_SCHEMAS_GYEAR:
1968 case XML_SCHEMAS_GYEARMONTH:
1969 case XML_SCHEMAS_DATE:
1970 case XML_SCHEMAS_DATETIME:
Daniel Veillard01fa6152004-06-29 17:04:39 +00001971 ret = xmlSchemaValidateDates(type->builtInType, value, val);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001972 break;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001973 case XML_SCHEMAS_DURATION:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001974 ret = xmlSchemaValidateDuration(type, value, val);
1975 break;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001976 case XML_SCHEMAS_FLOAT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001977 case XML_SCHEMAS_DOUBLE:{
1978 const xmlChar *cur = value;
1979 int neg = 0;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001980
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001981 if (cur == NULL)
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00001982 goto return1;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001983 if ((cur[0] == 'N') && (cur[1] == 'a') && (cur[2] == 'N')) {
1984 cur += 3;
1985 if (*cur != 0)
1986 goto return1;
1987 if (val != NULL) {
1988 if (type == xmlSchemaTypeFloatDef) {
1989 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1990 if (v != NULL) {
1991 v->value.f = (float) xmlXPathNAN;
1992 } else {
1993 xmlSchemaFreeValue(v);
1994 goto error;
1995 }
1996 } else {
1997 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1998 if (v != NULL) {
1999 v->value.d = xmlXPathNAN;
2000 } else {
2001 xmlSchemaFreeValue(v);
2002 goto error;
2003 }
2004 }
2005 *val = v;
2006 }
2007 goto return0;
2008 }
2009 if (*cur == '-') {
2010 neg = 1;
2011 cur++;
2012 }
2013 if ((cur[0] == 'I') && (cur[1] == 'N') && (cur[2] == 'F')) {
2014 cur += 3;
2015 if (*cur != 0)
2016 goto return1;
2017 if (val != NULL) {
2018 if (type == xmlSchemaTypeFloatDef) {
2019 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
2020 if (v != NULL) {
2021 if (neg)
2022 v->value.f = (float) xmlXPathNINF;
2023 else
2024 v->value.f = (float) xmlXPathPINF;
2025 } else {
2026 xmlSchemaFreeValue(v);
2027 goto error;
2028 }
2029 } else {
2030 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
2031 if (v != NULL) {
2032 if (neg)
2033 v->value.d = xmlXPathNINF;
2034 else
2035 v->value.d = xmlXPathPINF;
2036 } else {
2037 xmlSchemaFreeValue(v);
2038 goto error;
2039 }
2040 }
2041 *val = v;
2042 }
2043 goto return0;
2044 }
2045 if ((neg == 0) && (*cur == '+'))
2046 cur++;
2047 if ((cur[0] == 0) || (cur[0] == '+') || (cur[0] == '-'))
2048 goto return1;
2049 while ((*cur >= '0') && (*cur <= '9')) {
2050 cur++;
2051 }
2052 if (*cur == '.') {
2053 cur++;
2054 while ((*cur >= '0') && (*cur <= '9'))
2055 cur++;
2056 }
2057 if ((*cur == 'e') || (*cur == 'E')) {
2058 cur++;
2059 if ((*cur == '-') || (*cur == '+'))
2060 cur++;
2061 while ((*cur >= '0') && (*cur <= '9'))
2062 cur++;
2063 }
2064 if (*cur != 0)
2065 goto return1;
2066 if (val != NULL) {
2067 if (type == xmlSchemaTypeFloatDef) {
2068 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
2069 if (v != NULL) {
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00002070 /*
2071 * TODO: sscanf seems not to give the correct
2072 * value for extremely high/low values.
2073 * E.g. "1E-149" results in zero.
2074 */
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002075 if (sscanf((const char *) value, "%f",
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002076 &(v->value.f)) == 1) {
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00002077 *val = v;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002078 } else {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002079 xmlSchemaFreeValue(v);
2080 goto return1;
2081 }
2082 } else {
2083 goto error;
2084 }
2085 } else {
2086 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
2087 if (v != NULL) {
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00002088 /*
2089 * TODO: sscanf seems not to give the correct
2090 * value for extremely high/low values.
2091 */
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002092 if (sscanf((const char *) value, "%lf",
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002093 &(v->value.d)) == 1) {
2094 *val = v;
2095 } else {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002096 xmlSchemaFreeValue(v);
2097 goto return1;
2098 }
2099 } else {
2100 goto error;
2101 }
2102 }
2103 }
2104 goto return0;
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00002105 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002106 case XML_SCHEMAS_BOOLEAN:{
2107 const xmlChar *cur = value;
2108
2109 if ((cur[0] == '0') && (cur[1] == 0))
2110 ret = 0;
2111 else if ((cur[0] == '1') && (cur[1] == 0))
2112 ret = 1;
2113 else if ((cur[0] == 't') && (cur[1] == 'r')
2114 && (cur[2] == 'u') && (cur[3] == 'e')
2115 && (cur[4] == 0))
2116 ret = 1;
2117 else if ((cur[0] == 'f') && (cur[1] == 'a')
2118 && (cur[2] == 'l') && (cur[3] == 's')
2119 && (cur[4] == 'e') && (cur[5] == 0))
2120 ret = 0;
2121 else
2122 goto return1;
2123 if (val != NULL) {
2124 v = xmlSchemaNewValue(XML_SCHEMAS_BOOLEAN);
2125 if (v != NULL) {
2126 v->value.b = ret;
2127 *val = v;
2128 } else {
2129 goto error;
2130 }
2131 }
2132 goto return0;
2133 }
2134 case XML_SCHEMAS_TOKEN:{
2135 const xmlChar *cur = value;
2136
William M. Brack76e95df2003-10-18 16:20:14 +00002137 if (IS_BLANK_CH(*cur))
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002138 goto return1;
2139
2140 while (*cur != 0) {
2141 if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) {
2142 goto return1;
2143 } else if (*cur == ' ') {
2144 cur++;
2145 if (*cur == 0)
2146 goto return1;
2147 if (*cur == ' ')
2148 goto return1;
2149 } else {
2150 cur++;
2151 }
2152 }
2153 if (val != NULL) {
2154 v = xmlSchemaNewValue(XML_SCHEMAS_TOKEN);
2155 if (v != NULL) {
2156 v->value.str = xmlStrdup(value);
2157 *val = v;
2158 } else {
2159 goto error;
2160 }
2161 }
2162 goto return0;
2163 }
2164 case XML_SCHEMAS_LANGUAGE:
2165 if (xmlCheckLanguageID(value) == 1) {
2166 if (val != NULL) {
2167 v = xmlSchemaNewValue(XML_SCHEMAS_LANGUAGE);
2168 if (v != NULL) {
2169 v->value.str = xmlStrdup(value);
2170 *val = v;
2171 } else {
2172 goto error;
2173 }
2174 }
2175 goto return0;
2176 }
2177 goto return1;
2178 case XML_SCHEMAS_NMTOKEN:
2179 if (xmlValidateNMToken(value, 1) == 0) {
2180 if (val != NULL) {
2181 v = xmlSchemaNewValue(XML_SCHEMAS_NMTOKEN);
2182 if (v != NULL) {
2183 v->value.str = xmlStrdup(value);
2184 *val = v;
2185 } else {
2186 goto error;
2187 }
2188 }
2189 goto return0;
2190 }
2191 goto return1;
2192 case XML_SCHEMAS_NMTOKENS:
2193 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeNmtokenDef,
2194 value, val, node);
2195 if (ret > 0)
2196 ret = 0;
2197 else
2198 ret = 1;
2199 goto done;
2200 case XML_SCHEMAS_NAME:
2201 ret = xmlValidateName(value, 1);
Daniel Veillarddf292f72005-01-16 19:00:15 +00002202 if ((ret == 0) && (val != NULL) && (value != NULL)) {
2203 v = xmlSchemaNewValue(XML_SCHEMAS_NAME);
2204 if (v != NULL) {
2205 const xmlChar *start = value, *end;
2206 while (IS_BLANK_CH(*start)) start++;
2207 end = start;
2208 while ((*end != 0) && (!IS_BLANK_CH(*end))) end++;
2209 v->value.str = xmlStrndup(start, end - start);
2210 *val = v;
2211 } else {
2212 goto error;
2213 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002214 }
2215 goto done;
2216 case XML_SCHEMAS_QNAME:{
2217 xmlChar *uri = NULL;
2218 xmlChar *local = NULL;
2219
2220 ret = xmlValidateQName(value, 1);
2221 if ((ret == 0) && (node != NULL)) {
2222 xmlChar *prefix;
2223
2224 local = xmlSplitQName2(value, &prefix);
2225 if (prefix != NULL) {
2226 xmlNsPtr ns;
2227
2228 ns = xmlSearchNs(node->doc, node, prefix);
2229 if (ns == NULL)
2230 ret = 1;
2231 else if (val != NULL)
2232 uri = xmlStrdup(ns->href);
2233 }
2234 if ((local != NULL) && ((val == NULL) || (ret != 0)))
2235 xmlFree(local);
2236 if (prefix != NULL)
2237 xmlFree(prefix);
2238 }
2239 if ((ret == 0) && (val != NULL)) {
2240 v = xmlSchemaNewValue(XML_SCHEMAS_QNAME);
2241 if (v != NULL) {
2242 if (local != NULL)
2243 v->value.qname.name = local;
2244 else
2245 v->value.qname.name = xmlStrdup(value);
2246 if (uri != NULL)
2247 v->value.qname.uri = uri;
2248
2249 *val = v;
2250 } else {
2251 if (local != NULL)
2252 xmlFree(local);
2253 if (uri != NULL)
2254 xmlFree(uri);
2255 goto error;
2256 }
2257 }
2258 goto done;
2259 }
2260 case XML_SCHEMAS_NCNAME:
2261 ret = xmlValidateNCName(value, 1);
2262 if ((ret == 0) && (val != NULL)) {
2263 v = xmlSchemaNewValue(XML_SCHEMAS_NCNAME);
2264 if (v != NULL) {
2265 v->value.str = xmlStrdup(value);
2266 *val = v;
2267 } else {
2268 goto error;
2269 }
2270 }
2271 goto done;
2272 case XML_SCHEMAS_ID:
2273 ret = xmlValidateNCName(value, 1);
2274 if ((ret == 0) && (val != NULL)) {
2275 v = xmlSchemaNewValue(XML_SCHEMAS_ID);
2276 if (v != NULL) {
2277 v->value.str = xmlStrdup(value);
2278 *val = v;
2279 } else {
2280 goto error;
2281 }
2282 }
2283 if ((ret == 0) && (node != NULL) &&
2284 (node->type == XML_ATTRIBUTE_NODE)) {
2285 xmlAttrPtr attr = (xmlAttrPtr) node;
2286
2287 /*
2288 * NOTE: the IDness might have already be declared in the DTD
2289 */
2290 if (attr->atype != XML_ATTRIBUTE_ID) {
2291 xmlIDPtr res;
2292 xmlChar *strip;
2293
2294 strip = xmlSchemaStrip(value);
2295 if (strip != NULL) {
2296 res = xmlAddID(NULL, node->doc, strip, attr);
2297 xmlFree(strip);
2298 } else
2299 res = xmlAddID(NULL, node->doc, value, attr);
2300 if (res == NULL) {
2301 ret = 2;
2302 } else {
2303 attr->atype = XML_ATTRIBUTE_ID;
2304 }
2305 }
2306 }
2307 goto done;
2308 case XML_SCHEMAS_IDREF:
2309 ret = xmlValidateNCName(value, 1);
2310 if ((ret == 0) && (val != NULL)) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00002311 v = xmlSchemaNewValue(XML_SCHEMAS_IDREF);
2312 if (v == NULL)
2313 goto error;
2314 v->value.str = xmlStrdup(value);
2315 *val = v;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002316 }
2317 if ((ret == 0) && (node != NULL) &&
2318 (node->type == XML_ATTRIBUTE_NODE)) {
2319 xmlAttrPtr attr = (xmlAttrPtr) node;
2320 xmlChar *strip;
2321
2322 strip = xmlSchemaStrip(value);
2323 if (strip != NULL) {
2324 xmlAddRef(NULL, node->doc, strip, attr);
2325 xmlFree(strip);
2326 } else
2327 xmlAddRef(NULL, node->doc, value, attr);
2328 attr->atype = XML_ATTRIBUTE_IDREF;
2329 }
2330 goto done;
2331 case XML_SCHEMAS_IDREFS:
2332 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeIdrefDef,
2333 value, val, node);
2334 if (ret < 0)
2335 ret = 2;
2336 else
2337 ret = 0;
2338 if ((ret == 0) && (node != NULL) &&
2339 (node->type == XML_ATTRIBUTE_NODE)) {
2340 xmlAttrPtr attr = (xmlAttrPtr) node;
2341
2342 attr->atype = XML_ATTRIBUTE_IDREFS;
2343 }
2344 goto done;
2345 case XML_SCHEMAS_ENTITY:{
2346 xmlChar *strip;
2347
2348 ret = xmlValidateNCName(value, 1);
2349 if ((node == NULL) || (node->doc == NULL))
2350 ret = 3;
2351 if (ret == 0) {
2352 xmlEntityPtr ent;
2353
2354 strip = xmlSchemaStrip(value);
2355 if (strip != NULL) {
2356 ent = xmlGetDocEntity(node->doc, strip);
2357 xmlFree(strip);
2358 } else {
2359 ent = xmlGetDocEntity(node->doc, value);
2360 }
2361 if ((ent == NULL) ||
2362 (ent->etype !=
2363 XML_EXTERNAL_GENERAL_UNPARSED_ENTITY))
2364 ret = 4;
2365 }
2366 if ((ret == 0) && (val != NULL)) {
2367 TODO;
2368 }
2369 if ((ret == 0) && (node != NULL) &&
2370 (node->type == XML_ATTRIBUTE_NODE)) {
2371 xmlAttrPtr attr = (xmlAttrPtr) node;
2372
2373 attr->atype = XML_ATTRIBUTE_ENTITY;
2374 }
2375 goto done;
2376 }
2377 case XML_SCHEMAS_ENTITIES:
2378 if ((node == NULL) || (node->doc == NULL))
2379 goto return3;
2380 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeEntityDef,
2381 value, val, node);
2382 if (ret <= 0)
2383 ret = 1;
2384 else
2385 ret = 0;
2386 if ((ret == 0) && (node != NULL) &&
2387 (node->type == XML_ATTRIBUTE_NODE)) {
2388 xmlAttrPtr attr = (xmlAttrPtr) node;
2389
2390 attr->atype = XML_ATTRIBUTE_ENTITIES;
2391 }
2392 goto done;
2393 case XML_SCHEMAS_NOTATION:{
2394 xmlChar *uri = NULL;
2395 xmlChar *local = NULL;
2396
2397 ret = xmlValidateQName(value, 1);
2398 if ((ret == 0) && (node != NULL)) {
2399 xmlChar *prefix;
2400
2401 local = xmlSplitQName2(value, &prefix);
2402 if (prefix != NULL) {
2403 xmlNsPtr ns;
2404
2405 ns = xmlSearchNs(node->doc, node, prefix);
2406 if (ns == NULL)
2407 ret = 1;
2408 else if (val != NULL)
2409 uri = xmlStrdup(ns->href);
2410 }
2411 if ((local != NULL) && ((val == NULL) || (ret != 0)))
2412 xmlFree(local);
2413 if (prefix != NULL)
2414 xmlFree(prefix);
2415 }
2416 if ((node == NULL) || (node->doc == NULL))
2417 ret = 3;
2418 if (ret == 0) {
2419 ret = xmlValidateNotationUse(NULL, node->doc, value);
2420 if (ret == 1)
2421 ret = 0;
2422 else
2423 ret = 1;
2424 }
2425 if ((ret == 0) && (val != NULL)) {
2426 v = xmlSchemaNewValue(XML_SCHEMAS_NOTATION);
2427 if (v != NULL) {
2428 if (local != NULL)
2429 v->value.qname.name = local;
2430 else
2431 v->value.qname.name = xmlStrdup(value);
2432 if (uri != NULL)
2433 v->value.qname.uri = uri;
2434
2435 *val = v;
2436 } else {
2437 if (local != NULL)
2438 xmlFree(local);
2439 if (uri != NULL)
2440 xmlFree(uri);
2441 goto error;
2442 }
2443 }
2444 goto done;
2445 }
2446 case XML_SCHEMAS_ANYURI:{
Daniel Veillard11c466a2004-03-14 12:20:15 +00002447 if (*value != 0) {
2448 xmlURIPtr uri = xmlParseURI((const char *) value);
2449 if (uri == NULL)
2450 goto return1;
2451 xmlFreeURI(uri);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002452 }
Daniel Veillard11c466a2004-03-14 12:20:15 +00002453
2454 if (val != NULL) {
2455 v = xmlSchemaNewValue(XML_SCHEMAS_ANYURI);
2456 if (v == NULL)
2457 goto error;
2458 v->value.str = xmlStrdup(value);
2459 *val = v;
2460 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002461 goto return0;
2462 }
2463 case XML_SCHEMAS_HEXBINARY:{
2464 const xmlChar *cur = value;
2465 xmlChar *base;
2466 int total, i = 0;
2467
Daniel Veillardf34a20e2004-08-31 08:42:17 +00002468 if (cur == NULL)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002469 goto return1;
2470
2471 while (((*cur >= '0') && (*cur <= '9')) ||
2472 ((*cur >= 'A') && (*cur <= 'F')) ||
2473 ((*cur >= 'a') && (*cur <= 'f'))) {
2474 i++;
2475 cur++;
2476 }
2477
2478 if (*cur != 0)
2479 goto return1;
2480 if ((i % 2) != 0)
2481 goto return1;
2482
2483 if (val != NULL) {
2484
2485 v = xmlSchemaNewValue(XML_SCHEMAS_HEXBINARY);
2486 if (v == NULL)
2487 goto error;
2488
2489 cur = xmlStrdup(value);
2490 if (cur == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002491 xmlSchemaTypeErrMemory(node, "allocating hexbin data");
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002492 xmlFree(v);
2493 goto return1;
2494 }
2495
2496 total = i / 2; /* number of octets */
2497
2498 base = (xmlChar *) cur;
2499 while (i-- > 0) {
2500 if (*base >= 'a')
2501 *base = *base - ('a' - 'A');
2502 base++;
2503 }
2504
2505 v->value.hex.str = (xmlChar *) cur;
2506 v->value.hex.total = total;
2507 *val = v;
2508 }
2509 goto return0;
2510 }
2511 case XML_SCHEMAS_BASE64BINARY:{
2512 /* ISSUE:
2513 *
2514 * Ignore all stray characters? (yes, currently)
2515 * Worry about long lines? (no, currently)
2516 *
2517 * rfc2045.txt:
2518 *
2519 * "The encoded output stream must be represented in lines of
2520 * no more than 76 characters each. All line breaks or other
2521 * characters not found in Table 1 must be ignored by decoding
2522 * software. In base64 data, characters other than those in
2523 * Table 1, line breaks, and other white space probably
2524 * indicate a transmission error, about which a warning
2525 * message or even a message rejection might be appropriate
2526 * under some circumstances." */
2527 const xmlChar *cur = value;
2528 xmlChar *base;
2529 int total, i = 0, pad = 0;
2530
2531 if (cur == NULL)
2532 goto return1;
2533
2534 for (; *cur; ++cur) {
2535 int decc;
2536
2537 decc = _xmlSchemaBase64Decode(*cur);
2538 if (decc < 0) ;
2539 else if (decc < 64)
2540 i++;
2541 else
2542 break;
2543 }
2544 for (; *cur; ++cur) {
2545 int decc;
2546
2547 decc = _xmlSchemaBase64Decode(*cur);
2548 if (decc < 0) ;
2549 else if (decc < 64)
2550 goto return1;
2551 if (decc == 64)
2552 pad++;
2553 }
2554
2555 /* rfc2045.txt: "Special processing is performed if fewer than
2556 * 24 bits are available at the end of the data being encoded.
2557 * A full encoding quantum is always completed at the end of a
2558 * body. When fewer than 24 input bits are available in an
2559 * input group, zero bits are added (on the right) to form an
2560 * integral number of 6-bit groups. Padding at the end of the
2561 * data is performed using the "=" character. Since all
2562 * base64 input is an integral number of octets, only the
2563 * following cases can arise: (1) the final quantum of
2564 * encoding input is an integral multiple of 24 bits; here,
2565 * the final unit of encoded output will be an integral
2566 * multiple ofindent: Standard input:701: Warning:old style
2567 * assignment ambiguity in "=*". Assuming "= *" 4 characters
2568 * with no "=" padding, (2) the final
2569 * quantum of encoding input is exactly 8 bits; here, the
2570 * final unit of encoded output will be two characters
2571 * followed by two "=" padding characters, or (3) the final
2572 * quantum of encoding input is exactly 16 bits; here, the
2573 * final unit of encoded output will be three characters
2574 * followed by one "=" padding character." */
2575
2576 total = 3 * (i / 4);
2577 if (pad == 0) {
2578 if (i % 4 != 0)
2579 goto return1;
2580 } else if (pad == 1) {
2581 int decc;
2582
2583 if (i % 4 != 3)
2584 goto return1;
2585 for (decc = _xmlSchemaBase64Decode(*cur);
2586 (decc < 0) || (decc > 63);
2587 decc = _xmlSchemaBase64Decode(*cur))
2588 --cur;
2589 /* 16bits in 24bits means 2 pad bits: nnnnnn nnmmmm mmmm00*/
2590 /* 00111100 -> 0x3c */
2591 if (decc & ~0x3c)
2592 goto return1;
2593 total += 2;
2594 } else if (pad == 2) {
2595 int decc;
2596
2597 if (i % 4 != 2)
2598 goto return1;
2599 for (decc = _xmlSchemaBase64Decode(*cur);
2600 (decc < 0) || (decc > 63);
2601 decc = _xmlSchemaBase64Decode(*cur))
2602 --cur;
2603 /* 8bits in 12bits means 4 pad bits: nnnnnn nn0000 */
2604 /* 00110000 -> 0x30 */
2605 if (decc & ~0x30)
2606 goto return1;
2607 total += 1;
2608 } else
2609 goto return1;
2610
2611 if (val != NULL) {
2612 v = xmlSchemaNewValue(XML_SCHEMAS_BASE64BINARY);
2613 if (v == NULL)
2614 goto error;
2615 base =
2616 (xmlChar *) xmlMallocAtomic((i + pad + 1) *
2617 sizeof(xmlChar));
2618 if (base == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002619 xmlSchemaTypeErrMemory(node, "allocating base64 data");
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002620 xmlFree(v);
2621 goto return1;
2622 }
2623 v->value.base64.str = base;
2624 for (cur = value; *cur; ++cur)
2625 if (_xmlSchemaBase64Decode(*cur) >= 0) {
2626 *base = *cur;
2627 ++base;
2628 }
2629 *base = 0;
2630 v->value.base64.total = total;
2631 *val = v;
2632 }
2633 goto return0;
2634 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002635 case XML_SCHEMAS_INTEGER:
2636 case XML_SCHEMAS_PINTEGER:
2637 case XML_SCHEMAS_NPINTEGER:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002638 case XML_SCHEMAS_NINTEGER:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002639 case XML_SCHEMAS_NNINTEGER:{
2640 const xmlChar *cur = value;
2641 unsigned long lo, mi, hi;
William M. Brackec3b4b72005-03-15 15:50:17 +00002642 int sign = 0;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002643
2644 if (cur == NULL)
2645 goto return1;
2646 if (*cur == '-') {
2647 sign = 1;
2648 cur++;
2649 } else if (*cur == '+')
2650 cur++;
William M. Brackec3b4b72005-03-15 15:50:17 +00002651 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2652 if (ret == -1)
2653 goto return1;
2654 if (*cur != 0)
2655 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002656 if (type->builtInType == XML_SCHEMAS_NPINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002657 if ((sign == 0) &&
2658 ((hi != 0) || (mi != 0) || (lo != 0)))
2659 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002660 } else if (type->builtInType == XML_SCHEMAS_PINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002661 if (sign == 1)
2662 goto return1;
2663 if ((hi == 0) && (mi == 0) && (lo == 0))
2664 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002665 } else if (type->builtInType == XML_SCHEMAS_NINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002666 if (sign == 0)
2667 goto return1;
2668 if ((hi == 0) && (mi == 0) && (lo == 0))
2669 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002670 } else if (type->builtInType == XML_SCHEMAS_NNINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002671 if ((sign == 1) &&
2672 ((hi != 0) || (mi != 0) || (lo != 0)))
2673 goto return1;
2674 }
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00002675 if (val != NULL) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00002676 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002677 if (v != NULL) {
2678 v->value.decimal.lo = lo;
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00002679 v->value.decimal.mi = mi;
2680 v->value.decimal.hi = hi;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002681 v->value.decimal.sign = sign;
2682 v->value.decimal.frac = 0;
William M. Brackec3b4b72005-03-15 15:50:17 +00002683 v->value.decimal.total = ret;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002684 *val = v;
2685 }
2686 }
2687 goto return0;
2688 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002689 case XML_SCHEMAS_LONG:
2690 case XML_SCHEMAS_BYTE:
2691 case XML_SCHEMAS_SHORT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002692 case XML_SCHEMAS_INT:{
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00002693 const xmlChar *cur = value;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002694 unsigned long lo, mi, hi;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002695 int sign = 0;
2696
2697 if (cur == NULL)
2698 goto return1;
2699 if (*cur == '-') {
2700 sign = 1;
2701 cur++;
2702 } else if (*cur == '+')
2703 cur++;
William M. Brackec3b4b72005-03-15 15:50:17 +00002704 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2705 if (ret < 0)
2706 goto return1;
2707 if (*cur != 0)
2708 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002709 if (type->builtInType == XML_SCHEMAS_LONG) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002710 if (hi >= 922) {
2711 if (hi > 922)
2712 goto return1;
2713 if (mi >= 33720368) {
2714 if (mi > 33720368)
2715 goto return1;
2716 if ((sign == 0) && (lo > 54775807))
2717 goto return1;
2718 if ((sign == 1) && (lo > 54775808))
2719 goto return1;
2720 }
2721 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002722 } else if (type->builtInType == XML_SCHEMAS_INT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002723 if (hi != 0)
2724 goto return1;
2725 if (mi >= 21) {
2726 if (mi > 21)
2727 goto return1;
2728 if ((sign == 0) && (lo > 47483647))
2729 goto return1;
2730 if ((sign == 1) && (lo > 47483648))
2731 goto return1;
2732 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002733 } else if (type->builtInType == XML_SCHEMAS_SHORT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002734 if ((mi != 0) || (hi != 0))
2735 goto return1;
2736 if ((sign == 1) && (lo > 32768))
2737 goto return1;
2738 if ((sign == 0) && (lo > 32767))
2739 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002740 } else if (type->builtInType == XML_SCHEMAS_BYTE) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002741 if ((mi != 0) || (hi != 0))
2742 goto return1;
2743 if ((sign == 1) && (lo > 128))
2744 goto return1;
2745 if ((sign == 0) && (lo > 127))
2746 goto return1;
2747 }
2748 if (val != NULL) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00002749 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002750 if (v != NULL) {
2751 v->value.decimal.lo = lo;
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00002752 v->value.decimal.mi = mi;
2753 v->value.decimal.hi = hi;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002754 v->value.decimal.sign = sign;
2755 v->value.decimal.frac = 0;
William M. Brackec3b4b72005-03-15 15:50:17 +00002756 v->value.decimal.total = ret;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002757 *val = v;
2758 }
2759 }
2760 goto return0;
2761 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002762 case XML_SCHEMAS_UINT:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002763 case XML_SCHEMAS_ULONG:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002764 case XML_SCHEMAS_USHORT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002765 case XML_SCHEMAS_UBYTE:{
2766 const xmlChar *cur = value;
2767 unsigned long lo, mi, hi;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002768
2769 if (cur == NULL)
2770 goto return1;
William M. Brackec3b4b72005-03-15 15:50:17 +00002771 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2772 if (ret < 0)
2773 goto return1;
2774 if (*cur != 0)
2775 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002776 if (type->builtInType == XML_SCHEMAS_ULONG) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002777 if (hi >= 1844) {
2778 if (hi > 1844)
2779 goto return1;
2780 if (mi >= 67440737) {
2781 if (mi > 67440737)
2782 goto return1;
2783 if (lo > 9551615)
2784 goto return1;
2785 }
2786 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002787 } else if (type->builtInType == XML_SCHEMAS_UINT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002788 if (hi != 0)
2789 goto return1;
2790 if (mi >= 42) {
2791 if (mi > 42)
2792 goto return1;
2793 if (lo > 94967295)
2794 goto return1;
2795 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002796 } else if (type->builtInType == XML_SCHEMAS_USHORT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002797 if ((mi != 0) || (hi != 0))
2798 goto return1;
2799 if (lo > 65535)
2800 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002801 } else if (type->builtInType == XML_SCHEMAS_UBYTE) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002802 if ((mi != 0) || (hi != 0))
2803 goto return1;
2804 if (lo > 255)
2805 goto return1;
2806 }
2807 if (val != NULL) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00002808 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002809 if (v != NULL) {
2810 v->value.decimal.lo = lo;
2811 v->value.decimal.mi = mi;
2812 v->value.decimal.hi = hi;
2813 v->value.decimal.sign = 0;
2814 v->value.decimal.frac = 0;
William M. Brackec3b4b72005-03-15 15:50:17 +00002815 v->value.decimal.total = ret;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002816 *val = v;
2817 }
2818 }
2819 goto return0;
2820 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002821 }
2822
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002823 done:
2824 if (norm != NULL)
2825 xmlFree(norm);
2826 return (ret);
2827 return3:
2828 if (norm != NULL)
2829 xmlFree(norm);
2830 return (3);
2831 return1:
2832 if (norm != NULL)
2833 xmlFree(norm);
2834 return (1);
2835 return0:
2836 if (norm != NULL)
2837 xmlFree(norm);
2838 return (0);
2839 error:
2840 if (norm != NULL)
2841 xmlFree(norm);
2842 return (-1);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002843}
2844
2845/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002846 * xmlSchemaValPredefTypeNode:
Daniel Veillard4255d502002-04-16 15:50:10 +00002847 * @type: the predefined type
2848 * @value: the value to check
2849 * @val: the return computed value
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002850 * @node: the node containing the value
Daniel Veillard4255d502002-04-16 15:50:10 +00002851 *
2852 * Check that a value conforms to the lexical space of the predefined type.
2853 * if true a value is computed and returned in @val.
2854 *
2855 * Returns 0 if this validates, a positive error code number otherwise
2856 * and -1 in case of internal or API error.
2857 */
2858int
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002859xmlSchemaValPredefTypeNode(xmlSchemaTypePtr type, const xmlChar *value,
2860 xmlSchemaValPtr *val, xmlNodePtr node) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002861 return(xmlSchemaValAtomicType(type, value, val, node, 0));
Daniel Veillard4255d502002-04-16 15:50:10 +00002862}
2863
2864/**
Daniel Veillardc0826a72004-08-10 14:17:33 +00002865 * xmlSchemaValPredefTypeNodeNoNorm:
2866 * @type: the predefined type
2867 * @value: the value to check
2868 * @val: the return computed value
2869 * @node: the node containing the value
2870 *
2871 * Check that a value conforms to the lexical space of the predefined type.
2872 * if true a value is computed and returned in @val.
2873 * This one does apply any normalization to the value.
2874 *
2875 * Returns 0 if this validates, a positive error code number otherwise
2876 * and -1 in case of internal or API error.
2877 */
2878int
2879xmlSchemaValPredefTypeNodeNoNorm(xmlSchemaTypePtr type, const xmlChar *value,
2880 xmlSchemaValPtr *val, xmlNodePtr node) {
2881 return(xmlSchemaValAtomicType(type, value, val, node, 1));
2882}
2883
2884/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002885 * xmlSchemaValidatePredefinedType:
2886 * @type: the predefined type
2887 * @value: the value to check
2888 * @val: the return computed value
2889 *
2890 * Check that a value conforms to the lexical space of the predefined type.
2891 * if true a value is computed and returned in @val.
2892 *
2893 * Returns 0 if this validates, a positive error code number otherwise
2894 * and -1 in case of internal or API error.
2895 */
2896int
2897xmlSchemaValidatePredefinedType(xmlSchemaTypePtr type, const xmlChar *value,
2898 xmlSchemaValPtr *val) {
2899 return(xmlSchemaValPredefTypeNode(type, value, val, NULL));
2900}
2901
2902/**
Daniel Veillard4255d502002-04-16 15:50:10 +00002903 * xmlSchemaCompareDecimals:
2904 * @x: a first decimal value
2905 * @y: a second decimal value
2906 *
2907 * Compare 2 decimals
2908 *
2909 * Returns -1 if x < y, 0 if x == y, 1 if x > y and -2 in case of error
2910 */
2911static int
2912xmlSchemaCompareDecimals(xmlSchemaValPtr x, xmlSchemaValPtr y)
2913{
2914 xmlSchemaValPtr swp;
William M. Brack273670f2005-03-11 15:55:14 +00002915 int order = 1, integx, integy, dlen;
2916 unsigned long hi, mi, lo;
Daniel Veillard4255d502002-04-16 15:50:10 +00002917
William M. Brack273670f2005-03-11 15:55:14 +00002918 /*
2919 * First test: If x is -ve and not zero
2920 */
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002921 if ((x->value.decimal.sign) &&
2922 ((x->value.decimal.lo != 0) ||
2923 (x->value.decimal.mi != 0) ||
2924 (x->value.decimal.hi != 0))) {
William M. Brack273670f2005-03-11 15:55:14 +00002925 /*
2926 * Then if y is -ve and not zero reverse the compare
2927 */
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002928 if ((y->value.decimal.sign) &&
2929 ((y->value.decimal.lo != 0) ||
2930 (y->value.decimal.mi != 0) ||
2931 (y->value.decimal.hi != 0)))
Daniel Veillard80b19092003-03-28 13:29:53 +00002932 order = -1;
William M. Brack273670f2005-03-11 15:55:14 +00002933 /*
2934 * Otherwise (y >= 0) we have the answer
2935 */
Daniel Veillard80b19092003-03-28 13:29:53 +00002936 else
2937 return (-1);
William M. Brack273670f2005-03-11 15:55:14 +00002938 /*
2939 * If x is not -ve and y is -ve we have the answer
2940 */
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002941 } else if ((y->value.decimal.sign) &&
2942 ((y->value.decimal.lo != 0) ||
2943 (y->value.decimal.mi != 0) ||
2944 (y->value.decimal.hi != 0))) {
Daniel Veillard4255d502002-04-16 15:50:10 +00002945 return (1);
Daniel Veillard80b19092003-03-28 13:29:53 +00002946 }
William M. Brack273670f2005-03-11 15:55:14 +00002947 /*
2948 * If it's not simply determined by a difference in sign,
2949 * then we need to compare the actual values of the two nums.
2950 * To do this, we start by looking at the integral parts.
2951 * If the number of integral digits differ, then we have our
2952 * answer.
2953 */
2954 integx = x->value.decimal.total - x->value.decimal.frac;
2955 integy = y->value.decimal.total - y->value.decimal.frac;
2956 if (integx > integy)
2957 return order;
2958 else if (integy > integx)
2959 return -order;
2960 /*
2961 * If the number of integral digits is the same for both numbers,
2962 * then things get a little more complicated. We need to "normalize"
2963 * the numbers in order to properly compare them. To do this, we
2964 * look at the total length of each number (length => number of
2965 * significant digits), and divide the "shorter" by 10 (decreasing
2966 * the length) until they are of equal length.
2967 */
2968 dlen = x->value.decimal.total - y->value.decimal.total;
2969 if (dlen < 0) { /* y has more digits than x */
2970 swp = x;
2971 hi = y->value.decimal.hi;
2972 mi = y->value.decimal.mi;
2973 lo = y->value.decimal.lo;
2974 dlen = -dlen;
2975 order = -order;
2976 } else { /* x has more digits than y */
2977 swp = y;
2978 hi = x->value.decimal.hi;
2979 mi = x->value.decimal.mi;
2980 lo = x->value.decimal.lo;
Daniel Veillard4255d502002-04-16 15:50:10 +00002981 }
William M. Brack273670f2005-03-11 15:55:14 +00002982 while (dlen > 8) { /* in effect, right shift by 10**8 */
2983 lo = mi;
2984 mi = hi;
2985 hi = 0;
2986 dlen -= 8;
Daniel Veillard4255d502002-04-16 15:50:10 +00002987 }
William M. Brack273670f2005-03-11 15:55:14 +00002988 while (dlen > 0) {
2989 unsigned long rem1, rem2;
2990 rem1 = (hi % 10) * 100000000L;
2991 hi = hi / 10;
2992 rem2 = (mi % 10) * 100000000L;
2993 mi = (mi + rem1) / 10;
2994 lo = (lo + rem2) / 10;
2995 dlen--;
2996 }
2997 if (hi > swp->value.decimal.hi) {
2998 return order;
2999 } else if (hi == swp->value.decimal.hi) {
3000 if (mi > swp->value.decimal.mi) {
3001 return order;
3002 } else if (mi == swp->value.decimal.mi) {
3003 if (lo > swp->value.decimal.lo) {
3004 return order;
3005 } else if (lo == swp->value.decimal.lo) {
3006 if (x->value.decimal.total == y->value.decimal.total) {
3007 return 0;
3008 } else {
3009 return order;
3010 }
3011 }
3012 }
3013 }
3014 return -order;
Daniel Veillard4255d502002-04-16 15:50:10 +00003015}
3016
3017/**
Daniel Veillard070803b2002-05-03 07:29:38 +00003018 * xmlSchemaCompareDurations:
3019 * @x: a first duration value
3020 * @y: a second duration value
3021 *
3022 * Compare 2 durations
3023 *
3024 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3025 * case of error
3026 */
3027static int
3028xmlSchemaCompareDurations(xmlSchemaValPtr x, xmlSchemaValPtr y)
3029{
3030 long carry, mon, day;
3031 double sec;
Daniel Veillard80b19092003-03-28 13:29:53 +00003032 int invert = 1;
3033 long xmon, xday, myear, minday, maxday;
Daniel Veillard070803b2002-05-03 07:29:38 +00003034 static const long dayRange [2][12] = {
3035 { 0, 28, 59, 89, 120, 150, 181, 212, 242, 273, 303, 334, },
3036 { 0, 31, 62, 92, 123, 153, 184, 215, 245, 276, 306, 337} };
3037
3038 if ((x == NULL) || (y == NULL))
Daniel Veillard5a872412002-05-22 06:40:27 +00003039 return -2;
Daniel Veillard070803b2002-05-03 07:29:38 +00003040
3041 /* months */
3042 mon = x->value.dur.mon - y->value.dur.mon;
3043
3044 /* seconds */
3045 sec = x->value.dur.sec - y->value.dur.sec;
3046 carry = (long)sec / SECS_PER_DAY;
3047 sec -= (double)(carry * SECS_PER_DAY);
3048
3049 /* days */
3050 day = x->value.dur.day - y->value.dur.day + carry;
3051
3052 /* easy test */
3053 if (mon == 0) {
3054 if (day == 0)
3055 if (sec == 0.0)
3056 return 0;
3057 else if (sec < 0.0)
3058 return -1;
3059 else
3060 return 1;
3061 else if (day < 0)
3062 return -1;
3063 else
3064 return 1;
3065 }
3066
3067 if (mon > 0) {
3068 if ((day >= 0) && (sec >= 0.0))
3069 return 1;
3070 else {
3071 xmon = mon;
3072 xday = -day;
3073 }
3074 } else if ((day <= 0) && (sec <= 0.0)) {
3075 return -1;
3076 } else {
Daniel Veillard80b19092003-03-28 13:29:53 +00003077 invert = -1;
Daniel Veillard070803b2002-05-03 07:29:38 +00003078 xmon = -mon;
3079 xday = day;
3080 }
3081
3082 myear = xmon / 12;
Daniel Veillard80b19092003-03-28 13:29:53 +00003083 if (myear == 0) {
3084 minday = 0;
3085 maxday = 0;
3086 } else {
3087 maxday = 366 * ((myear + 3) / 4) +
3088 365 * ((myear - 1) % 4);
3089 minday = maxday - 1;
3090 }
3091
Daniel Veillard070803b2002-05-03 07:29:38 +00003092 xmon = xmon % 12;
3093 minday += dayRange[0][xmon];
3094 maxday += dayRange[1][xmon];
3095
Daniel Veillard80b19092003-03-28 13:29:53 +00003096 if ((maxday == minday) && (maxday == xday))
3097 return(0); /* can this really happen ? */
Daniel Veillard070803b2002-05-03 07:29:38 +00003098 if (maxday < xday)
Daniel Veillard80b19092003-03-28 13:29:53 +00003099 return(-invert);
3100 if (minday > xday)
3101 return(invert);
Daniel Veillard070803b2002-05-03 07:29:38 +00003102
3103 /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00003104 return 2;
3105}
3106
3107/*
3108 * macros for adding date/times and durations
3109 */
3110#define FQUOTIENT(a,b) (floor(((double)a/(double)b)))
3111#define MODULO(a,b) (a - FQUOTIENT(a,b) * b)
3112#define FQUOTIENT_RANGE(a,low,high) (FQUOTIENT((a-low),(high-low)))
3113#define MODULO_RANGE(a,low,high) ((MODULO((a-low),(high-low)))+low)
3114
3115/**
Daniel Veillard669adfc2004-05-29 20:12:46 +00003116 * xmlSchemaDupVal:
3117 * @v: the #xmlSchemaValPtr value to duplicate
3118 *
3119 * Makes a copy of @v. The calling program is responsible for freeing
3120 * the returned value.
3121 *
3122 * returns a pointer to a duplicated #xmlSchemaValPtr or NULL if error.
3123 */
3124static xmlSchemaValPtr
3125xmlSchemaDupVal (xmlSchemaValPtr v)
3126{
3127 xmlSchemaValPtr ret = xmlSchemaNewValue(v->type);
3128 if (ret == NULL)
3129 return NULL;
3130
3131 memcpy(ret, v, sizeof(xmlSchemaVal));
3132 return ret;
3133}
3134
3135/**
Kasimier T. Buchcik285ebab2005-03-04 18:04:59 +00003136 * xmlSchemaCopyValue:
3137 * @val: the precomputed value to be copied
3138 *
3139 * Copies the precomputed value. This duplicates any string within.
3140 *
3141 * Returns the copy or NULL if a copy for a data-type is not implemented.
3142 */
3143xmlSchemaValPtr
3144xmlSchemaCopyValue(xmlSchemaValPtr val)
3145{
3146 xmlSchemaValPtr ret;
3147
3148 if (val == NULL)
3149 return (NULL);
3150 /*
3151 * Copy the string values.
3152 */
3153 switch (val->type) {
3154 case XML_SCHEMAS_IDREFS:
3155 case XML_SCHEMAS_ENTITIES:
3156 case XML_SCHEMAS_NMTOKENS:
3157 case XML_SCHEMAS_ANYTYPE:
3158 case XML_SCHEMAS_ANYSIMPLETYPE:
3159 return (NULL);
3160 case XML_SCHEMAS_STRING:
3161 case XML_SCHEMAS_NORMSTRING:
3162 case XML_SCHEMAS_TOKEN:
3163 case XML_SCHEMAS_LANGUAGE:
3164 case XML_SCHEMAS_NAME:
3165 case XML_SCHEMAS_NCNAME:
3166 case XML_SCHEMAS_ID:
3167 case XML_SCHEMAS_IDREF:
3168 case XML_SCHEMAS_ENTITY:
3169 case XML_SCHEMAS_NMTOKEN:
Kasimier T. Buchcik2ee855d2005-03-07 11:14:14 +00003170 case XML_SCHEMAS_ANYURI:
Kasimier T. Buchcik285ebab2005-03-04 18:04:59 +00003171 ret = xmlSchemaDupVal(val);
3172 if (val->value.str != NULL)
3173 ret->value.str = xmlStrdup(BAD_CAST val->value.str);
3174 return (ret);
Kasimier T. Buchcik2ee855d2005-03-07 11:14:14 +00003175 case XML_SCHEMAS_QNAME:
Kasimier T. Buchcik285ebab2005-03-04 18:04:59 +00003176 case XML_SCHEMAS_NOTATION:
3177 ret = xmlSchemaDupVal(val);
3178 if (val->value.qname.name != NULL)
3179 ret->value.qname.name =
3180 xmlStrdup(BAD_CAST val->value.qname.name);
3181 if (val->value.qname.uri != NULL)
3182 ret->value.qname.uri =
3183 xmlStrdup(BAD_CAST val->value.qname.uri);
3184 return (ret);
3185 case XML_SCHEMAS_HEXBINARY:
3186 ret = xmlSchemaDupVal(val);
3187 if (val->value.hex.str != NULL)
3188 ret->value.hex.str = xmlStrdup(BAD_CAST val->value.hex.str);
3189 return (ret);
3190 case XML_SCHEMAS_BASE64BINARY:
3191 ret = xmlSchemaDupVal(val);
3192 if (val->value.base64.str != NULL)
3193 ret->value.base64.str =
3194 xmlStrdup(BAD_CAST val->value.base64.str);
3195 return (ret);
3196 default:
3197 return (xmlSchemaDupVal(val));
3198 }
3199 return (NULL);
3200}
3201
3202/**
Daniel Veillard5a872412002-05-22 06:40:27 +00003203 * _xmlSchemaDateAdd:
3204 * @dt: an #xmlSchemaValPtr
3205 * @dur: an #xmlSchemaValPtr of type #XS_DURATION
3206 *
3207 * Compute a new date/time from @dt and @dur. This function assumes @dt
3208 * is either #XML_SCHEMAS_DATETIME, #XML_SCHEMAS_DATE, #XML_SCHEMAS_GYEARMONTH,
Daniel Veillard669adfc2004-05-29 20:12:46 +00003209 * or #XML_SCHEMAS_GYEAR. The returned #xmlSchemaVal is the same type as
3210 * @dt. The calling program is responsible for freeing the returned value.
Daniel Veillard5a872412002-05-22 06:40:27 +00003211 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00003212 * Returns a pointer to a new #xmlSchemaVal or NULL if error.
Daniel Veillard5a872412002-05-22 06:40:27 +00003213 */
3214static xmlSchemaValPtr
3215_xmlSchemaDateAdd (xmlSchemaValPtr dt, xmlSchemaValPtr dur)
3216{
Daniel Veillard669adfc2004-05-29 20:12:46 +00003217 xmlSchemaValPtr ret, tmp;
Daniel Veillard5a872412002-05-22 06:40:27 +00003218 long carry, tempdays, temp;
3219 xmlSchemaValDatePtr r, d;
3220 xmlSchemaValDurationPtr u;
3221
3222 if ((dt == NULL) || (dur == NULL))
3223 return NULL;
3224
3225 ret = xmlSchemaNewValue(dt->type);
3226 if (ret == NULL)
3227 return NULL;
3228
Daniel Veillard669adfc2004-05-29 20:12:46 +00003229 /* make a copy so we don't alter the original value */
3230 tmp = xmlSchemaDupVal(dt);
3231 if (tmp == NULL) {
3232 xmlSchemaFreeValue(ret);
3233 return NULL;
3234 }
3235
Daniel Veillard5a872412002-05-22 06:40:27 +00003236 r = &(ret->value.date);
Daniel Veillard669adfc2004-05-29 20:12:46 +00003237 d = &(tmp->value.date);
Daniel Veillard5a872412002-05-22 06:40:27 +00003238 u = &(dur->value.dur);
3239
3240 /* normalization */
3241 if (d->mon == 0)
3242 d->mon = 1;
3243
3244 /* normalize for time zone offset */
3245 u->sec -= (d->tzo * 60);
3246 d->tzo = 0;
3247
3248 /* normalization */
3249 if (d->day == 0)
3250 d->day = 1;
3251
3252 /* month */
3253 carry = d->mon + u->mon;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003254 r->mon = (unsigned int) MODULO_RANGE(carry, 1, 13);
3255 carry = (long) FQUOTIENT_RANGE(carry, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00003256
3257 /* year (may be modified later) */
3258 r->year = d->year + carry;
3259 if (r->year == 0) {
3260 if (d->year > 0)
3261 r->year--;
3262 else
3263 r->year++;
3264 }
3265
3266 /* time zone */
3267 r->tzo = d->tzo;
3268 r->tz_flag = d->tz_flag;
3269
3270 /* seconds */
3271 r->sec = d->sec + u->sec;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003272 carry = (long) FQUOTIENT((long)r->sec, 60);
Daniel Veillard5a872412002-05-22 06:40:27 +00003273 if (r->sec != 0.0) {
3274 r->sec = MODULO(r->sec, 60.0);
3275 }
3276
3277 /* minute */
3278 carry += d->min;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003279 r->min = (unsigned int) MODULO(carry, 60);
3280 carry = (long) FQUOTIENT(carry, 60);
Daniel Veillard5a872412002-05-22 06:40:27 +00003281
3282 /* hours */
3283 carry += d->hour;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003284 r->hour = (unsigned int) MODULO(carry, 24);
3285 carry = (long)FQUOTIENT(carry, 24);
Daniel Veillard5a872412002-05-22 06:40:27 +00003286
3287 /*
3288 * days
3289 * Note we use tempdays because the temporary values may need more
3290 * than 5 bits
3291 */
3292 if ((VALID_YEAR(r->year)) && (VALID_MONTH(r->mon)) &&
3293 (d->day > MAX_DAYINMONTH(r->year, r->mon)))
3294 tempdays = MAX_DAYINMONTH(r->year, r->mon);
3295 else if (d->day < 1)
3296 tempdays = 1;
3297 else
3298 tempdays = d->day;
3299
3300 tempdays += u->day + carry;
3301
3302 while (1) {
3303 if (tempdays < 1) {
Daniel Veillardebe25d42004-03-25 09:35:49 +00003304 long tmon = (long) MODULO_RANGE(r->mon-1, 1, 13);
3305 long tyr = r->year + (long)FQUOTIENT_RANGE(r->mon-1, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00003306 if (tyr == 0)
3307 tyr--;
3308 tempdays += MAX_DAYINMONTH(tyr, tmon);
3309 carry = -1;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003310 } else if (tempdays > (long) MAX_DAYINMONTH(r->year, r->mon)) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003311 tempdays = tempdays - MAX_DAYINMONTH(r->year, r->mon);
3312 carry = 1;
3313 } else
3314 break;
3315
3316 temp = r->mon + carry;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003317 r->mon = (unsigned int) MODULO_RANGE(temp, 1, 13);
3318 r->year = r->year + (unsigned int) FQUOTIENT_RANGE(temp, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00003319 if (r->year == 0) {
3320 if (temp < 1)
3321 r->year--;
3322 else
3323 r->year++;
3324 }
3325 }
3326
3327 r->day = tempdays;
3328
3329 /*
3330 * adjust the date/time type to the date values
3331 */
3332 if (ret->type != XML_SCHEMAS_DATETIME) {
3333 if ((r->hour) || (r->min) || (r->sec))
3334 ret->type = XML_SCHEMAS_DATETIME;
3335 else if (ret->type != XML_SCHEMAS_DATE) {
3336 if ((r->mon != 1) && (r->day != 1))
3337 ret->type = XML_SCHEMAS_DATE;
3338 else if ((ret->type != XML_SCHEMAS_GYEARMONTH) && (r->mon != 1))
3339 ret->type = XML_SCHEMAS_GYEARMONTH;
3340 }
3341 }
3342
Daniel Veillard669adfc2004-05-29 20:12:46 +00003343 xmlSchemaFreeValue(tmp);
Daniel Veillard5a872412002-05-22 06:40:27 +00003344
Daniel Veillard5a872412002-05-22 06:40:27 +00003345 return ret;
3346}
3347
3348/**
3349 * xmlSchemaDateNormalize:
Daniel Veillard669adfc2004-05-29 20:12:46 +00003350 * @dt: an #xmlSchemaValPtr of a date/time type value.
3351 * @offset: number of seconds to adjust @dt by.
Daniel Veillard5a872412002-05-22 06:40:27 +00003352 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00003353 * Normalize @dt to GMT time. The @offset parameter is subtracted from
3354 * the return value is a time-zone offset is present on @dt.
Daniel Veillard5a872412002-05-22 06:40:27 +00003355 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00003356 * Returns a normalized copy of @dt or NULL if error.
Daniel Veillard5a872412002-05-22 06:40:27 +00003357 */
3358static xmlSchemaValPtr
3359xmlSchemaDateNormalize (xmlSchemaValPtr dt, double offset)
3360{
3361 xmlSchemaValPtr dur, ret;
3362
3363 if (dt == NULL)
3364 return NULL;
3365
3366 if (((dt->type != XML_SCHEMAS_TIME) &&
3367 (dt->type != XML_SCHEMAS_DATETIME)) || (dt->value.date.tzo == 0))
3368 return xmlSchemaDupVal(dt);
3369
3370 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
3371 if (dur == NULL)
3372 return NULL;
3373
3374 dur->value.date.sec -= offset;
3375
3376 ret = _xmlSchemaDateAdd(dt, dur);
3377 if (ret == NULL)
3378 return NULL;
3379
3380 xmlSchemaFreeValue(dur);
3381
3382 /* ret->value.date.tzo = 0; */
3383 return ret;
3384}
3385
3386/**
3387 * _xmlSchemaDateCastYMToDays:
3388 * @dt: an #xmlSchemaValPtr
3389 *
3390 * Convert mon and year of @dt to total number of days. Take the
3391 * number of years since (or before) 1 AD and add the number of leap
3392 * years. This is a function because negative
3393 * years must be handled a little differently and there is no zero year.
3394 *
3395 * Returns number of days.
3396 */
3397static long
3398_xmlSchemaDateCastYMToDays (const xmlSchemaValPtr dt)
3399{
3400 long ret;
Daniel Veillard49e89632004-09-23 16:24:36 +00003401 int mon;
Daniel Veillard5a872412002-05-22 06:40:27 +00003402
Daniel Veillard49e89632004-09-23 16:24:36 +00003403 mon = dt->value.date.mon;
3404 if (mon <= 0) mon = 1; /* normalization */
3405
3406 if (dt->value.date.year <= 0)
Daniel Veillard5a872412002-05-22 06:40:27 +00003407 ret = (dt->value.date.year * 365) +
3408 (((dt->value.date.year+1)/4)-((dt->value.date.year+1)/100)+
3409 ((dt->value.date.year+1)/400)) +
Daniel Veillard49e89632004-09-23 16:24:36 +00003410 DAY_IN_YEAR(0, mon, dt->value.date.year);
Daniel Veillard5a872412002-05-22 06:40:27 +00003411 else
3412 ret = ((dt->value.date.year-1) * 365) +
3413 (((dt->value.date.year-1)/4)-((dt->value.date.year-1)/100)+
3414 ((dt->value.date.year-1)/400)) +
Daniel Veillard49e89632004-09-23 16:24:36 +00003415 DAY_IN_YEAR(0, mon, dt->value.date.year);
Daniel Veillard5a872412002-05-22 06:40:27 +00003416
3417 return ret;
3418}
3419
3420/**
3421 * TIME_TO_NUMBER:
3422 * @dt: an #xmlSchemaValPtr
3423 *
3424 * Calculates the number of seconds in the time portion of @dt.
3425 *
3426 * Returns seconds.
3427 */
3428#define TIME_TO_NUMBER(dt) \
3429 ((double)((dt->value.date.hour * SECS_PER_HOUR) + \
Daniel Veillardb3721c22003-03-31 11:22:25 +00003430 (dt->value.date.min * SECS_PER_MIN) + \
3431 (dt->value.date.tzo * SECS_PER_MIN)) + \
3432 dt->value.date.sec)
Daniel Veillard5a872412002-05-22 06:40:27 +00003433
3434/**
3435 * xmlSchemaCompareDates:
3436 * @x: a first date/time value
3437 * @y: a second date/time value
3438 *
3439 * Compare 2 date/times
3440 *
3441 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3442 * case of error
3443 */
3444static int
3445xmlSchemaCompareDates (xmlSchemaValPtr x, xmlSchemaValPtr y)
3446{
3447 unsigned char xmask, ymask, xor_mask, and_mask;
3448 xmlSchemaValPtr p1, p2, q1, q2;
3449 long p1d, p2d, q1d, q2d;
3450
3451 if ((x == NULL) || (y == NULL))
3452 return -2;
3453
3454 if (x->value.date.tz_flag) {
3455
3456 if (!y->value.date.tz_flag) {
3457 p1 = xmlSchemaDateNormalize(x, 0);
3458 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3459 /* normalize y + 14:00 */
3460 q1 = xmlSchemaDateNormalize(y, (14 * SECS_PER_HOUR));
3461
3462 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003463 if (p1d < q1d) {
3464 xmlSchemaFreeValue(p1);
3465 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003466 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003467 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003468 double sec;
3469
3470 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00003471 if (sec < 0.0) {
3472 xmlSchemaFreeValue(p1);
3473 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003474 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003475 } else {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003476 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003477 /* normalize y - 14:00 */
3478 q2 = xmlSchemaDateNormalize(y, -(14 * SECS_PER_HOUR));
3479 q2d = _xmlSchemaDateCastYMToDays(q2) + q2->value.date.day;
3480 if (p1d > q2d)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003481 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003482 else if (p1d == q2d) {
3483 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q2);
3484 if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003485 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003486 else
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003487 ret = 2; /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00003488 }
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003489 xmlSchemaFreeValue(p1);
3490 xmlSchemaFreeValue(q1);
3491 xmlSchemaFreeValue(q2);
3492 if (ret != 0)
3493 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003494 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00003495 } else {
3496 xmlSchemaFreeValue(p1);
3497 xmlSchemaFreeValue(q1);
3498 }
Daniel Veillard5a872412002-05-22 06:40:27 +00003499 }
3500 } else if (y->value.date.tz_flag) {
3501 q1 = xmlSchemaDateNormalize(y, 0);
3502 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
3503
3504 /* normalize x - 14:00 */
3505 p1 = xmlSchemaDateNormalize(x, -(14 * SECS_PER_HOUR));
3506 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3507
Daniel Veillardfdc91562002-07-01 21:52:03 +00003508 if (p1d < q1d) {
3509 xmlSchemaFreeValue(p1);
3510 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003511 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003512 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003513 double sec;
3514
3515 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00003516 if (sec < 0.0) {
3517 xmlSchemaFreeValue(p1);
3518 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003519 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003520 } else {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003521 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003522 /* normalize x + 14:00 */
3523 p2 = xmlSchemaDateNormalize(x, (14 * SECS_PER_HOUR));
3524 p2d = _xmlSchemaDateCastYMToDays(p2) + p2->value.date.day;
3525
Daniel Veillard6560a422003-03-27 21:25:38 +00003526 if (p2d > q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003527 ret = 1;
Daniel Veillard6560a422003-03-27 21:25:38 +00003528 } else if (p2d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003529 sec = TIME_TO_NUMBER(p2) - TIME_TO_NUMBER(q1);
3530 if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003531 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003532 else
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003533 ret = 2; /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00003534 }
Daniel Veillard6560a422003-03-27 21:25:38 +00003535 xmlSchemaFreeValue(p1);
3536 xmlSchemaFreeValue(q1);
3537 xmlSchemaFreeValue(p2);
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003538 if (ret != 0)
3539 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003540 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00003541 } else {
3542 xmlSchemaFreeValue(p1);
3543 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003544 }
3545 }
3546
3547 /*
3548 * if the same type then calculate the difference
3549 */
3550 if (x->type == y->type) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003551 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003552 q1 = xmlSchemaDateNormalize(y, 0);
3553 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
3554
3555 p1 = xmlSchemaDateNormalize(x, 0);
3556 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3557
Daniel Veillardfdc91562002-07-01 21:52:03 +00003558 if (p1d < q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003559 ret = -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003560 } else if (p1d > q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003561 ret = 1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003562 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00003563 double sec;
3564
3565 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
3566 if (sec < 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003567 ret = -1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003568 else if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003569 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003570
3571 }
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003572 xmlSchemaFreeValue(p1);
3573 xmlSchemaFreeValue(q1);
3574 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003575 }
3576
3577 switch (x->type) {
3578 case XML_SCHEMAS_DATETIME:
3579 xmask = 0xf;
3580 break;
3581 case XML_SCHEMAS_DATE:
3582 xmask = 0x7;
3583 break;
3584 case XML_SCHEMAS_GYEAR:
3585 xmask = 0x1;
3586 break;
3587 case XML_SCHEMAS_GMONTH:
3588 xmask = 0x2;
3589 break;
3590 case XML_SCHEMAS_GDAY:
3591 xmask = 0x3;
3592 break;
3593 case XML_SCHEMAS_GYEARMONTH:
3594 xmask = 0x3;
3595 break;
3596 case XML_SCHEMAS_GMONTHDAY:
3597 xmask = 0x6;
3598 break;
3599 case XML_SCHEMAS_TIME:
3600 xmask = 0x8;
3601 break;
3602 default:
3603 xmask = 0;
3604 break;
3605 }
3606
3607 switch (y->type) {
3608 case XML_SCHEMAS_DATETIME:
3609 ymask = 0xf;
3610 break;
3611 case XML_SCHEMAS_DATE:
3612 ymask = 0x7;
3613 break;
3614 case XML_SCHEMAS_GYEAR:
3615 ymask = 0x1;
3616 break;
3617 case XML_SCHEMAS_GMONTH:
3618 ymask = 0x2;
3619 break;
3620 case XML_SCHEMAS_GDAY:
3621 ymask = 0x3;
3622 break;
3623 case XML_SCHEMAS_GYEARMONTH:
3624 ymask = 0x3;
3625 break;
3626 case XML_SCHEMAS_GMONTHDAY:
3627 ymask = 0x6;
3628 break;
3629 case XML_SCHEMAS_TIME:
3630 ymask = 0x8;
3631 break;
3632 default:
3633 ymask = 0;
3634 break;
3635 }
3636
3637 xor_mask = xmask ^ ymask; /* mark type differences */
3638 and_mask = xmask & ymask; /* mark field specification */
3639
3640 /* year */
3641 if (xor_mask & 1)
3642 return 2; /* indeterminate */
3643 else if (and_mask & 1) {
3644 if (x->value.date.year < y->value.date.year)
3645 return -1;
3646 else if (x->value.date.year > y->value.date.year)
3647 return 1;
3648 }
3649
3650 /* month */
3651 if (xor_mask & 2)
3652 return 2; /* indeterminate */
3653 else if (and_mask & 2) {
3654 if (x->value.date.mon < y->value.date.mon)
3655 return -1;
3656 else if (x->value.date.mon > y->value.date.mon)
3657 return 1;
3658 }
3659
3660 /* day */
3661 if (xor_mask & 4)
3662 return 2; /* indeterminate */
3663 else if (and_mask & 4) {
3664 if (x->value.date.day < y->value.date.day)
3665 return -1;
3666 else if (x->value.date.day > y->value.date.day)
3667 return 1;
3668 }
3669
3670 /* time */
3671 if (xor_mask & 8)
3672 return 2; /* indeterminate */
3673 else if (and_mask & 8) {
3674 if (x->value.date.hour < y->value.date.hour)
3675 return -1;
3676 else if (x->value.date.hour > y->value.date.hour)
3677 return 1;
3678 else if (x->value.date.min < y->value.date.min)
3679 return -1;
3680 else if (x->value.date.min > y->value.date.min)
3681 return 1;
3682 else if (x->value.date.sec < y->value.date.sec)
3683 return -1;
3684 else if (x->value.date.sec > y->value.date.sec)
3685 return 1;
3686 }
3687
Daniel Veillard070803b2002-05-03 07:29:38 +00003688 return 0;
3689}
3690
3691/**
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003692 * xmlSchemaComparePreserveReplaceStrings:
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003693 * @x: a first string value
3694 * @y: a second string value
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003695 * @invert: inverts the result if x < y or x > y.
3696 *
3697 * Compare 2 string for their normalized values.
3698 * @x is a string with whitespace of "preserve", @y is
3699 * a string with a whitespace of "replace". I.e. @x could
3700 * be an "xsd:string" and @y an "xsd:normalizedString".
3701 *
3702 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
3703 * case of error
3704 */
3705static int
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003706xmlSchemaComparePreserveReplaceStrings(const xmlChar *x,
3707 const xmlChar *y,
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003708 int invert)
3709{
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003710 int tmp;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003711
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003712 while ((*x != 0) && (*y != 0)) {
3713 if (IS_WSP_REPLACE_CH(*y)) {
3714 if (! IS_WSP_SPACE_CH(*x)) {
3715 if ((*x - 0x20) < 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003716 if (invert)
3717 return(1);
3718 else
3719 return(-1);
3720 } else {
3721 if (invert)
3722 return(-1);
3723 else
3724 return(1);
3725 }
3726 }
3727 } else {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003728 tmp = *x - *y;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003729 if (tmp < 0) {
3730 if (invert)
3731 return(1);
3732 else
3733 return(-1);
3734 }
3735 if (tmp > 0) {
3736 if (invert)
3737 return(-1);
3738 else
3739 return(1);
3740 }
3741 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003742 x++;
3743 y++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003744 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003745 if (*x != 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003746 if (invert)
3747 return(-1);
3748 else
3749 return(1);
3750 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003751 if (*y != 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003752 if (invert)
3753 return(1);
3754 else
3755 return(-1);
3756 }
3757 return(0);
3758}
3759
3760/**
3761 * xmlSchemaComparePreserveCollapseStrings:
3762 * @x: a first string value
3763 * @y: a second string value
3764 *
3765 * Compare 2 string for their normalized values.
3766 * @x is a string with whitespace of "preserve", @y is
3767 * a string with a whitespace of "collapse". I.e. @x could
3768 * be an "xsd:string" and @y an "xsd:normalizedString".
3769 *
3770 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
3771 * case of error
3772 */
3773static int
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003774xmlSchemaComparePreserveCollapseStrings(const xmlChar *x,
3775 const xmlChar *y,
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003776 int invert)
3777{
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003778 int tmp;
3779
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003780 /*
3781 * Skip leading blank chars of the collapsed string.
3782 */
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003783 while IS_WSP_BLANK_CH(*y)
3784 y++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003785
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003786 while ((*x != 0) && (*y != 0)) {
3787 if IS_WSP_BLANK_CH(*y) {
3788 if (! IS_WSP_SPACE_CH(*x)) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003789 /*
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003790 * The yv character would have been replaced to 0x20.
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003791 */
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003792 if ((*x - 0x20) < 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003793 if (invert)
3794 return(1);
3795 else
3796 return(-1);
3797 } else {
3798 if (invert)
3799 return(-1);
3800 else
3801 return(1);
3802 }
3803 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003804 x++;
3805 y++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003806 /*
3807 * Skip contiguous blank chars of the collapsed string.
3808 */
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003809 while IS_WSP_BLANK_CH(*y)
3810 y++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003811 } else {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003812 tmp = *x++ - *y++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003813 if (tmp < 0) {
3814 if (invert)
3815 return(1);
3816 else
3817 return(-1);
3818 }
3819 if (tmp > 0) {
3820 if (invert)
3821 return(-1);
3822 else
3823 return(1);
3824 }
3825 }
3826 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003827 if (*x != 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003828 if (invert)
3829 return(-1);
3830 else
3831 return(1);
3832 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003833 if (*y != 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003834 /*
3835 * Skip trailing blank chars of the collapsed string.
3836 */
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003837 while IS_WSP_BLANK_CH(*y)
3838 y++;
3839 if (*y != 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003840 if (invert)
3841 return(1);
3842 else
3843 return(-1);
3844 }
3845 }
3846 return(0);
3847}
3848
3849/**
3850 * xmlSchemaComparePreserveCollapseStrings:
3851 * @x: a first string value
3852 * @y: a second string value
3853 *
3854 * Compare 2 string for their normalized values.
3855 * @x is a string with whitespace of "preserve", @y is
3856 * a string with a whitespace of "collapse". I.e. @x could
3857 * be an "xsd:string" and @y an "xsd:normalizedString".
3858 *
3859 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
3860 * case of error
3861 */
3862static int
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003863xmlSchemaCompareReplaceCollapseStrings(const xmlChar *x,
3864 const xmlChar *y,
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003865 int invert)
3866{
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003867 int tmp;
3868
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003869 /*
3870 * Skip leading blank chars of the collapsed string.
3871 */
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003872 while IS_WSP_BLANK_CH(*y)
3873 y++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003874
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003875 while ((*x != 0) && (*y != 0)) {
3876 if IS_WSP_BLANK_CH(*y) {
3877 if (! IS_WSP_BLANK_CH(*x)) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003878 /*
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003879 * The yv character would have been replaced to 0x20.
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003880 */
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003881 if ((*x - 0x20) < 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003882 if (invert)
3883 return(1);
3884 else
3885 return(-1);
3886 } else {
3887 if (invert)
3888 return(-1);
3889 else
3890 return(1);
3891 }
3892 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003893 x++;
3894 y++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003895 /*
3896 * Skip contiguous blank chars of the collapsed string.
3897 */
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003898 while IS_WSP_BLANK_CH(*y)
3899 y++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003900 } else {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003901 if IS_WSP_BLANK_CH(*x) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003902 /*
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003903 * The xv character would have been replaced to 0x20.
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003904 */
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003905 if ((0x20 - *y) < 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003906 if (invert)
3907 return(1);
3908 else
3909 return(-1);
3910 } else {
3911 if (invert)
3912 return(-1);
3913 else
3914 return(1);
3915 }
3916 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003917 tmp = *x++ - *y++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003918 if (tmp < 0)
3919 return(-1);
3920 if (tmp > 0)
3921 return(1);
3922 }
3923 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003924 if (*x != 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003925 if (invert)
3926 return(-1);
3927 else
3928 return(1);
3929 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003930 if (*y != 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003931 /*
3932 * Skip trailing blank chars of the collapsed string.
3933 */
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003934 while IS_WSP_BLANK_CH(*y)
3935 y++;
3936 if (*y != 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003937 if (invert)
3938 return(1);
3939 else
3940 return(-1);
3941 }
3942 }
3943 return(0);
3944}
3945
3946
3947/**
3948 * xmlSchemaCompareReplacedStrings:
3949 * @x: a first string value
3950 * @y: a second string value
3951 *
3952 * Compare 2 string for their normalized values.
3953 *
3954 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
3955 * case of error
3956 */
3957static int
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003958xmlSchemaCompareReplacedStrings(const xmlChar *x,
3959 const xmlChar *y)
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003960{
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003961 int tmp;
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003962
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003963 while ((*x != 0) && (*y != 0)) {
3964 if IS_WSP_BLANK_CH(*y) {
3965 if (! IS_WSP_BLANK_CH(*x)) {
3966 if ((*x - 0x20) < 0)
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003967 return(-1);
3968 else
3969 return(1);
3970 }
3971 } else {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003972 if IS_WSP_BLANK_CH(*x) {
3973 if ((0x20 - *y) < 0)
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003974 return(-1);
3975 else
3976 return(1);
3977 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003978 tmp = *x - *y;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003979 if (tmp < 0)
3980 return(-1);
3981 if (tmp > 0)
3982 return(1);
3983 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003984 x++;
3985 y++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003986 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003987 if (*x != 0)
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003988 return(1);
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003989 if (*y != 0)
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003990 return(-1);
3991 return(0);
3992}
3993
3994/**
Daniel Veillardc4c21552003-03-29 10:53:38 +00003995 * xmlSchemaCompareNormStrings:
3996 * @x: a first string value
3997 * @y: a second string value
3998 *
3999 * Compare 2 string for their normalized values.
4000 *
4001 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
4002 * case of error
4003 */
4004static int
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004005xmlSchemaCompareNormStrings(const xmlChar *x,
4006 const xmlChar *y) {
Daniel Veillardc4c21552003-03-29 10:53:38 +00004007 int tmp;
Daniel Veillardc4c21552003-03-29 10:53:38 +00004008
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004009 while (IS_BLANK_CH(*x)) x++;
4010 while (IS_BLANK_CH(*y)) y++;
4011 while ((*x != 0) && (*y != 0)) {
4012 if (IS_BLANK_CH(*x)) {
4013 if (!IS_BLANK_CH(*y)) {
4014 tmp = *x - *y;
Daniel Veillardc4c21552003-03-29 10:53:38 +00004015 return(tmp);
4016 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004017 while (IS_BLANK_CH(*x)) x++;
4018 while (IS_BLANK_CH(*y)) y++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00004019 } else {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004020 tmp = *x++ - *y++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00004021 if (tmp < 0)
4022 return(-1);
4023 if (tmp > 0)
4024 return(1);
4025 }
4026 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004027 if (*x != 0) {
4028 while (IS_BLANK_CH(*x)) x++;
4029 if (*x != 0)
Daniel Veillardc4c21552003-03-29 10:53:38 +00004030 return(1);
4031 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004032 if (*y != 0) {
4033 while (IS_BLANK_CH(*y)) y++;
4034 if (*y != 0)
Daniel Veillardc4c21552003-03-29 10:53:38 +00004035 return(-1);
4036 }
4037 return(0);
4038}
4039
4040/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00004041 * xmlSchemaCompareFloats:
4042 * @x: a first float or double value
4043 * @y: a second float or double value
4044 *
4045 * Compare 2 values
4046 *
4047 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
4048 * case of error
4049 */
4050static int
4051xmlSchemaCompareFloats(xmlSchemaValPtr x, xmlSchemaValPtr y) {
4052 double d1, d2;
4053
4054 if ((x == NULL) || (y == NULL))
4055 return(-2);
4056
4057 /*
4058 * Cast everything to doubles.
4059 */
4060 if (x->type == XML_SCHEMAS_DOUBLE)
4061 d1 = x->value.d;
4062 else if (x->type == XML_SCHEMAS_FLOAT)
4063 d1 = x->value.f;
4064 else
4065 return(-2);
4066
4067 if (y->type == XML_SCHEMAS_DOUBLE)
4068 d2 = y->value.d;
4069 else if (y->type == XML_SCHEMAS_FLOAT)
4070 d2 = y->value.f;
4071 else
4072 return(-2);
4073
4074 /*
4075 * Check for special cases.
4076 */
4077 if (xmlXPathIsNaN(d1)) {
4078 if (xmlXPathIsNaN(d2))
4079 return(0);
4080 return(1);
4081 }
4082 if (xmlXPathIsNaN(d2))
4083 return(-1);
4084 if (d1 == xmlXPathPINF) {
4085 if (d2 == xmlXPathPINF)
4086 return(0);
4087 return(1);
4088 }
4089 if (d2 == xmlXPathPINF)
4090 return(-1);
4091 if (d1 == xmlXPathNINF) {
4092 if (d2 == xmlXPathNINF)
4093 return(0);
4094 return(-1);
4095 }
4096 if (d2 == xmlXPathNINF)
4097 return(1);
4098
4099 /*
4100 * basic tests, the last one we should have equality, but
4101 * portability is more important than speed and handling
4102 * NaN or Inf in a portable way is always a challenge, so ...
4103 */
4104 if (d1 < d2)
4105 return(-1);
4106 if (d1 > d2)
4107 return(1);
4108 if (d1 == d2)
4109 return(0);
4110 return(2);
4111}
4112
4113/**
Daniel Veillard4255d502002-04-16 15:50:10 +00004114 * xmlSchemaCompareValues:
4115 * @x: a first value
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004116 * @xvalue: the first value as a string (optional)
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004117 * @xwtsp: the whitespace type
Daniel Veillard4255d502002-04-16 15:50:10 +00004118 * @y: a second value
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004119 * @xvalue: the second value as a string (optional)
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004120 * @ywtsp: the whitespace type
Daniel Veillard4255d502002-04-16 15:50:10 +00004121 *
4122 * Compare 2 values
4123 *
Daniel Veillard5a872412002-05-22 06:40:27 +00004124 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
4125 * case of error
Daniel Veillard4255d502002-04-16 15:50:10 +00004126 */
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004127static int
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004128xmlSchemaCompareValuesInternal(xmlSchemaValType xtype,
4129 xmlSchemaValPtr x,
4130 const xmlChar *xvalue,
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004131 xmlSchemaWhitespaceValueType xws,
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004132 xmlSchemaValType ytype,
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004133 xmlSchemaValPtr y,
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004134 const xmlChar *yvalue,
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004135 xmlSchemaWhitespaceValueType yws)
4136{
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004137 switch (xtype) {
Daniel Veillard80b19092003-03-28 13:29:53 +00004138 case XML_SCHEMAS_UNKNOWN:
William M. Brack2f2a6632004-08-20 23:09:47 +00004139 case XML_SCHEMAS_ANYTYPE:
Daniel Veillard80b19092003-03-28 13:29:53 +00004140 return(-2);
4141 case XML_SCHEMAS_INTEGER:
4142 case XML_SCHEMAS_NPINTEGER:
4143 case XML_SCHEMAS_NINTEGER:
4144 case XML_SCHEMAS_NNINTEGER:
4145 case XML_SCHEMAS_PINTEGER:
4146 case XML_SCHEMAS_INT:
4147 case XML_SCHEMAS_UINT:
4148 case XML_SCHEMAS_LONG:
4149 case XML_SCHEMAS_ULONG:
4150 case XML_SCHEMAS_SHORT:
4151 case XML_SCHEMAS_USHORT:
4152 case XML_SCHEMAS_BYTE:
4153 case XML_SCHEMAS_UBYTE:
Daniel Veillard4255d502002-04-16 15:50:10 +00004154 case XML_SCHEMAS_DECIMAL:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004155 if ((x == NULL) || (y == NULL))
4156 return(-2);
4157 if (ytype == xtype)
Daniel Veillard80b19092003-03-28 13:29:53 +00004158 return(xmlSchemaCompareDecimals(x, y));
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004159 if ((ytype == XML_SCHEMAS_DECIMAL) ||
4160 (ytype == XML_SCHEMAS_INTEGER) ||
4161 (ytype == XML_SCHEMAS_NPINTEGER) ||
4162 (ytype == XML_SCHEMAS_NINTEGER) ||
4163 (ytype == XML_SCHEMAS_NNINTEGER) ||
4164 (ytype == XML_SCHEMAS_PINTEGER) ||
4165 (ytype == XML_SCHEMAS_INT) ||
4166 (ytype == XML_SCHEMAS_UINT) ||
4167 (ytype == XML_SCHEMAS_LONG) ||
4168 (ytype == XML_SCHEMAS_ULONG) ||
4169 (ytype == XML_SCHEMAS_SHORT) ||
4170 (ytype == XML_SCHEMAS_USHORT) ||
4171 (ytype == XML_SCHEMAS_BYTE) ||
4172 (ytype == XML_SCHEMAS_UBYTE))
Daniel Veillard4255d502002-04-16 15:50:10 +00004173 return(xmlSchemaCompareDecimals(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00004174 return(-2);
Daniel Veillard070803b2002-05-03 07:29:38 +00004175 case XML_SCHEMAS_DURATION:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004176 if ((x == NULL) || (y == NULL))
4177 return(-2);
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004178 if (ytype == XML_SCHEMAS_DURATION)
Daniel Veillard070803b2002-05-03 07:29:38 +00004179 return(xmlSchemaCompareDurations(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00004180 return(-2);
4181 case XML_SCHEMAS_TIME:
4182 case XML_SCHEMAS_GDAY:
4183 case XML_SCHEMAS_GMONTH:
4184 case XML_SCHEMAS_GMONTHDAY:
4185 case XML_SCHEMAS_GYEAR:
4186 case XML_SCHEMAS_GYEARMONTH:
4187 case XML_SCHEMAS_DATE:
4188 case XML_SCHEMAS_DATETIME:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004189 if ((x == NULL) || (y == NULL))
4190 return(-2);
4191 if ((ytype == XML_SCHEMAS_DATETIME) ||
4192 (ytype == XML_SCHEMAS_TIME) ||
4193 (ytype == XML_SCHEMAS_GDAY) ||
4194 (ytype == XML_SCHEMAS_GMONTH) ||
4195 (ytype == XML_SCHEMAS_GMONTHDAY) ||
4196 (ytype == XML_SCHEMAS_GYEAR) ||
4197 (ytype == XML_SCHEMAS_DATE) ||
4198 (ytype == XML_SCHEMAS_GYEARMONTH))
Daniel Veillard5a872412002-05-22 06:40:27 +00004199 return (xmlSchemaCompareDates(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00004200 return (-2);
Kasimier T. Buchcik2ee855d2005-03-07 11:14:14 +00004201 /*
4202 * Note that we will support comparison of string types against
4203 * anySimpleType as well.
4204 */
4205 case XML_SCHEMAS_ANYSIMPLETYPE:
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004206 case XML_SCHEMAS_STRING:
4207 case XML_SCHEMAS_NORMSTRING:
Daniel Veillard80b19092003-03-28 13:29:53 +00004208 case XML_SCHEMAS_TOKEN:
4209 case XML_SCHEMAS_LANGUAGE:
4210 case XML_SCHEMAS_NMTOKEN:
Daniel Veillard80b19092003-03-28 13:29:53 +00004211 case XML_SCHEMAS_NAME:
Daniel Veillard80b19092003-03-28 13:29:53 +00004212 case XML_SCHEMAS_NCNAME:
4213 case XML_SCHEMAS_ID:
4214 case XML_SCHEMAS_IDREF:
Daniel Veillard80b19092003-03-28 13:29:53 +00004215 case XML_SCHEMAS_ENTITY:
Daniel Veillard80b19092003-03-28 13:29:53 +00004216 case XML_SCHEMAS_NOTATION:
4217 case XML_SCHEMAS_ANYURI:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004218 {
4219 const xmlChar *xv, *yv;
4220
4221 if (x == NULL)
4222 xv = xvalue;
4223 else
4224 xv = x->value.str;
4225 if (y == NULL)
4226 yv = yvalue;
4227 else
4228 yv = y->value.str;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004229 /*
4230 * TODO: Compare those against QName.
4231 */
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004232 if (ytype == XML_SCHEMAS_QNAME) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004233 TODO
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004234 if (y == NULL)
4235 return(-2);
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004236 return (-2);
4237 }
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004238 if ((ytype == XML_SCHEMAS_ANYSIMPLETYPE) ||
4239 (ytype == XML_SCHEMAS_STRING) ||
4240 (ytype == XML_SCHEMAS_NORMSTRING) ||
4241 (ytype == XML_SCHEMAS_TOKEN) ||
4242 (ytype == XML_SCHEMAS_LANGUAGE) ||
4243 (ytype == XML_SCHEMAS_NMTOKEN) ||
4244 (ytype == XML_SCHEMAS_NAME) ||
4245 (ytype == XML_SCHEMAS_NCNAME) ||
4246 (ytype == XML_SCHEMAS_ID) ||
4247 (ytype == XML_SCHEMAS_IDREF) ||
4248 (ytype == XML_SCHEMAS_ENTITY) ||
4249 (ytype == XML_SCHEMAS_NOTATION) ||
4250 (ytype == XML_SCHEMAS_ANYURI)) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004251
4252 if (xws == XML_SCHEMA_WHITESPACE_PRESERVE) {
4253
4254 if (yws == XML_SCHEMA_WHITESPACE_PRESERVE) {
4255 /* TODO: What about x < y or x > y. */
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004256 if (xmlStrEqual(xv, yv))
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004257 return (0);
4258 else
4259 return (2);
4260 } else if (yws == XML_SCHEMA_WHITESPACE_REPLACE)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004261 return (xmlSchemaComparePreserveReplaceStrings(xv, yv, 0));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004262 else if (yws == XML_SCHEMA_WHITESPACE_COLLAPSE)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004263 return (xmlSchemaComparePreserveCollapseStrings(xv, yv, 0));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004264
4265 } else if (xws == XML_SCHEMA_WHITESPACE_REPLACE) {
4266
4267 if (yws == XML_SCHEMA_WHITESPACE_PRESERVE)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004268 return (xmlSchemaComparePreserveReplaceStrings(yv, xv, 1));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004269 if (yws == XML_SCHEMA_WHITESPACE_REPLACE)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004270 return (xmlSchemaCompareReplacedStrings(xv, yv));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004271 if (yws == XML_SCHEMA_WHITESPACE_COLLAPSE)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004272 return (xmlSchemaCompareReplaceCollapseStrings(xv, yv, 0));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004273
4274 } else if (xws == XML_SCHEMA_WHITESPACE_COLLAPSE) {
4275
4276 if (yws == XML_SCHEMA_WHITESPACE_PRESERVE)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004277 return (xmlSchemaComparePreserveCollapseStrings(yv, xv, 1));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004278 if (yws == XML_SCHEMA_WHITESPACE_REPLACE)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004279 return (xmlSchemaCompareReplaceCollapseStrings(yv, xv, 1));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004280 if (yws == XML_SCHEMA_WHITESPACE_COLLAPSE)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004281 return (xmlSchemaCompareNormStrings(xv, yv));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004282 } else
4283 return (-2);
4284
4285 }
Daniel Veillardc4c21552003-03-29 10:53:38 +00004286 return (-2);
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004287 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004288 case XML_SCHEMAS_QNAME:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004289 if ((x == NULL) || (y == NULL))
4290 return(-2);
4291 if (ytype == XML_SCHEMAS_QNAME) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004292 if ((xmlStrEqual(x->value.qname.name, y->value.qname.name)) &&
4293 (xmlStrEqual(x->value.qname.uri, y->value.qname.uri)))
4294 return(0);
4295 return(2);
4296 }
4297 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00004298 case XML_SCHEMAS_FLOAT:
4299 case XML_SCHEMAS_DOUBLE:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004300 if ((x == NULL) || (y == NULL))
4301 return(-2);
4302 if ((ytype == XML_SCHEMAS_FLOAT) ||
4303 (ytype == XML_SCHEMAS_DOUBLE))
Daniel Veillardb6c7f412003-03-29 16:41:55 +00004304 return (xmlSchemaCompareFloats(x, y));
4305 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00004306 case XML_SCHEMAS_BOOLEAN:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004307 if ((x == NULL) || (y == NULL))
4308 return(-2);
4309 if (ytype == XML_SCHEMAS_BOOLEAN) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00004310 if (x->value.b == y->value.b)
4311 return(0);
4312 if (x->value.b == 0)
4313 return(-1);
4314 return(1);
4315 }
4316 return (-2);
Daniel Veillard560c2a42003-07-06 21:13:49 +00004317 case XML_SCHEMAS_HEXBINARY:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004318 if ((x == NULL) || (y == NULL))
4319 return(-2);
4320 if (ytype == XML_SCHEMAS_HEXBINARY) {
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004321 if (x->value.hex.total == y->value.hex.total) {
4322 int ret = xmlStrcmp(x->value.hex.str, y->value.hex.str);
4323 if (ret > 0)
4324 return(1);
4325 else if (ret == 0)
4326 return(0);
4327 }
4328 else if (x->value.hex.total > y->value.hex.total)
4329 return(1);
4330
4331 return(-1);
4332 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00004333 return (-2);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00004334 case XML_SCHEMAS_BASE64BINARY:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004335 if ((x == NULL) || (y == NULL))
4336 return(-2);
4337 if (ytype == XML_SCHEMAS_BASE64BINARY) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00004338 if (x->value.base64.total == y->value.base64.total) {
4339 int ret = xmlStrcmp(x->value.base64.str,
4340 y->value.base64.str);
4341 if (ret > 0)
4342 return(1);
4343 else if (ret == 0)
4344 return(0);
4345 }
4346 else if (x->value.base64.total > y->value.base64.total)
4347 return(1);
4348 else
4349 return(-1);
4350 }
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004351 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00004352 case XML_SCHEMAS_IDREFS:
4353 case XML_SCHEMAS_ENTITIES:
4354 case XML_SCHEMAS_NMTOKENS:
4355 TODO
4356 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00004357 }
Daniel Veillard5a872412002-05-22 06:40:27 +00004358 return -2;
Daniel Veillard4255d502002-04-16 15:50:10 +00004359}
4360
4361/**
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004362 * xmlSchemaCompareValues:
4363 * @x: a first value
4364 * @y: a second value
4365 *
4366 * Compare 2 values
4367 *
4368 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
4369 * case of error
4370 */
4371int
4372xmlSchemaCompareValues(xmlSchemaValPtr x, xmlSchemaValPtr y) {
4373 xmlSchemaWhitespaceValueType xws, yws;
4374
Daniel Veillard5e094142005-02-18 19:36:12 +00004375 if ((x == NULL) || (y == NULL))
4376 return(-2);
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004377 if (x->type == XML_SCHEMAS_STRING)
4378 xws = XML_SCHEMA_WHITESPACE_PRESERVE;
4379 else if (x->type == XML_SCHEMAS_NORMSTRING)
4380 xws = XML_SCHEMA_WHITESPACE_REPLACE;
4381 else
4382 xws = XML_SCHEMA_WHITESPACE_COLLAPSE;
4383
4384 if (y->type == XML_SCHEMAS_STRING)
4385 yws = XML_SCHEMA_WHITESPACE_PRESERVE;
4386 else if (x->type == XML_SCHEMAS_NORMSTRING)
4387 yws = XML_SCHEMA_WHITESPACE_REPLACE;
4388 else
4389 yws = XML_SCHEMA_WHITESPACE_COLLAPSE;
4390
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004391 return(xmlSchemaCompareValuesInternal(x->type, x, NULL, xws, y->type,
4392 y, NULL, yws));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004393}
4394
4395/**
4396 * xmlSchemaCompareValuesWhtsp:
4397 * @x: a first value
4398 * @xws: the whitespace value of x
4399 * @y: a second value
4400 * @yws: the whitespace value of y
4401 *
4402 * Compare 2 values
4403 *
4404 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
4405 * case of error
4406 */
4407int
4408xmlSchemaCompareValuesWhtsp(xmlSchemaValPtr x,
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004409 xmlSchemaWhitespaceValueType xws,
4410 xmlSchemaValPtr y,
4411 xmlSchemaWhitespaceValueType yws)
4412{
Kasimier T. Buchcik9dbb0ce2005-03-16 16:39:23 +00004413 if ((x == NULL) || (y == NULL))
4414 return(-2);
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004415 return(xmlSchemaCompareValuesInternal(x->type, x, NULL, xws, y->type,
4416 y, NULL, yws));
4417}
4418
4419/**
4420 * xmlSchemaCompareValuesWhtspExt:
4421 * @x: a first value
4422 * @xws: the whitespace value of x
4423 * @y: a second value
4424 * @yws: the whitespace value of y
4425 *
4426 * Compare 2 values
4427 *
4428 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
4429 * case of error
4430 */
4431static int
4432xmlSchemaCompareValuesWhtspExt(xmlSchemaValType xtype,
4433 xmlSchemaValPtr x,
4434 const xmlChar *xvalue,
4435 xmlSchemaWhitespaceValueType xws,
4436 xmlSchemaValType ytype,
4437 xmlSchemaValPtr y,
4438 const xmlChar *yvalue,
4439 xmlSchemaWhitespaceValueType yws)
4440{
4441 return(xmlSchemaCompareValuesInternal(xtype, x, xvalue, xws, ytype, y,
4442 yvalue, yws));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004443}
4444
4445/**
Daniel Veillardc4c21552003-03-29 10:53:38 +00004446 * xmlSchemaNormLen:
4447 * @value: a string
4448 *
4449 * Computes the UTF8 length of the normalized value of the string
4450 *
4451 * Returns the length or -1 in case of error.
4452 */
4453static int
4454xmlSchemaNormLen(const xmlChar *value) {
4455 const xmlChar *utf;
4456 int ret = 0;
4457
4458 if (value == NULL)
4459 return(-1);
4460 utf = value;
William M. Brack76e95df2003-10-18 16:20:14 +00004461 while (IS_BLANK_CH(*utf)) utf++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00004462 while (*utf != 0) {
4463 if (utf[0] & 0x80) {
4464 if ((utf[1] & 0xc0) != 0x80)
4465 return(-1);
4466 if ((utf[0] & 0xe0) == 0xe0) {
4467 if ((utf[2] & 0xc0) != 0x80)
4468 return(-1);
4469 if ((utf[0] & 0xf0) == 0xf0) {
4470 if ((utf[0] & 0xf8) != 0xf0 || (utf[3] & 0xc0) != 0x80)
4471 return(-1);
4472 utf += 4;
4473 } else {
4474 utf += 3;
4475 }
4476 } else {
4477 utf += 2;
4478 }
William M. Brack76e95df2003-10-18 16:20:14 +00004479 } else if (IS_BLANK_CH(*utf)) {
4480 while (IS_BLANK_CH(*utf)) utf++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00004481 if (*utf == 0)
4482 break;
4483 } else {
4484 utf++;
4485 }
4486 ret++;
4487 }
4488 return(ret);
4489}
4490
Daniel Veillard6927b102004-10-27 17:29:04 +00004491/**
4492 * xmlSchemaGetFacetValueAsULong:
4493 * @facet: an schemas type facet
4494 *
4495 * Extract the value of a facet
4496 *
4497 * Returns the value as a long
4498 */
Daniel Veillardc0826a72004-08-10 14:17:33 +00004499unsigned long
4500xmlSchemaGetFacetValueAsULong(xmlSchemaFacetPtr facet)
4501{
4502 /*
4503 * TODO: Check if this is a decimal.
4504 */
William M. Brack094dd862004-11-14 14:28:34 +00004505 if (facet == NULL)
4506 return 0;
Daniel Veillardc0826a72004-08-10 14:17:33 +00004507 return ((unsigned long) facet->val->value.decimal.lo);
4508}
4509
Daniel Veillardc4c21552003-03-29 10:53:38 +00004510/**
Daniel Veillard01fa6152004-06-29 17:04:39 +00004511 * xmlSchemaValidateListSimpleTypeFacet:
4512 * @facet: the facet to check
4513 * @value: the lexical repr of the value to validate
4514 * @actualLen: the number of list items
4515 * @expectedLen: the resulting expected number of list items
4516 *
4517 * Checks the value of a list simple type against a facet.
4518 *
4519 * Returns 0 if the value is valid, a positive error code
4520 * number otherwise and -1 in case of an internal error.
4521 */
4522int
4523xmlSchemaValidateListSimpleTypeFacet(xmlSchemaFacetPtr facet,
4524 const xmlChar *value,
4525 unsigned long actualLen,
4526 unsigned long *expectedLen)
4527{
Daniel Veillardce682bc2004-11-05 17:22:25 +00004528 if (facet == NULL)
4529 return(-1);
Daniel Veillard01fa6152004-06-29 17:04:39 +00004530 /*
4531 * TODO: Check if this will work with large numbers.
4532 * (compare value.decimal.mi and value.decimal.hi as well?).
4533 */
4534 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
4535 if (actualLen != facet->val->value.decimal.lo) {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004536 if (expectedLen != NULL)
Daniel Veillardc0826a72004-08-10 14:17:33 +00004537 *expectedLen = facet->val->value.decimal.lo;
Daniel Veillard01fa6152004-06-29 17:04:39 +00004538 return (XML_SCHEMAV_CVC_LENGTH_VALID);
4539 }
4540 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
4541 if (actualLen < facet->val->value.decimal.lo) {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004542 if (expectedLen != NULL)
Daniel Veillardc0826a72004-08-10 14:17:33 +00004543 *expectedLen = facet->val->value.decimal.lo;
Daniel Veillard01fa6152004-06-29 17:04:39 +00004544 return (XML_SCHEMAV_CVC_MINLENGTH_VALID);
4545 }
4546 } else if (facet->type == XML_SCHEMA_FACET_MAXLENGTH) {
4547 if (actualLen > facet->val->value.decimal.lo) {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004548 if (expectedLen != NULL)
Daniel Veillardc0826a72004-08-10 14:17:33 +00004549 *expectedLen = facet->val->value.decimal.lo;
Daniel Veillard01fa6152004-06-29 17:04:39 +00004550 return (XML_SCHEMAV_CVC_MAXLENGTH_VALID);
4551 }
4552 } else
4553 /*
4554 * NOTE: That we can pass NULL as xmlSchemaValPtr to
4555 * xmlSchemaValidateFacet, since the remaining facet types
4556 * are: XML_SCHEMA_FACET_PATTERN, XML_SCHEMA_FACET_ENUMERATION.
4557 */
4558 return(xmlSchemaValidateFacet(NULL, facet, value, NULL));
4559 return (0);
4560}
4561
4562/**
Daniel Veillard6927b102004-10-27 17:29:04 +00004563 * xmlSchemaValidateLengthFacet:
Daniel Veillardc0826a72004-08-10 14:17:33 +00004564 * @type: the built-in type
4565 * @facet: the facet to check
4566 * @value: the lexical repr. of the value to be validated
4567 * @val: the precomputed value
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004568 * @ws: the whitespace type of the value
4569 * @length: the actual length of the value
4570 *
4571 * Checka a value against a "length", "minLength" and "maxLength"
4572 * facet; sets @length to the computed length of @value.
4573 *
4574 * Returns 0 if the value is valid, a positive error code
4575 * otherwise and -1 in case of an internal or API error.
4576 */
4577static int
4578xmlSchemaValidateLengthFacetInternal(xmlSchemaFacetPtr facet,
4579 xmlSchemaTypeType valType,
4580 const xmlChar *value,
4581 xmlSchemaValPtr val,
4582 unsigned long *length,
4583 xmlSchemaWhitespaceValueType ws)
4584{
4585 unsigned int len = 0;
4586
4587 if ((length == NULL) || (facet == NULL))
4588 return (-1);
4589 *length = 0;
4590 if ((facet->type != XML_SCHEMA_FACET_LENGTH) &&
4591 (facet->type != XML_SCHEMA_FACET_MAXLENGTH) &&
4592 (facet->type != XML_SCHEMA_FACET_MINLENGTH))
4593 return (-1);
4594
4595 /*
4596 * TODO: length, maxLength and minLength must be of type
4597 * nonNegativeInteger only. Check if decimal is used somehow.
4598 */
4599 if ((facet->val == NULL) ||
4600 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
4601 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
4602 (facet->val->value.decimal.frac != 0)) {
4603 return(-1);
4604 }
4605 if ((val != NULL) && (val->type == XML_SCHEMAS_HEXBINARY))
4606 len = val->value.hex.total;
4607 else if ((val != NULL) && (val->type == XML_SCHEMAS_BASE64BINARY))
4608 len = val->value.base64.total;
4609 else {
4610 switch (valType) {
4611 case XML_SCHEMAS_STRING:
4612 case XML_SCHEMAS_NORMSTRING:
4613 if (ws == XML_SCHEMA_WHITESPACE_UNKNOWN) {
4614 /*
4615 * This is to ensure API compatibility with the old
4616 * xmlSchemaValidateLengthFacet(). Anyway, this was and
4617 * is not the correct handling.
4618 * TODO: Get rid of this case somehow.
4619 */
4620 if (valType == XML_SCHEMAS_STRING)
4621 len = xmlUTF8Strlen(value);
4622 else
4623 len = xmlSchemaNormLen(value);
4624 } else if (value != NULL) {
4625 if (ws == XML_SCHEMA_WHITESPACE_COLLAPSE)
4626 len = xmlSchemaNormLen(value);
4627 else
4628 /*
4629 * Should be OK for "preserve" as well.
4630 */
4631 len = xmlUTF8Strlen(value);
4632 }
4633 break;
4634 case XML_SCHEMAS_IDREF:
4635 case XML_SCHEMAS_TOKEN:
4636 case XML_SCHEMAS_LANGUAGE:
4637 case XML_SCHEMAS_NMTOKEN:
4638 case XML_SCHEMAS_NAME:
4639 case XML_SCHEMAS_NCNAME:
4640 case XML_SCHEMAS_ID:
4641 /*
4642 * FIXME: What exactly to do with anyURI?
4643 */
4644 case XML_SCHEMAS_ANYURI:
4645 if (value != NULL)
4646 len = xmlSchemaNormLen(value);
4647 break;
4648 default:
4649 TODO
4650 }
4651 }
4652 *length = (unsigned long) len;
4653 /*
4654 * TODO: Return the whole expected value, i.e. "lo", "mi" and "hi".
4655 */
4656 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
4657 if (len != facet->val->value.decimal.lo)
4658 return(XML_SCHEMAV_CVC_LENGTH_VALID);
4659 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
4660 if (len < facet->val->value.decimal.lo)
4661 return(XML_SCHEMAV_CVC_MINLENGTH_VALID);
4662 } else {
4663 if (len > facet->val->value.decimal.lo)
4664 return(XML_SCHEMAV_CVC_MAXLENGTH_VALID);
4665 }
4666
4667 return (0);
4668}
4669
4670/**
4671 * xmlSchemaValidateLengthFacet:
4672 * @type: the built-in type
4673 * @facet: the facet to check
4674 * @value: the lexical repr. of the value to be validated
4675 * @val: the precomputed value
Daniel Veillardc0826a72004-08-10 14:17:33 +00004676 * @length: the actual length of the value
4677 *
4678 * Checka a value against a "length", "minLength" and "maxLength"
4679 * facet; sets @length to the computed length of @value.
4680 *
4681 * Returns 0 if the value is valid, a positive error code
4682 * otherwise and -1 in case of an internal or API error.
4683 */
4684int
4685xmlSchemaValidateLengthFacet(xmlSchemaTypePtr type,
4686 xmlSchemaFacetPtr facet,
4687 const xmlChar *value,
4688 xmlSchemaValPtr val,
4689 unsigned long *length)
4690{
Daniel Veillardcc5e2332005-03-16 21:55:35 +00004691 if (type == NULL)
4692 return(-1);
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004693 return (xmlSchemaValidateLengthFacetInternal(facet,
4694 type->builtInType, value, val, length,
4695 XML_SCHEMA_WHITESPACE_UNKNOWN));
4696}
Daniel Veillardc0826a72004-08-10 14:17:33 +00004697
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004698/**
4699 * xmlSchemaValidateLengthFacetWhtsp:
4700 * @facet: the facet to check
4701 * @valType: the built-in type
4702 * @value: the lexical repr. of the value to be validated
4703 * @val: the precomputed value
4704 * @ws: the whitespace type of the value
4705 * @length: the actual length of the value
4706 *
4707 * Checka a value against a "length", "minLength" and "maxLength"
4708 * facet; sets @length to the computed length of @value.
4709 *
4710 * Returns 0 if the value is valid, a positive error code
4711 * otherwise and -1 in case of an internal or API error.
4712 */
4713int
4714xmlSchemaValidateLengthFacetWhtsp(xmlSchemaFacetPtr facet,
4715 xmlSchemaValType valType,
4716 const xmlChar *value,
4717 xmlSchemaValPtr val,
4718 unsigned long *length,
4719 xmlSchemaWhitespaceValueType ws)
4720{
4721 return (xmlSchemaValidateLengthFacetInternal(facet, valType, value, val,
4722 length, ws));
Daniel Veillardc0826a72004-08-10 14:17:33 +00004723}
4724
4725/**
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004726 * xmlSchemaValidateFacetInternal:
Daniel Veillard4255d502002-04-16 15:50:10 +00004727 * @facet: the facet to check
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004728 * @fws: the whitespace type of the facet's value
4729 * @valType: the built-in type of the value
Daniel Veillard4255d502002-04-16 15:50:10 +00004730 * @value: the lexical repr of the value to validate
4731 * @val: the precomputed value
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004732 * @ws: the whitespace type of the value
Daniel Veillard4255d502002-04-16 15:50:10 +00004733 *
4734 * Check a value against a facet condition
4735 *
4736 * Returns 0 if the element is schemas valid, a positive error code
4737 * number otherwise and -1 in case of internal or API error.
4738 */
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004739static int
4740xmlSchemaValidateFacetInternal(xmlSchemaFacetPtr facet,
4741 xmlSchemaWhitespaceValueType fws,
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004742 xmlSchemaValType valType,
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004743 const xmlChar *value,
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004744 xmlSchemaValPtr val,
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004745 xmlSchemaWhitespaceValueType ws)
Daniel Veillard4255d502002-04-16 15:50:10 +00004746{
4747 int ret;
4748
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004749 if (facet == NULL)
4750 return(-1);
4751
Daniel Veillard4255d502002-04-16 15:50:10 +00004752 switch (facet->type) {
4753 case XML_SCHEMA_FACET_PATTERN:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004754 /*
4755 * NOTE that for patterns, the @value needs to be the normalized
4756 * value, *not* the lexical initial value or the canonical value.
4757 */
4758 if (value == NULL)
4759 return(-1);
Daniel Veillard4255d502002-04-16 15:50:10 +00004760 ret = xmlRegexpExec(facet->regexp, value);
4761 if (ret == 1)
4762 return(0);
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004763 if (ret == 0)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004764 return(XML_SCHEMAV_CVC_PATTERN_VALID);
Daniel Veillard4255d502002-04-16 15:50:10 +00004765 return(ret);
4766 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
4767 ret = xmlSchemaCompareValues(val, facet->val);
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004768 if (ret == -2)
Daniel Veillard4255d502002-04-16 15:50:10 +00004769 return(-1);
Daniel Veillard4255d502002-04-16 15:50:10 +00004770 if (ret == -1)
4771 return(0);
Daniel Veillard01fa6152004-06-29 17:04:39 +00004772 return(XML_SCHEMAV_CVC_MAXEXCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00004773 case XML_SCHEMA_FACET_MAXINCLUSIVE:
4774 ret = xmlSchemaCompareValues(val, facet->val);
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004775 if (ret == -2)
Daniel Veillard070803b2002-05-03 07:29:38 +00004776 return(-1);
Daniel Veillard070803b2002-05-03 07:29:38 +00004777 if ((ret == -1) || (ret == 0))
4778 return(0);
Daniel Veillard01fa6152004-06-29 17:04:39 +00004779 return(XML_SCHEMAV_CVC_MAXINCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00004780 case XML_SCHEMA_FACET_MINEXCLUSIVE:
4781 ret = xmlSchemaCompareValues(val, facet->val);
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004782 if (ret == -2)
Daniel Veillard070803b2002-05-03 07:29:38 +00004783 return(-1);
Daniel Veillard070803b2002-05-03 07:29:38 +00004784 if (ret == 1)
4785 return(0);
Daniel Veillard01fa6152004-06-29 17:04:39 +00004786 return(XML_SCHEMAV_CVC_MINEXCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00004787 case XML_SCHEMA_FACET_MININCLUSIVE:
4788 ret = xmlSchemaCompareValues(val, facet->val);
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004789 if (ret == -2)
Daniel Veillard070803b2002-05-03 07:29:38 +00004790 return(-1);
Daniel Veillard070803b2002-05-03 07:29:38 +00004791 if ((ret == 1) || (ret == 0))
4792 return(0);
Daniel Veillard01fa6152004-06-29 17:04:39 +00004793 return(XML_SCHEMAV_CVC_MININCLUSIVE_VALID);
Daniel Veillard8651f532002-04-17 09:06:27 +00004794 case XML_SCHEMA_FACET_WHITESPACE:
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004795 /* TODO whitespaces */
Daniel Veillard01fa6152004-06-29 17:04:39 +00004796 /*
4797 * NOTE: Whitespace should be handled to normalize
4798 * the value to be validated against a the facets;
4799 * not to normalize the value in-between.
4800 */
Daniel Veillard8651f532002-04-17 09:06:27 +00004801 return(0);
Daniel Veillard88c58912002-04-23 07:12:20 +00004802 case XML_SCHEMA_FACET_ENUMERATION:
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004803 if (ws == XML_SCHEMA_WHITESPACE_UNKNOWN) {
4804 /*
4805 * This is to ensure API compatibility with the old
4806 * xmlSchemaValidateFacet().
4807 * TODO: Get rid of this case.
4808 */
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004809 if ((facet->value != NULL) &&
4810 (xmlStrEqual(facet->value, value)))
4811 return(0);
4812 } else {
4813 ret = xmlSchemaCompareValuesWhtspExt(facet->val->type,
4814 facet->val, facet->value, fws, valType, val,
4815 value, ws);
4816 if (ret == -2)
4817 return(-1);
4818 if (ret == 0)
4819 return(0);
4820 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00004821 return(XML_SCHEMAV_CVC_ENUMERATION_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004822 case XML_SCHEMA_FACET_LENGTH:
4823 case XML_SCHEMA_FACET_MAXLENGTH:
4824 case XML_SCHEMA_FACET_MINLENGTH: {
4825 unsigned int len = 0;
4826
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004827 /*
4828 * TODO: length, maxLength and minLength must be of type
4829 * nonNegativeInteger only. Check if decimal is used somehow.
4830 */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004831 if ((facet->val == NULL) ||
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004832 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
4833 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004834 (facet->val->value.decimal.frac != 0)) {
4835 return(-1);
4836 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00004837 if ((val != NULL) && (val->type == XML_SCHEMAS_HEXBINARY))
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004838 len = val->value.hex.total;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00004839 else if ((val != NULL) && (val->type == XML_SCHEMAS_BASE64BINARY))
4840 len = val->value.base64.total;
4841 else {
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004842 switch (valType) {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004843 case XML_SCHEMAS_STRING:
4844 case XML_SCHEMAS_NORMSTRING:
4845 if (ws == XML_SCHEMA_WHITESPACE_UNKNOWN) {
4846 /*
4847 * This is to ensure API compatibility with the old
4848 * xmlSchemaValidateFacet(). Anyway, this was and
4849 * is not the correct handling.
4850 * TODO: Get rid of this case somehow.
4851 */
4852 if (valType == XML_SCHEMAS_STRING)
4853 len = xmlUTF8Strlen(value);
4854 else
4855 len = xmlSchemaNormLen(value);
4856 } else if (value != NULL) {
4857 if (ws == XML_SCHEMA_WHITESPACE_COLLAPSE)
4858 len = xmlSchemaNormLen(value);
4859 else
4860 /*
4861 * Should be OK for "preserve" as well.
4862 */
4863 len = xmlUTF8Strlen(value);
4864 }
4865 break;
4866 case XML_SCHEMAS_IDREF:
Daniel Veillard560c2a42003-07-06 21:13:49 +00004867 case XML_SCHEMAS_TOKEN:
4868 case XML_SCHEMAS_LANGUAGE:
4869 case XML_SCHEMAS_NMTOKEN:
4870 case XML_SCHEMAS_NAME:
4871 case XML_SCHEMAS_NCNAME:
4872 case XML_SCHEMAS_ID:
Daniel Veillard01fa6152004-06-29 17:04:39 +00004873 /*
4874 * FIXME: What exactly to do with anyURI?
4875 */
4876 case XML_SCHEMAS_ANYURI:
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004877 if (value != NULL)
4878 len = xmlSchemaNormLen(value);
4879 break;
Daniel Veillard560c2a42003-07-06 21:13:49 +00004880 default:
4881 TODO
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004882 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004883 }
4884 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004885 if (len != facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004886 return(XML_SCHEMAV_CVC_LENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004887 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004888 if (len < facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004889 return(XML_SCHEMAV_CVC_MINLENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004890 } else {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004891 if (len > facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004892 return(XML_SCHEMAV_CVC_MAXLENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004893 }
4894 break;
4895 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00004896 case XML_SCHEMA_FACET_TOTALDIGITS:
4897 case XML_SCHEMA_FACET_FRACTIONDIGITS:
4898
4899 if ((facet->val == NULL) ||
4900 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
4901 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
4902 (facet->val->value.decimal.frac != 0)) {
4903 return(-1);
4904 }
4905 if ((val == NULL) ||
4906 ((val->type != XML_SCHEMAS_DECIMAL) &&
4907 (val->type != XML_SCHEMAS_INTEGER) &&
4908 (val->type != XML_SCHEMAS_NPINTEGER) &&
4909 (val->type != XML_SCHEMAS_NINTEGER) &&
4910 (val->type != XML_SCHEMAS_NNINTEGER) &&
4911 (val->type != XML_SCHEMAS_PINTEGER) &&
4912 (val->type != XML_SCHEMAS_INT) &&
4913 (val->type != XML_SCHEMAS_UINT) &&
4914 (val->type != XML_SCHEMAS_LONG) &&
4915 (val->type != XML_SCHEMAS_ULONG) &&
4916 (val->type != XML_SCHEMAS_SHORT) &&
4917 (val->type != XML_SCHEMAS_USHORT) &&
4918 (val->type != XML_SCHEMAS_BYTE) &&
4919 (val->type != XML_SCHEMAS_UBYTE))) {
4920 return(-1);
4921 }
4922 if (facet->type == XML_SCHEMA_FACET_TOTALDIGITS) {
4923 if (val->value.decimal.total > facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004924 return(XML_SCHEMAV_CVC_TOTALDIGITS_VALID);
Daniel Veillard560c2a42003-07-06 21:13:49 +00004925
4926 } else if (facet->type == XML_SCHEMA_FACET_FRACTIONDIGITS) {
4927 if (val->value.decimal.frac > facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004928 return(XML_SCHEMAV_CVC_FRACTIONDIGITS_VALID);
Daniel Veillard560c2a42003-07-06 21:13:49 +00004929 }
4930 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00004931 default:
4932 TODO
4933 }
4934 return(0);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00004935
Daniel Veillard4255d502002-04-16 15:50:10 +00004936}
4937
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004938/**
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004939 * xmlSchemaValidateFacet:
4940 * @base: the base type
4941 * @facet: the facet to check
4942 * @value: the lexical repr of the value to validate
4943 * @val: the precomputed value
4944 *
4945 * Check a value against a facet condition
4946 *
4947 * Returns 0 if the element is schemas valid, a positive error code
4948 * number otherwise and -1 in case of internal or API error.
4949 */
4950int
Kasimier T. Buchcik9dbb0ce2005-03-16 16:39:23 +00004951xmlSchemaValidateFacet(xmlSchemaTypePtr base,
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004952 xmlSchemaFacetPtr facet,
4953 const xmlChar *value,
4954 xmlSchemaValPtr val)
4955{
4956 /*
4957 * This tries to ensure API compatibility regarding the old
4958 * xmlSchemaValidateFacet() and the new xmlSchemaValidateFacetInternal() and
4959 * xmlSchemaValidateFacetWhtsp().
4960 */
Kasimier T. Buchcik9dbb0ce2005-03-16 16:39:23 +00004961 if (val != NULL)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004962 return(xmlSchemaValidateFacetInternal(facet,
Kasimier T. Buchcik9dbb0ce2005-03-16 16:39:23 +00004963 XML_SCHEMA_WHITESPACE_UNKNOWN, val->type, value, val,
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004964 XML_SCHEMA_WHITESPACE_UNKNOWN));
Kasimier T. Buchcik9dbb0ce2005-03-16 16:39:23 +00004965 else if (base != NULL)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004966 return(xmlSchemaValidateFacetInternal(facet,
Kasimier T. Buchcik9dbb0ce2005-03-16 16:39:23 +00004967 XML_SCHEMA_WHITESPACE_UNKNOWN, base->builtInType, value, val,
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004968 XML_SCHEMA_WHITESPACE_UNKNOWN));
Kasimier T. Buchcik9dbb0ce2005-03-16 16:39:23 +00004969 return(-1);
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004970}
4971
4972/**
4973 * xmlSchemaValidateFacetWhtsp:
4974 * @facet: the facet to check
4975 * @fws: the whitespace type of the facet's value
4976 * @valType: the built-in type of the value
4977 * @value: the lexical (or normalized for pattern) repr of the value to validate
4978 * @val: the precomputed value
4979 * @ws: the whitespace type of the value
4980 *
4981 * Check a value against a facet condition. This takes value normalization
4982 * according to the specified whitespace types into account.
4983 * Note that @value needs to be the *normalized* value if the facet
4984 * is of type "pattern".
4985 *
4986 * Returns 0 if the element is schemas valid, a positive error code
4987 * number otherwise and -1 in case of internal or API error.
4988 */
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004989int
4990xmlSchemaValidateFacetWhtsp(xmlSchemaFacetPtr facet,
4991 xmlSchemaWhitespaceValueType fws,
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004992 xmlSchemaValType valType,
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004993 const xmlChar *value,
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004994 xmlSchemaValPtr val,
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004995 xmlSchemaWhitespaceValueType ws)
4996{
4997 return(xmlSchemaValidateFacetInternal(facet, fws, valType,
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004998 value, val, ws));
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004999}
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005000
5001/**
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00005002 * xmlSchemaGetCanonValue:
5003 * @val: the precomputed value
5004 * @retValue: the returned value
5005 *
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005006 * Get a the cononical lexical representation of the value.
Daniel Veillardb5839c32005-02-19 18:27:14 +00005007 * The caller has to free the returned retValue.
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005008 * WARNING: Some value types are not supported yet, resulting
5009 * in a @retValue of "???".
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00005010 *
5011 * Returns 0 if the value could be built and -1 in case of
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005012 * API errors.
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00005013 */
5014int
Daniel Veillardb5839c32005-02-19 18:27:14 +00005015xmlSchemaGetCanonValue(xmlSchemaValPtr val, const xmlChar **retValue)
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00005016{
Daniel Veillardb5839c32005-02-19 18:27:14 +00005017 if ((retValue == NULL) || (val == NULL))
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00005018 return (-1);
5019 *retValue = NULL;
5020 switch (val->type) {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005021 case XML_SCHEMAS_STRING:
5022 if (val->value.str == NULL)
5023 *retValue = BAD_CAST xmlStrdup(BAD_CAST "");
5024 else
5025 *retValue =
5026 BAD_CAST xmlStrdup((const xmlChar *) val->value.str);
5027 break;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00005028 case XML_SCHEMAS_NORMSTRING:
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005029 if (val->value.str == NULL)
5030 *retValue = BAD_CAST xmlStrdup(BAD_CAST "");
5031 else {
5032 *retValue = xmlSchemaWhiteSpaceReplace(
5033 (const xmlChar *) val->value.str);
5034 if ((*retValue) == NULL)
5035 *retValue = BAD_CAST xmlStrdup(
5036 (const xmlChar *) val->value.str);
5037 }
5038 break;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00005039 case XML_SCHEMAS_TOKEN:
5040 case XML_SCHEMAS_LANGUAGE:
5041 case XML_SCHEMAS_NMTOKEN:
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005042 case XML_SCHEMAS_NAME:
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00005043 case XML_SCHEMAS_NCNAME:
5044 case XML_SCHEMAS_ID:
5045 case XML_SCHEMAS_IDREF:
5046 case XML_SCHEMAS_ENTITY:
5047 case XML_SCHEMAS_NOTATION:
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005048 case XML_SCHEMAS_ANYURI:
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00005049 if (val->value.str == NULL)
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005050 return (-1);
5051 *retValue = BAD_CAST xmlSchemaCollapseString(BAD_CAST val->value.str);
5052 break;
5053 case XML_SCHEMAS_QNAME:
5054 /*
5055 * TODO: What exactly to do with QNames?
5056 */
5057 if (val->value.qname.uri == NULL) {
5058 *retValue = BAD_CAST xmlStrdup(BAD_CAST val->value.qname.name);
5059 return (0);
5060 } else {
5061 *retValue = BAD_CAST xmlStrdup(BAD_CAST "{");
5062 *retValue = BAD_CAST xmlStrcat((xmlChar *) (*retValue),
5063 BAD_CAST val->value.qname.uri);
5064 *retValue = BAD_CAST xmlStrcat((xmlChar *) (*retValue),
5065 BAD_CAST "}");
5066 *retValue = BAD_CAST xmlStrcat((xmlChar *) (*retValue),
5067 BAD_CAST val->value.qname.uri);
5068 }
5069 break;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00005070 default:
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005071 *retValue = BAD_CAST xmlStrdup(BAD_CAST "???");
5072 break;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00005073 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005074 return (0);
5075}
5076
5077xmlSchemaValType
5078xmlSchemaGetValType(xmlSchemaValPtr val)
5079{
5080 return (val->type);
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00005081}
5082
Daniel Veillard5d4644e2005-04-01 13:11:58 +00005083#define bottom_xmlschemastypes
5084#include "elfgcchack.h"
Daniel Veillard4255d502002-04-16 15:50:10 +00005085#endif /* LIBXML_SCHEMAS_ENABLED */