blob: 2b629bd2221737c31b043350a0dae8ddd4bac6e6 [file] [log] [blame]
Daniel Veillard4255d502002-04-16 15:50:10 +00001/*
2 * schemastypes.c : implementation of the XML Schema Datatypes
3 * definition and validity checking
4 *
5 * See Copyright for the status of this software.
6 *
7 * Daniel Veillard <veillard@redhat.com>
8 */
9
10#define IN_LIBXML
11#include "libxml.h"
12
13#ifdef LIBXML_SCHEMAS_ENABLED
14
15#include <string.h>
16#include <libxml/xmlmemory.h>
17#include <libxml/parser.h>
18#include <libxml/parserInternals.h>
19#include <libxml/hash.h>
20#include <libxml/valid.h>
Daniel Veillard96a4b252003-02-06 08:22:32 +000021#include <libxml/xpath.h>
22#include <libxml/uri.h>
Daniel Veillard4255d502002-04-16 15:50:10 +000023
24#include <libxml/xmlschemas.h>
25#include <libxml/schemasInternals.h>
26#include <libxml/xmlschemastypes.h>
27
Daniel Veillard070803b2002-05-03 07:29:38 +000028#ifdef HAVE_MATH_H
29#include <math.h>
30#endif
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +000031#ifdef HAVE_FLOAT_H
32#include <float.h>
33#endif
Daniel Veillard070803b2002-05-03 07:29:38 +000034
Daniel Veillard4255d502002-04-16 15:50:10 +000035#define DEBUG
36
Daniel Veillardd0cf7f62004-11-09 16:17:02 +000037#ifndef LIBXML_XPATH_ENABLED
38extern double xmlXPathNAN;
39extern double xmlXPathPINF;
40extern double xmlXPathNINF;
41#endif
42
Daniel Veillard4255d502002-04-16 15:50:10 +000043#define TODO \
44 xmlGenericError(xmlGenericErrorContext, \
45 "Unimplemented block at %s:%d\n", \
46 __FILE__, __LINE__);
47
48#define XML_SCHEMAS_NAMESPACE_NAME \
49 (const xmlChar *)"http://www.w3.org/2001/XMLSchema"
50
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +000051#define IS_WSP_REPLACE_CH(c) ((((c) == 0x9) || ((c) == 0xa)) || \
52 ((c) == 0xd))
53
54#define IS_WSP_SPACE_CH(c) ((c) == 0x20)
55
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +000056#define IS_WSP_BLANK_CH(c) IS_BLANK_CH(c)
57
Daniel Veillard070803b2002-05-03 07:29:38 +000058/* Date value */
59typedef struct _xmlSchemaValDate xmlSchemaValDate;
60typedef xmlSchemaValDate *xmlSchemaValDatePtr;
61struct _xmlSchemaValDate {
62 long year;
63 unsigned int mon :4; /* 1 <= mon <= 12 */
64 unsigned int day :5; /* 1 <= day <= 31 */
65 unsigned int hour :5; /* 0 <= hour <= 23 */
66 unsigned int min :6; /* 0 <= min <= 59 */
67 double sec;
Daniel Veillarda77cf712003-05-09 23:09:55 +000068 unsigned int tz_flag :1; /* is tzo explicitely set? */
Daniel Veillard070803b2002-05-03 07:29:38 +000069 int tzo :11; /* -1440 <= tzo <= 1440 */
70};
71
72/* Duration value */
73typedef struct _xmlSchemaValDuration xmlSchemaValDuration;
74typedef xmlSchemaValDuration *xmlSchemaValDurationPtr;
75struct _xmlSchemaValDuration {
76 long mon; /* mon stores years also */
77 long day;
78 double sec; /* sec stores min and hour also */
79};
80
Daniel Veillard4255d502002-04-16 15:50:10 +000081typedef struct _xmlSchemaValDecimal xmlSchemaValDecimal;
82typedef xmlSchemaValDecimal *xmlSchemaValDecimalPtr;
83struct _xmlSchemaValDecimal {
84 /* would use long long but not portable */
Daniel Veillarde637c4a2003-03-30 21:10:09 +000085 unsigned long lo;
86 unsigned long mi;
87 unsigned long hi;
Daniel Veillard4255d502002-04-16 15:50:10 +000088 unsigned int extra;
Daniel Veillard5a872412002-05-22 06:40:27 +000089 unsigned int sign:1;
William M. Brackc1939562003-08-05 15:52:22 +000090 unsigned int frac:7;
91 unsigned int total:8;
Daniel Veillard4255d502002-04-16 15:50:10 +000092};
93
Daniel Veillarde637c4a2003-03-30 21:10:09 +000094typedef struct _xmlSchemaValQName xmlSchemaValQName;
95typedef xmlSchemaValQName *xmlSchemaValQNamePtr;
96struct _xmlSchemaValQName {
97 xmlChar *name;
98 xmlChar *uri;
99};
100
Daniel Veillard70bcb0e2003-08-08 14:00:28 +0000101typedef struct _xmlSchemaValHex xmlSchemaValHex;
102typedef xmlSchemaValHex *xmlSchemaValHexPtr;
103struct _xmlSchemaValHex {
104 xmlChar *str;
105 unsigned int total;
106};
107
Daniel Veillard1ac24d32003-08-27 14:15:15 +0000108typedef struct _xmlSchemaValBase64 xmlSchemaValBase64;
109typedef xmlSchemaValBase64 *xmlSchemaValBase64Ptr;
110struct _xmlSchemaValBase64 {
111 xmlChar *str;
112 unsigned int total;
113};
114
Daniel Veillard4255d502002-04-16 15:50:10 +0000115struct _xmlSchemaVal {
116 xmlSchemaValType type;
117 union {
Daniel Veillard5a872412002-05-22 06:40:27 +0000118 xmlSchemaValDecimal decimal;
Daniel Veillard070803b2002-05-03 07:29:38 +0000119 xmlSchemaValDate date;
120 xmlSchemaValDuration dur;
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000121 xmlSchemaValQName qname;
Daniel Veillard70bcb0e2003-08-08 14:00:28 +0000122 xmlSchemaValHex hex;
Daniel Veillard1ac24d32003-08-27 14:15:15 +0000123 xmlSchemaValBase64 base64;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000124 float f;
125 double d;
Daniel Veillardc5a70f22003-02-06 23:41:59 +0000126 int b;
Daniel Veillardc4c21552003-03-29 10:53:38 +0000127 xmlChar *str;
Daniel Veillard4255d502002-04-16 15:50:10 +0000128 } value;
129};
130
131static int xmlSchemaTypesInitialized = 0;
132static xmlHashTablePtr xmlSchemaTypesBank = NULL;
133
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000134/*
135 * Basic types
136 */
Daniel Veillard4255d502002-04-16 15:50:10 +0000137static xmlSchemaTypePtr xmlSchemaTypeStringDef = NULL;
138static xmlSchemaTypePtr xmlSchemaTypeAnyTypeDef = NULL;
139static xmlSchemaTypePtr xmlSchemaTypeAnySimpleTypeDef = NULL;
140static xmlSchemaTypePtr xmlSchemaTypeDecimalDef = NULL;
Daniel Veillard070803b2002-05-03 07:29:38 +0000141static xmlSchemaTypePtr xmlSchemaTypeDatetimeDef = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +0000142static xmlSchemaTypePtr xmlSchemaTypeDateDef = NULL;
Daniel Veillard070803b2002-05-03 07:29:38 +0000143static xmlSchemaTypePtr xmlSchemaTypeTimeDef = NULL;
144static xmlSchemaTypePtr xmlSchemaTypeGYearDef = NULL;
145static xmlSchemaTypePtr xmlSchemaTypeGYearMonthDef = NULL;
146static xmlSchemaTypePtr xmlSchemaTypeGDayDef = NULL;
147static xmlSchemaTypePtr xmlSchemaTypeGMonthDayDef = NULL;
148static xmlSchemaTypePtr xmlSchemaTypeGMonthDef = NULL;
149static xmlSchemaTypePtr xmlSchemaTypeDurationDef = NULL;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000150static xmlSchemaTypePtr xmlSchemaTypeFloatDef = NULL;
Daniel Veillardc5a70f22003-02-06 23:41:59 +0000151static xmlSchemaTypePtr xmlSchemaTypeBooleanDef = NULL;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000152static xmlSchemaTypePtr xmlSchemaTypeDoubleDef = NULL;
Daniel Veillard560c2a42003-07-06 21:13:49 +0000153static xmlSchemaTypePtr xmlSchemaTypeHexBinaryDef = NULL;
Daniel Veillard1ac24d32003-08-27 14:15:15 +0000154static xmlSchemaTypePtr xmlSchemaTypeBase64BinaryDef = NULL;
Daniel Veillarde5b110b2003-02-04 14:43:39 +0000155static xmlSchemaTypePtr xmlSchemaTypeAnyURIDef = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +0000156
157/*
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000158 * Derived types
159 */
160static xmlSchemaTypePtr xmlSchemaTypePositiveIntegerDef = NULL;
161static xmlSchemaTypePtr xmlSchemaTypeNonPositiveIntegerDef = NULL;
162static xmlSchemaTypePtr xmlSchemaTypeNegativeIntegerDef = NULL;
163static xmlSchemaTypePtr xmlSchemaTypeNonNegativeIntegerDef = NULL;
164static xmlSchemaTypePtr xmlSchemaTypeIntegerDef = NULL;
165static xmlSchemaTypePtr xmlSchemaTypeLongDef = NULL;
166static xmlSchemaTypePtr xmlSchemaTypeIntDef = NULL;
167static xmlSchemaTypePtr xmlSchemaTypeShortDef = NULL;
168static xmlSchemaTypePtr xmlSchemaTypeByteDef = NULL;
169static xmlSchemaTypePtr xmlSchemaTypeUnsignedLongDef = NULL;
170static xmlSchemaTypePtr xmlSchemaTypeUnsignedIntDef = NULL;
171static xmlSchemaTypePtr xmlSchemaTypeUnsignedShortDef = NULL;
172static xmlSchemaTypePtr xmlSchemaTypeUnsignedByteDef = NULL;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000173static xmlSchemaTypePtr xmlSchemaTypeNormStringDef = NULL;
174static xmlSchemaTypePtr xmlSchemaTypeTokenDef = NULL;
175static xmlSchemaTypePtr xmlSchemaTypeLanguageDef = NULL;
176static xmlSchemaTypePtr xmlSchemaTypeNameDef = NULL;
177static xmlSchemaTypePtr xmlSchemaTypeQNameDef = NULL;
Daniel Veillarde5b110b2003-02-04 14:43:39 +0000178static xmlSchemaTypePtr xmlSchemaTypeNCNameDef = NULL;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000179static xmlSchemaTypePtr xmlSchemaTypeIdDef = NULL;
180static xmlSchemaTypePtr xmlSchemaTypeIdrefDef = NULL;
181static xmlSchemaTypePtr xmlSchemaTypeIdrefsDef = NULL;
Daniel Veillarda1a9d042003-03-18 16:53:17 +0000182static xmlSchemaTypePtr xmlSchemaTypeEntityDef = NULL;
183static xmlSchemaTypePtr xmlSchemaTypeEntitiesDef = NULL;
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000184static xmlSchemaTypePtr xmlSchemaTypeNotationDef = NULL;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000185static xmlSchemaTypePtr xmlSchemaTypeNmtokenDef = NULL;
186static xmlSchemaTypePtr xmlSchemaTypeNmtokensDef = NULL;
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000187
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000188/************************************************************************
189 * *
190 * Datatype error handlers *
191 * *
192 ************************************************************************/
193/**
194 * xmlSchemaTypeErrMemory:
195 * @extra: extra informations
196 *
197 * Handle an out of memory condition
198 */
199static void
200xmlSchemaTypeErrMemory(xmlNodePtr node, const char *extra)
201{
202 __xmlSimpleError(XML_FROM_DATATYPE, XML_ERR_NO_MEMORY, node, NULL, extra);
203}
204
205/************************************************************************
206 * *
207 * Base types support *
208 * *
209 ************************************************************************/
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000210/*
Daniel Veillard4255d502002-04-16 15:50:10 +0000211 * xmlSchemaInitBasicType:
212 * @name: the type name
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000213 * @type: the value type associated
Daniel Veillard4255d502002-04-16 15:50:10 +0000214 *
Daniel Veillard01fa6152004-06-29 17:04:39 +0000215 * Initialize one primitive built-in type
Daniel Veillard4255d502002-04-16 15:50:10 +0000216 */
217static xmlSchemaTypePtr
Daniel Veillard01fa6152004-06-29 17:04:39 +0000218xmlSchemaInitBasicType(const char *name, xmlSchemaValType type,
219 xmlSchemaTypePtr baseType) {
Daniel Veillard4255d502002-04-16 15:50:10 +0000220 xmlSchemaTypePtr ret;
221
222 ret = (xmlSchemaTypePtr) xmlMalloc(sizeof(xmlSchemaType));
223 if (ret == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000224 xmlSchemaTypeErrMemory(NULL, "could not initialize basic types");
Daniel Veillard4255d502002-04-16 15:50:10 +0000225 return(NULL);
226 }
227 memset(ret, 0, sizeof(xmlSchemaType));
Daniel Veillardbe9c6322003-11-22 20:37:51 +0000228 ret->name = (const xmlChar *)name;
Daniel Veillard4255d502002-04-16 15:50:10 +0000229 ret->type = XML_SCHEMA_TYPE_BASIC;
Daniel Veillard01fa6152004-06-29 17:04:39 +0000230 ret->baseType = baseType;
231 /*
232 * Hack to reflect the variety.
233 */
234 if ((type == XML_SCHEMAS_IDREFS) ||
235 (type == XML_SCHEMAS_NMTOKENS) ||
236 (type == XML_SCHEMAS_ENTITIES))
237 ret->flags |= XML_SCHEMAS_TYPE_VARIETY_LIST;
William M. Brack2f2a6632004-08-20 23:09:47 +0000238 else if ((type != XML_SCHEMAS_ANYTYPE) &&
239 (type != XML_SCHEMAS_ANYSIMPLETYPE))
Daniel Veillard01fa6152004-06-29 17:04:39 +0000240 ret->flags |= XML_SCHEMAS_TYPE_VARIETY_ATOMIC;
Daniel Veillard4255d502002-04-16 15:50:10 +0000241 ret->contentType = XML_SCHEMA_CONTENT_BASIC;
Daniel Veillard01fa6152004-06-29 17:04:39 +0000242 switch (type) {
243 case XML_SCHEMAS_STRING:
244 case XML_SCHEMAS_DECIMAL:
245 case XML_SCHEMAS_DATE:
246 case XML_SCHEMAS_DATETIME:
247 case XML_SCHEMAS_TIME:
248 case XML_SCHEMAS_GYEAR:
249 case XML_SCHEMAS_GYEARMONTH:
250 case XML_SCHEMAS_GMONTH:
251 case XML_SCHEMAS_GMONTHDAY:
252 case XML_SCHEMAS_GDAY:
253 case XML_SCHEMAS_DURATION:
254 case XML_SCHEMAS_FLOAT:
255 case XML_SCHEMAS_DOUBLE:
256 case XML_SCHEMAS_BOOLEAN:
257 case XML_SCHEMAS_ANYURI:
258 case XML_SCHEMAS_HEXBINARY:
259 case XML_SCHEMAS_BASE64BINARY:
260 case XML_SCHEMAS_QNAME:
261 case XML_SCHEMAS_NOTATION:
262 ret->flags |= XML_SCHEMAS_TYPE_BUILTIN_PRIMITIVE;
William M. Brack96d2eff2004-06-30 11:48:47 +0000263 default:
264 break;
Daniel Veillard01fa6152004-06-29 17:04:39 +0000265 }
266
Daniel Veillard4255d502002-04-16 15:50:10 +0000267 xmlHashAddEntry2(xmlSchemaTypesBank, ret->name,
268 XML_SCHEMAS_NAMESPACE_NAME, ret);
Daniel Veillard01fa6152004-06-29 17:04:39 +0000269 ret->builtInType = type;
Daniel Veillard4255d502002-04-16 15:50:10 +0000270 return(ret);
271}
272
273/*
274 * xmlSchemaInitTypes:
275 *
276 * Initialize the default XML Schemas type library
277 */
278void
Daniel Veillard6560a422003-03-27 21:25:38 +0000279xmlSchemaInitTypes(void)
280{
Daniel Veillard4255d502002-04-16 15:50:10 +0000281 if (xmlSchemaTypesInitialized != 0)
Daniel Veillard6560a422003-03-27 21:25:38 +0000282 return;
Daniel Veillard4255d502002-04-16 15:50:10 +0000283 xmlSchemaTypesBank = xmlHashCreate(40);
Daniel Veillard6560a422003-03-27 21:25:38 +0000284
Daniel Veillard01fa6152004-06-29 17:04:39 +0000285
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000286 /*
Daniel Veillard01fa6152004-06-29 17:04:39 +0000287 * 3.4.7 Built-in Complex Type Definition
288 */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000289 xmlSchemaTypeAnyTypeDef = xmlSchemaInitBasicType("anyType",
William M. Brack2f2a6632004-08-20 23:09:47 +0000290 XML_SCHEMAS_ANYTYPE,
Daniel Veillard01fa6152004-06-29 17:04:39 +0000291 NULL);
292 xmlSchemaTypeAnyTypeDef->baseType = xmlSchemaTypeAnyTypeDef;
293 xmlSchemaTypeAnyTypeDef->contentType = XML_SCHEMA_CONTENT_MIXED;
294 {
295 xmlSchemaWildcardPtr wild;
296
297 wild = (xmlSchemaWildcardPtr) xmlMalloc(sizeof(xmlSchemaWildcard));
298 if (wild == NULL) {
William M. Brack2f2a6632004-08-20 23:09:47 +0000299 xmlSchemaTypeErrMemory(NULL, "could not create an attribute wildcard on anyType");
Daniel Veillard01fa6152004-06-29 17:04:39 +0000300 return;
301 }
302 memset(wild, 0, sizeof(xmlSchemaWildcard));
303 wild->any = 1;
304 wild->processContents = XML_SCHEMAS_ANY_LAX;
305 wild->minOccurs = 1;
306 wild->maxOccurs = 1;
307 xmlSchemaTypeAnyTypeDef->attributeWildcard = wild;
308 }
309 xmlSchemaTypeAnySimpleTypeDef = xmlSchemaInitBasicType("anySimpleType",
William M. Brack2f2a6632004-08-20 23:09:47 +0000310 XML_SCHEMAS_ANYSIMPLETYPE,
Daniel Veillard01fa6152004-06-29 17:04:39 +0000311 xmlSchemaTypeAnyTypeDef);
312 /*
313 * primitive datatypes
314 */
315 xmlSchemaTypeStringDef = xmlSchemaInitBasicType("string",
316 XML_SCHEMAS_STRING,
317 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000318 xmlSchemaTypeDecimalDef = xmlSchemaInitBasicType("decimal",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000319 XML_SCHEMAS_DECIMAL,
320 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000321 xmlSchemaTypeDateDef = xmlSchemaInitBasicType("date",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000322 XML_SCHEMAS_DATE,
323 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000324 xmlSchemaTypeDatetimeDef = xmlSchemaInitBasicType("dateTime",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000325 XML_SCHEMAS_DATETIME,
326 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000327 xmlSchemaTypeTimeDef = xmlSchemaInitBasicType("time",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000328 XML_SCHEMAS_TIME,
329 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000330 xmlSchemaTypeGYearDef = xmlSchemaInitBasicType("gYear",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000331 XML_SCHEMAS_GYEAR,
332 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000333 xmlSchemaTypeGYearMonthDef = xmlSchemaInitBasicType("gYearMonth",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000334 XML_SCHEMAS_GYEARMONTH,
335 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000336 xmlSchemaTypeGMonthDef = xmlSchemaInitBasicType("gMonth",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000337 XML_SCHEMAS_GMONTH,
338 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000339 xmlSchemaTypeGMonthDayDef = xmlSchemaInitBasicType("gMonthDay",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000340 XML_SCHEMAS_GMONTHDAY,
341 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000342 xmlSchemaTypeGDayDef = xmlSchemaInitBasicType("gDay",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000343 XML_SCHEMAS_GDAY,
344 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000345 xmlSchemaTypeDurationDef = xmlSchemaInitBasicType("duration",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000346 XML_SCHEMAS_DURATION,
347 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000348 xmlSchemaTypeFloatDef = xmlSchemaInitBasicType("float",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000349 XML_SCHEMAS_FLOAT,
350 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000351 xmlSchemaTypeDoubleDef = xmlSchemaInitBasicType("double",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000352 XML_SCHEMAS_DOUBLE,
353 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000354 xmlSchemaTypeBooleanDef = xmlSchemaInitBasicType("boolean",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000355 XML_SCHEMAS_BOOLEAN,
356 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000357 xmlSchemaTypeAnyURIDef = xmlSchemaInitBasicType("anyURI",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000358 XML_SCHEMAS_ANYURI,
359 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard560c2a42003-07-06 21:13:49 +0000360 xmlSchemaTypeHexBinaryDef = xmlSchemaInitBasicType("hexBinary",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000361 XML_SCHEMAS_HEXBINARY,
362 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard1ac24d32003-08-27 14:15:15 +0000363 xmlSchemaTypeBase64BinaryDef
Daniel Veillard01fa6152004-06-29 17:04:39 +0000364 = xmlSchemaInitBasicType("base64Binary", XML_SCHEMAS_BASE64BINARY,
365 xmlSchemaTypeAnySimpleTypeDef);
366 xmlSchemaTypeNotationDef = xmlSchemaInitBasicType("NOTATION",
367 XML_SCHEMAS_NOTATION,
368 xmlSchemaTypeAnySimpleTypeDef);
369 xmlSchemaTypeQNameDef = xmlSchemaInitBasicType("QName",
370 XML_SCHEMAS_QNAME,
371 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard4255d502002-04-16 15:50:10 +0000372
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000373 /*
374 * derived datatypes
375 */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000376 xmlSchemaTypeIntegerDef = xmlSchemaInitBasicType("integer",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000377 XML_SCHEMAS_INTEGER,
378 xmlSchemaTypeDecimalDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000379 xmlSchemaTypeNonPositiveIntegerDef =
380 xmlSchemaInitBasicType("nonPositiveInteger",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000381 XML_SCHEMAS_NPINTEGER,
382 xmlSchemaTypeIntegerDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000383 xmlSchemaTypeNegativeIntegerDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000384 xmlSchemaInitBasicType("negativeInteger", XML_SCHEMAS_NINTEGER,
385 xmlSchemaTypeNonPositiveIntegerDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000386 xmlSchemaTypeLongDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000387 xmlSchemaInitBasicType("long", XML_SCHEMAS_LONG,
388 xmlSchemaTypeIntegerDef);
389 xmlSchemaTypeIntDef = xmlSchemaInitBasicType("int", XML_SCHEMAS_INT,
390 xmlSchemaTypeLongDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000391 xmlSchemaTypeShortDef = xmlSchemaInitBasicType("short",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000392 XML_SCHEMAS_SHORT,
393 xmlSchemaTypeIntDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000394 xmlSchemaTypeByteDef = xmlSchemaInitBasicType("byte",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000395 XML_SCHEMAS_BYTE,
396 xmlSchemaTypeShortDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000397 xmlSchemaTypeNonNegativeIntegerDef =
398 xmlSchemaInitBasicType("nonNegativeInteger",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000399 XML_SCHEMAS_NNINTEGER,
400 xmlSchemaTypeIntegerDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000401 xmlSchemaTypeUnsignedLongDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000402 xmlSchemaInitBasicType("unsignedLong", XML_SCHEMAS_ULONG,
403 xmlSchemaTypeNonNegativeIntegerDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000404 xmlSchemaTypeUnsignedIntDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000405 xmlSchemaInitBasicType("unsignedInt", XML_SCHEMAS_UINT,
406 xmlSchemaTypeUnsignedLongDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000407 xmlSchemaTypeUnsignedShortDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000408 xmlSchemaInitBasicType("unsignedShort", XML_SCHEMAS_USHORT,
409 xmlSchemaTypeUnsignedIntDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000410 xmlSchemaTypeUnsignedByteDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000411 xmlSchemaInitBasicType("unsignedByte", XML_SCHEMAS_UBYTE,
412 xmlSchemaTypeUnsignedShortDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000413 xmlSchemaTypePositiveIntegerDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000414 xmlSchemaInitBasicType("positiveInteger", XML_SCHEMAS_PINTEGER,
415 xmlSchemaTypeNonNegativeIntegerDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000416 xmlSchemaTypeNormStringDef = xmlSchemaInitBasicType("normalizedString",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000417 XML_SCHEMAS_NORMSTRING,
418 xmlSchemaTypeStringDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000419 xmlSchemaTypeTokenDef = xmlSchemaInitBasicType("token",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000420 XML_SCHEMAS_TOKEN,
421 xmlSchemaTypeNormStringDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000422 xmlSchemaTypeLanguageDef = xmlSchemaInitBasicType("language",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000423 XML_SCHEMAS_LANGUAGE,
424 xmlSchemaTypeTokenDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000425 xmlSchemaTypeNameDef = xmlSchemaInitBasicType("Name",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000426 XML_SCHEMAS_NAME,
427 xmlSchemaTypeTokenDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000428 xmlSchemaTypeNmtokenDef = xmlSchemaInitBasicType("NMTOKEN",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000429 XML_SCHEMAS_NMTOKEN,
430 xmlSchemaTypeTokenDef);
431 xmlSchemaTypeNCNameDef = xmlSchemaInitBasicType("NCName",
432 XML_SCHEMAS_NCNAME,
433 xmlSchemaTypeNameDef);
434 xmlSchemaTypeIdDef = xmlSchemaInitBasicType("ID", XML_SCHEMAS_ID,
435 xmlSchemaTypeNCNameDef);
436 xmlSchemaTypeIdrefDef = xmlSchemaInitBasicType("IDREF",
437 XML_SCHEMAS_IDREF,
438 xmlSchemaTypeNCNameDef);
439 xmlSchemaTypeIdrefsDef = xmlSchemaInitBasicType("IDREFS",
440 XML_SCHEMAS_IDREFS,
441 xmlSchemaTypeIdrefDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000442 xmlSchemaTypeNmtokensDef = xmlSchemaInitBasicType("NMTOKENS",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000443 XML_SCHEMAS_NMTOKENS,
444 xmlSchemaTypeNmtokenDef);
445 xmlSchemaTypeEntityDef = xmlSchemaInitBasicType("ENTITY",
446 XML_SCHEMAS_ENTITY,
447 xmlSchemaTypeNCNameDef);
448 xmlSchemaTypeEntitiesDef = xmlSchemaInitBasicType("ENTITIES",
449 XML_SCHEMAS_ENTITIES,
450 xmlSchemaTypeNCNameDef);
Daniel Veillard4255d502002-04-16 15:50:10 +0000451 xmlSchemaTypesInitialized = 1;
452}
453
454/**
455 * xmlSchemaCleanupTypes:
456 *
457 * Cleanup the default XML Schemas type library
458 */
459void
460xmlSchemaCleanupTypes(void) {
461 if (xmlSchemaTypesInitialized == 0)
462 return;
Daniel Veillard01fa6152004-06-29 17:04:39 +0000463 xmlSchemaFreeWildcard(xmlSchemaTypeAnyTypeDef->attributeWildcard);
Daniel Veillard4255d502002-04-16 15:50:10 +0000464 xmlHashFree(xmlSchemaTypesBank, (xmlHashDeallocator) xmlSchemaFreeType);
465 xmlSchemaTypesInitialized = 0;
466}
467
468/**
Daniel Veillard6927b102004-10-27 17:29:04 +0000469 * xmlSchemaIsBuiltInTypeFacet:
Daniel Veillard01fa6152004-06-29 17:04:39 +0000470 * @type: the built-in type
471 * @facetType: the facet type
472 *
473 * Evaluates if a specific facet can be
474 * used in conjunction with a type.
475 *
476 * Returns 1 if the facet can be used with the given built-in type,
477 * 0 otherwise and -1 in case the type is not a built-in type.
478 */
479int
480xmlSchemaIsBuiltInTypeFacet(xmlSchemaTypePtr type, int facetType)
481{
Daniel Veillardce682bc2004-11-05 17:22:25 +0000482 if (type == NULL)
483 return (-1);
Daniel Veillard01fa6152004-06-29 17:04:39 +0000484 if (type->type != XML_SCHEMA_TYPE_BASIC)
485 return (-1);
486 switch (type->builtInType) {
487 case XML_SCHEMAS_BOOLEAN:
488 if ((facetType == XML_SCHEMA_FACET_PATTERN) ||
489 (facetType == XML_SCHEMA_FACET_WHITESPACE))
490 return (1);
491 else
492 return (0);
493 case XML_SCHEMAS_STRING:
494 case XML_SCHEMAS_NOTATION:
495 case XML_SCHEMAS_QNAME:
496 case XML_SCHEMAS_ANYURI:
497 case XML_SCHEMAS_BASE64BINARY:
498 case XML_SCHEMAS_HEXBINARY:
499 if ((facetType == XML_SCHEMA_FACET_LENGTH) ||
500 (facetType == XML_SCHEMA_FACET_MINLENGTH) ||
501 (facetType == XML_SCHEMA_FACET_MAXLENGTH) ||
502 (facetType == XML_SCHEMA_FACET_PATTERN) ||
503 (facetType == XML_SCHEMA_FACET_ENUMERATION) ||
504 (facetType == XML_SCHEMA_FACET_WHITESPACE))
505 return (1);
506 else
507 return (0);
508 case XML_SCHEMAS_DECIMAL:
509 if ((facetType == XML_SCHEMA_FACET_TOTALDIGITS) ||
510 (facetType == XML_SCHEMA_FACET_FRACTIONDIGITS) ||
511 (facetType == XML_SCHEMA_FACET_PATTERN) ||
512 (facetType == XML_SCHEMA_FACET_WHITESPACE) ||
513 (facetType == XML_SCHEMA_FACET_ENUMERATION) ||
514 (facetType == XML_SCHEMA_FACET_MAXINCLUSIVE) ||
515 (facetType == XML_SCHEMA_FACET_MAXEXCLUSIVE) ||
516 (facetType == XML_SCHEMA_FACET_MININCLUSIVE) ||
517 (facetType == XML_SCHEMA_FACET_MINEXCLUSIVE))
518 return (1);
519 else
520 return (0);
521 case XML_SCHEMAS_TIME:
522 case XML_SCHEMAS_GDAY:
523 case XML_SCHEMAS_GMONTH:
524 case XML_SCHEMAS_GMONTHDAY:
525 case XML_SCHEMAS_GYEAR:
526 case XML_SCHEMAS_GYEARMONTH:
527 case XML_SCHEMAS_DATE:
528 case XML_SCHEMAS_DATETIME:
529 case XML_SCHEMAS_DURATION:
530 case XML_SCHEMAS_FLOAT:
531 case XML_SCHEMAS_DOUBLE:
532 if ((facetType == XML_SCHEMA_FACET_PATTERN) ||
533 (facetType == XML_SCHEMA_FACET_ENUMERATION) ||
534 (facetType == XML_SCHEMA_FACET_WHITESPACE) ||
535 (facetType == XML_SCHEMA_FACET_MAXINCLUSIVE) ||
536 (facetType == XML_SCHEMA_FACET_MAXEXCLUSIVE) ||
537 (facetType == XML_SCHEMA_FACET_MININCLUSIVE) ||
538 (facetType == XML_SCHEMA_FACET_MINEXCLUSIVE))
539 return (1);
540 else
541 return (0);
542 default:
Daniel Veillardc7e3cc42004-09-28 12:33:52 +0000543 break;
Daniel Veillard01fa6152004-06-29 17:04:39 +0000544 }
545 return (0);
546}
547
548/**
549 * xmlSchemaGetBuiltInType:
550 * @type: the type of the built in type
551 *
552 * Gives you the type struct for a built-in
553 * type by its type id.
554 *
555 * Returns the type if found, NULL otherwise.
556 */
557xmlSchemaTypePtr
558xmlSchemaGetBuiltInType(xmlSchemaValType type)
559{
560 if (xmlSchemaTypesInitialized == 0)
561 xmlSchemaInitTypes();
562 switch (type) {
563
564 case XML_SCHEMAS_ANYSIMPLETYPE:
565 return (xmlSchemaTypeAnySimpleTypeDef);
566 case XML_SCHEMAS_STRING:
567 return (xmlSchemaTypeStringDef);
568 case XML_SCHEMAS_NORMSTRING:
569 return (xmlSchemaTypeNormStringDef);
570 case XML_SCHEMAS_DECIMAL:
571 return (xmlSchemaTypeDecimalDef);
572 case XML_SCHEMAS_TIME:
573 return (xmlSchemaTypeTimeDef);
574 case XML_SCHEMAS_GDAY:
575 return (xmlSchemaTypeGDayDef);
576 case XML_SCHEMAS_GMONTH:
577 return (xmlSchemaTypeGMonthDef);
578 case XML_SCHEMAS_GMONTHDAY:
579 return (xmlSchemaTypeGMonthDayDef);
580 case XML_SCHEMAS_GYEAR:
581 return (xmlSchemaTypeGYearDef);
582 case XML_SCHEMAS_GYEARMONTH:
583 return (xmlSchemaTypeGYearMonthDef);
584 case XML_SCHEMAS_DATE:
585 return (xmlSchemaTypeDateDef);
586 case XML_SCHEMAS_DATETIME:
587 return (xmlSchemaTypeDatetimeDef);
588 case XML_SCHEMAS_DURATION:
589 return (xmlSchemaTypeDurationDef);
590 case XML_SCHEMAS_FLOAT:
591 return (xmlSchemaTypeFloatDef);
592 case XML_SCHEMAS_DOUBLE:
593 return (xmlSchemaTypeDoubleDef);
594 case XML_SCHEMAS_BOOLEAN:
595 return (xmlSchemaTypeBooleanDef);
596 case XML_SCHEMAS_TOKEN:
597 return (xmlSchemaTypeTokenDef);
598 case XML_SCHEMAS_LANGUAGE:
599 return (xmlSchemaTypeLanguageDef);
600 case XML_SCHEMAS_NMTOKEN:
601 return (xmlSchemaTypeNmtokenDef);
602 case XML_SCHEMAS_NMTOKENS:
603 return (xmlSchemaTypeNmtokensDef);
604 case XML_SCHEMAS_NAME:
605 return (xmlSchemaTypeNameDef);
606 case XML_SCHEMAS_QNAME:
607 return (xmlSchemaTypeQNameDef);
608 case XML_SCHEMAS_NCNAME:
609 return (xmlSchemaTypeNCNameDef);
610 case XML_SCHEMAS_ID:
611 return (xmlSchemaTypeIdDef);
612 case XML_SCHEMAS_IDREF:
613 return (xmlSchemaTypeIdrefDef);
614 case XML_SCHEMAS_IDREFS:
615 return (xmlSchemaTypeIdrefsDef);
616 case XML_SCHEMAS_ENTITY:
617 return (xmlSchemaTypeEntityDef);
618 case XML_SCHEMAS_ENTITIES:
619 return (xmlSchemaTypeEntitiesDef);
620 case XML_SCHEMAS_NOTATION:
621 return (xmlSchemaTypeNotationDef);
622 case XML_SCHEMAS_ANYURI:
623 return (xmlSchemaTypeAnyURIDef);
624 case XML_SCHEMAS_INTEGER:
625 return (xmlSchemaTypeIntegerDef);
626 case XML_SCHEMAS_NPINTEGER:
627 return (xmlSchemaTypeNonPositiveIntegerDef);
628 case XML_SCHEMAS_NINTEGER:
629 return (xmlSchemaTypeNegativeIntegerDef);
630 case XML_SCHEMAS_NNINTEGER:
631 return (xmlSchemaTypeNonNegativeIntegerDef);
632 case XML_SCHEMAS_PINTEGER:
633 return (xmlSchemaTypePositiveIntegerDef);
634 case XML_SCHEMAS_INT:
635 return (xmlSchemaTypeIntDef);
636 case XML_SCHEMAS_UINT:
637 return (xmlSchemaTypeUnsignedIntDef);
638 case XML_SCHEMAS_LONG:
639 return (xmlSchemaTypeLongDef);
640 case XML_SCHEMAS_ULONG:
641 return (xmlSchemaTypeUnsignedLongDef);
642 case XML_SCHEMAS_SHORT:
643 return (xmlSchemaTypeShortDef);
644 case XML_SCHEMAS_USHORT:
645 return (xmlSchemaTypeUnsignedShortDef);
646 case XML_SCHEMAS_BYTE:
647 return (xmlSchemaTypeByteDef);
648 case XML_SCHEMAS_UBYTE:
649 return (xmlSchemaTypeUnsignedByteDef);
650 case XML_SCHEMAS_HEXBINARY:
651 return (xmlSchemaTypeHexBinaryDef);
652 case XML_SCHEMAS_BASE64BINARY:
653 return (xmlSchemaTypeBase64BinaryDef);
654 case XML_SCHEMAS_ANYTYPE:
655 return (xmlSchemaTypeAnyTypeDef);
656 default:
657 return (NULL);
658 }
659}
660
661/**
Daniel Veillard4255d502002-04-16 15:50:10 +0000662 * xmlSchemaNewValue:
663 * @type: the value type
664 *
665 * Allocate a new simple type value
666 *
667 * Returns a pointer to the new value or NULL in case of error
668 */
669static xmlSchemaValPtr
670xmlSchemaNewValue(xmlSchemaValType type) {
671 xmlSchemaValPtr value;
672
673 value = (xmlSchemaValPtr) xmlMalloc(sizeof(xmlSchemaVal));
674 if (value == NULL) {
675 return(NULL);
676 }
677 memset(value, 0, sizeof(xmlSchemaVal));
678 value->type = type;
679 return(value);
680}
681
682/**
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +0000683 * xmlSchemaNewStringValue:
684 * @type: the value type
Daniel Veillardb5839c32005-02-19 18:27:14 +0000685 * @value: the value
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +0000686 *
687 * Allocate a new simple type value. The type can be
Kasimier T. Buchcik2ee855d2005-03-07 11:14:14 +0000688 * of XML_SCHEMAS_STRING.
689 * WARNING: This one is intended to be expanded for other
690 * string based types. We need this for anySimpleType as well.
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +0000691 *
692 * Returns a pointer to the new value or NULL in case of error
693 */
694xmlSchemaValPtr
695xmlSchemaNewStringValue(xmlSchemaValType type,
696 const xmlChar *value)
697{
698 xmlSchemaValPtr val;
699
700 if (type != XML_SCHEMAS_STRING)
701 return(NULL);
702 val = (xmlSchemaValPtr) xmlMalloc(sizeof(xmlSchemaVal));
703 if (val == NULL) {
704 return(NULL);
705 }
706 memset(val, 0, sizeof(xmlSchemaVal));
707 val->type = type;
708 val->value.str = (xmlChar *) value;
709 return(val);
710}
711
Kasimier T. Buchcikb06b4de2005-02-17 19:00:23 +0000712/**
713 * xmlSchemaNewNOTATIONValue:
Daniel Veillardb5839c32005-02-19 18:27:14 +0000714 * @name: the notation name
715 * @ns: the notation namespace name or NULL
Kasimier T. Buchcikb06b4de2005-02-17 19:00:23 +0000716 *
717 * Allocate a new NOTATION value.
718 *
719 * Returns a pointer to the new value or NULL in case of error
720 */
721xmlSchemaValPtr
722xmlSchemaNewNOTATIONValue(const xmlChar *name,
723 const xmlChar *ns)
724{
725 xmlSchemaValPtr val;
726
727 val = xmlSchemaNewValue(XML_SCHEMAS_NOTATION);
728 if (val == NULL)
729 return (NULL);
730
William M. Brack12d37ab2005-02-21 13:54:07 +0000731 val->value.qname.name = (xmlChar *)name;
Kasimier T. Buchcikb06b4de2005-02-17 19:00:23 +0000732 if (ns != NULL)
William M. Brack12d37ab2005-02-21 13:54:07 +0000733 val->value.qname.uri = (xmlChar *)ns;
Kasimier T. Buchcikb06b4de2005-02-17 19:00:23 +0000734 return(val);
735}
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +0000736
737/**
Daniel Veillard4255d502002-04-16 15:50:10 +0000738 * xmlSchemaFreeValue:
739 * @value: the value to free
740 *
741 * Cleanup the default XML Schemas type library
742 */
743void
744xmlSchemaFreeValue(xmlSchemaValPtr value) {
745 if (value == NULL)
746 return;
Daniel Veillardc4c21552003-03-29 10:53:38 +0000747 switch (value->type) {
748 case XML_SCHEMAS_STRING:
749 case XML_SCHEMAS_NORMSTRING:
750 case XML_SCHEMAS_TOKEN:
751 case XML_SCHEMAS_LANGUAGE:
752 case XML_SCHEMAS_NMTOKEN:
753 case XML_SCHEMAS_NMTOKENS:
754 case XML_SCHEMAS_NAME:
Daniel Veillardc4c21552003-03-29 10:53:38 +0000755 case XML_SCHEMAS_NCNAME:
756 case XML_SCHEMAS_ID:
757 case XML_SCHEMAS_IDREF:
758 case XML_SCHEMAS_IDREFS:
759 case XML_SCHEMAS_ENTITY:
Kasimier T. Buchcikb06b4de2005-02-17 19:00:23 +0000760 case XML_SCHEMAS_ENTITIES:
Daniel Veillardc4c21552003-03-29 10:53:38 +0000761 case XML_SCHEMAS_ANYURI:
762 if (value->value.str != NULL)
763 xmlFree(value->value.str);
764 break;
Kasimier T. Buchcikb06b4de2005-02-17 19:00:23 +0000765 case XML_SCHEMAS_NOTATION:
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000766 case XML_SCHEMAS_QNAME:
767 if (value->value.qname.uri != NULL)
768 xmlFree(value->value.qname.uri);
769 if (value->value.qname.name != NULL)
770 xmlFree(value->value.qname.name);
771 break;
Daniel Veillard70bcb0e2003-08-08 14:00:28 +0000772 case XML_SCHEMAS_HEXBINARY:
773 if (value->value.hex.str != NULL)
774 xmlFree(value->value.hex.str);
775 break;
Daniel Veillard1ac24d32003-08-27 14:15:15 +0000776 case XML_SCHEMAS_BASE64BINARY:
777 if (value->value.base64.str != NULL)
778 xmlFree(value->value.base64.str);
779 break;
Daniel Veillardc4c21552003-03-29 10:53:38 +0000780 default:
781 break;
782 }
Daniel Veillard4255d502002-04-16 15:50:10 +0000783 xmlFree(value);
784}
785
786/**
787 * xmlSchemaGetPredefinedType:
788 * @name: the type name
789 * @ns: the URI of the namespace usually "http://www.w3.org/2001/XMLSchema"
790 *
791 * Lookup a type in the default XML Schemas type library
792 *
793 * Returns the type if found, NULL otherwise
794 */
795xmlSchemaTypePtr
796xmlSchemaGetPredefinedType(const xmlChar *name, const xmlChar *ns) {
797 if (xmlSchemaTypesInitialized == 0)
798 xmlSchemaInitTypes();
799 if (name == NULL)
800 return(NULL);
801 return((xmlSchemaTypePtr) xmlHashLookup2(xmlSchemaTypesBank, name, ns));
802}
Daniel Veillard070803b2002-05-03 07:29:38 +0000803
Daniel Veillard01fa6152004-06-29 17:04:39 +0000804/**
805 * xmlSchemaGetBuiltInListSimpleTypeItemType:
806 * @type: the built-in simple type.
807 *
Daniel Veillard6927b102004-10-27 17:29:04 +0000808 * Lookup function
809 *
Daniel Veillardc0826a72004-08-10 14:17:33 +0000810 * Returns the item type of @type as defined by the built-in datatype
811 * hierarchy of XML Schema Part 2: Datatypes, or NULL in case of an error.
Daniel Veillard01fa6152004-06-29 17:04:39 +0000812 */
813xmlSchemaTypePtr
814xmlSchemaGetBuiltInListSimpleTypeItemType(xmlSchemaTypePtr type)
815{
Daniel Veillard42595322004-11-08 10:52:06 +0000816 if ((type == NULL) || (type->type != XML_SCHEMA_TYPE_BASIC))
Daniel Veillard01fa6152004-06-29 17:04:39 +0000817 return (NULL);
818 switch (type->builtInType) {
819 case XML_SCHEMAS_NMTOKENS:
820 return (xmlSchemaTypeNmtokenDef );
821 case XML_SCHEMAS_IDREFS:
822 return (xmlSchemaTypeIdrefDef);
823 case XML_SCHEMAS_ENTITIES:
824 return (xmlSchemaTypeEntityDef);
825 default:
826 return (NULL);
827 }
828}
829
Daniel Veillard070803b2002-05-03 07:29:38 +0000830/****************************************************************
831 * *
832 * Convenience macros and functions *
833 * *
834 ****************************************************************/
835
836#define IS_TZO_CHAR(c) \
837 ((c == 0) || (c == 'Z') || (c == '+') || (c == '-'))
838
839#define VALID_YEAR(yr) (yr != 0)
840#define VALID_MONTH(mon) ((mon >= 1) && (mon <= 12))
841/* VALID_DAY should only be used when month is unknown */
842#define VALID_DAY(day) ((day >= 1) && (day <= 31))
843#define VALID_HOUR(hr) ((hr >= 0) && (hr <= 23))
844#define VALID_MIN(min) ((min >= 0) && (min <= 59))
845#define VALID_SEC(sec) ((sec >= 0) && (sec < 60))
846#define VALID_TZO(tzo) ((tzo > -1440) && (tzo < 1440))
847#define IS_LEAP(y) \
848 (((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0))
849
Daniel Veillardebe25d42004-03-25 09:35:49 +0000850static const unsigned int daysInMonth[12] =
Daniel Veillard070803b2002-05-03 07:29:38 +0000851 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
Daniel Veillardebe25d42004-03-25 09:35:49 +0000852static const unsigned int daysInMonthLeap[12] =
Daniel Veillard070803b2002-05-03 07:29:38 +0000853 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
854
Daniel Veillard5a872412002-05-22 06:40:27 +0000855#define MAX_DAYINMONTH(yr,mon) \
856 (IS_LEAP(yr) ? daysInMonthLeap[mon - 1] : daysInMonth[mon - 1])
857
Daniel Veillard070803b2002-05-03 07:29:38 +0000858#define VALID_MDAY(dt) \
859 (IS_LEAP(dt->year) ? \
860 (dt->day <= daysInMonthLeap[dt->mon - 1]) : \
861 (dt->day <= daysInMonth[dt->mon - 1]))
862
863#define VALID_DATE(dt) \
864 (VALID_YEAR(dt->year) && VALID_MONTH(dt->mon) && VALID_MDAY(dt))
865
866#define VALID_TIME(dt) \
867 (VALID_HOUR(dt->hour) && VALID_MIN(dt->min) && \
868 VALID_SEC(dt->sec) && VALID_TZO(dt->tzo))
869
870#define VALID_DATETIME(dt) \
871 (VALID_DATE(dt) && VALID_TIME(dt))
872
873#define SECS_PER_MIN (60)
874#define SECS_PER_HOUR (60 * SECS_PER_MIN)
875#define SECS_PER_DAY (24 * SECS_PER_HOUR)
876
Daniel Veillard5a872412002-05-22 06:40:27 +0000877static const long dayInYearByMonth[12] =
878 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
879static const long dayInLeapYearByMonth[12] =
880 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 };
881
882#define DAY_IN_YEAR(day, month, year) \
883 ((IS_LEAP(year) ? \
884 dayInLeapYearByMonth[month - 1] : \
885 dayInYearByMonth[month - 1]) + day)
886
887#ifdef DEBUG
888#define DEBUG_DATE(dt) \
889 xmlGenericError(xmlGenericErrorContext, \
890 "type=%o %04ld-%02u-%02uT%02u:%02u:%03f", \
891 dt->type,dt->value.date.year,dt->value.date.mon, \
892 dt->value.date.day,dt->value.date.hour,dt->value.date.min, \
893 dt->value.date.sec); \
894 if (dt->value.date.tz_flag) \
895 if (dt->value.date.tzo != 0) \
896 xmlGenericError(xmlGenericErrorContext, \
897 "%+05d\n",dt->value.date.tzo); \
898 else \
899 xmlGenericError(xmlGenericErrorContext, "Z\n"); \
900 else \
901 xmlGenericError(xmlGenericErrorContext,"\n")
902#else
903#define DEBUG_DATE(dt)
904#endif
905
Daniel Veillard070803b2002-05-03 07:29:38 +0000906/**
907 * _xmlSchemaParseGYear:
908 * @dt: pointer to a date structure
909 * @str: pointer to the string to analyze
910 *
911 * Parses a xs:gYear without time zone and fills in the appropriate
912 * field of the @dt structure. @str is updated to point just after the
913 * xs:gYear. It is supposed that @dt->year is big enough to contain
914 * the year.
915 *
916 * Returns 0 or the error code
917 */
918static int
919_xmlSchemaParseGYear (xmlSchemaValDatePtr dt, const xmlChar **str) {
920 const xmlChar *cur = *str, *firstChar;
921 int isneg = 0, digcnt = 0;
922
923 if (((*cur < '0') || (*cur > '9')) &&
924 (*cur != '-') && (*cur != '+'))
925 return -1;
926
927 if (*cur == '-') {
928 isneg = 1;
929 cur++;
930 }
931
932 firstChar = cur;
933
934 while ((*cur >= '0') && (*cur <= '9')) {
935 dt->year = dt->year * 10 + (*cur - '0');
936 cur++;
937 digcnt++;
938 }
939
940 /* year must be at least 4 digits (CCYY); over 4
941 * digits cannot have a leading zero. */
942 if ((digcnt < 4) || ((digcnt > 4) && (*firstChar == '0')))
943 return 1;
944
945 if (isneg)
946 dt->year = - dt->year;
947
948 if (!VALID_YEAR(dt->year))
949 return 2;
950
951 *str = cur;
952 return 0;
953}
954
955/**
956 * PARSE_2_DIGITS:
957 * @num: the integer to fill in
958 * @cur: an #xmlChar *
959 * @invalid: an integer
960 *
961 * Parses a 2-digits integer and updates @num with the value. @cur is
962 * updated to point just after the integer.
963 * In case of error, @invalid is set to %TRUE, values of @num and
964 * @cur are undefined.
965 */
966#define PARSE_2_DIGITS(num, cur, invalid) \
967 if ((cur[0] < '0') || (cur[0] > '9') || \
968 (cur[1] < '0') || (cur[1] > '9')) \
969 invalid = 1; \
970 else \
971 num = (cur[0] - '0') * 10 + (cur[1] - '0'); \
972 cur += 2;
973
974/**
975 * PARSE_FLOAT:
976 * @num: the double to fill in
977 * @cur: an #xmlChar *
978 * @invalid: an integer
979 *
980 * Parses a float and updates @num with the value. @cur is
981 * updated to point just after the float. The float must have a
982 * 2-digits integer part and may or may not have a decimal part.
983 * In case of error, @invalid is set to %TRUE, values of @num and
984 * @cur are undefined.
985 */
986#define PARSE_FLOAT(num, cur, invalid) \
987 PARSE_2_DIGITS(num, cur, invalid); \
988 if (!invalid && (*cur == '.')) { \
989 double mult = 1; \
990 cur++; \
991 if ((*cur < '0') || (*cur > '9')) \
992 invalid = 1; \
993 while ((*cur >= '0') && (*cur <= '9')) { \
994 mult /= 10; \
995 num += (*cur - '0') * mult; \
996 cur++; \
997 } \
998 }
999
1000/**
1001 * _xmlSchemaParseGMonth:
1002 * @dt: pointer to a date structure
1003 * @str: pointer to the string to analyze
1004 *
1005 * Parses a xs:gMonth without time zone and fills in the appropriate
1006 * field of the @dt structure. @str is updated to point just after the
1007 * xs:gMonth.
1008 *
1009 * Returns 0 or the error code
1010 */
1011static int
1012_xmlSchemaParseGMonth (xmlSchemaValDatePtr dt, const xmlChar **str) {
1013 const xmlChar *cur = *str;
1014 int ret = 0;
1015
1016 PARSE_2_DIGITS(dt->mon, cur, ret);
1017 if (ret != 0)
1018 return ret;
1019
1020 if (!VALID_MONTH(dt->mon))
1021 return 2;
1022
1023 *str = cur;
1024 return 0;
1025}
1026
1027/**
1028 * _xmlSchemaParseGDay:
1029 * @dt: pointer to a date structure
1030 * @str: pointer to the string to analyze
1031 *
1032 * Parses a xs:gDay without time zone and fills in the appropriate
1033 * field of the @dt structure. @str is updated to point just after the
1034 * xs:gDay.
1035 *
1036 * Returns 0 or the error code
1037 */
1038static int
1039_xmlSchemaParseGDay (xmlSchemaValDatePtr dt, const xmlChar **str) {
1040 const xmlChar *cur = *str;
1041 int ret = 0;
1042
1043 PARSE_2_DIGITS(dt->day, cur, ret);
1044 if (ret != 0)
1045 return ret;
1046
1047 if (!VALID_DAY(dt->day))
1048 return 2;
1049
1050 *str = cur;
1051 return 0;
1052}
1053
1054/**
1055 * _xmlSchemaParseTime:
1056 * @dt: pointer to a date structure
1057 * @str: pointer to the string to analyze
1058 *
1059 * Parses a xs:time without time zone and fills in the appropriate
1060 * fields of the @dt structure. @str is updated to point just after the
1061 * xs:time.
1062 * In case of error, values of @dt fields are undefined.
1063 *
1064 * Returns 0 or the error code
1065 */
1066static int
1067_xmlSchemaParseTime (xmlSchemaValDatePtr dt, const xmlChar **str) {
1068 const xmlChar *cur = *str;
1069 unsigned int hour = 0; /* use temp var in case str is not xs:time */
1070 int ret = 0;
1071
1072 PARSE_2_DIGITS(hour, cur, ret);
1073 if (ret != 0)
1074 return ret;
1075
1076 if (*cur != ':')
1077 return 1;
1078 cur++;
1079
1080 /* the ':' insures this string is xs:time */
1081 dt->hour = hour;
1082
1083 PARSE_2_DIGITS(dt->min, cur, ret);
1084 if (ret != 0)
1085 return ret;
1086
1087 if (*cur != ':')
1088 return 1;
1089 cur++;
1090
1091 PARSE_FLOAT(dt->sec, cur, ret);
1092 if (ret != 0)
1093 return ret;
1094
1095 if (!VALID_TIME(dt))
1096 return 2;
1097
1098 *str = cur;
1099 return 0;
1100}
1101
1102/**
1103 * _xmlSchemaParseTimeZone:
1104 * @dt: pointer to a date structure
1105 * @str: pointer to the string to analyze
1106 *
1107 * Parses a time zone without time zone and fills in the appropriate
1108 * field of the @dt structure. @str is updated to point just after the
1109 * time zone.
1110 *
1111 * Returns 0 or the error code
1112 */
1113static int
1114_xmlSchemaParseTimeZone (xmlSchemaValDatePtr dt, const xmlChar **str) {
1115 const xmlChar *cur = *str;
1116 int ret = 0;
1117
1118 if (str == NULL)
1119 return -1;
1120
1121 switch (*cur) {
1122 case 0:
1123 dt->tz_flag = 0;
1124 dt->tzo = 0;
1125 break;
1126
1127 case 'Z':
1128 dt->tz_flag = 1;
1129 dt->tzo = 0;
1130 cur++;
1131 break;
1132
1133 case '+':
1134 case '-': {
1135 int isneg = 0, tmp = 0;
1136 isneg = (*cur == '-');
1137
1138 cur++;
1139
1140 PARSE_2_DIGITS(tmp, cur, ret);
1141 if (ret != 0)
1142 return ret;
1143 if (!VALID_HOUR(tmp))
1144 return 2;
1145
1146 if (*cur != ':')
1147 return 1;
1148 cur++;
1149
1150 dt->tzo = tmp * 60;
1151
1152 PARSE_2_DIGITS(tmp, cur, ret);
1153 if (ret != 0)
1154 return ret;
1155 if (!VALID_MIN(tmp))
1156 return 2;
1157
1158 dt->tzo += tmp;
1159 if (isneg)
1160 dt->tzo = - dt->tzo;
1161
1162 if (!VALID_TZO(dt->tzo))
1163 return 2;
1164
Daniel Veillard5a872412002-05-22 06:40:27 +00001165 dt->tz_flag = 1;
Daniel Veillard070803b2002-05-03 07:29:38 +00001166 break;
1167 }
1168 default:
1169 return 1;
1170 }
1171
1172 *str = cur;
1173 return 0;
1174}
1175
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001176/**
1177 * _xmlSchemaBase64Decode:
1178 * @ch: a character
1179 *
1180 * Converts a base64 encoded character to its base 64 value.
1181 *
1182 * Returns 0-63 (value), 64 (pad), or -1 (not recognized)
1183 */
1184static int
1185_xmlSchemaBase64Decode (const xmlChar ch) {
1186 if (('A' <= ch) && (ch <= 'Z')) return ch - 'A';
1187 if (('a' <= ch) && (ch <= 'z')) return ch - 'a' + 26;
1188 if (('0' <= ch) && (ch <= '9')) return ch - '0' + 52;
1189 if ('+' == ch) return 62;
1190 if ('/' == ch) return 63;
1191 if ('=' == ch) return 64;
1192 return -1;
1193}
1194
Daniel Veillard070803b2002-05-03 07:29:38 +00001195/****************************************************************
1196 * *
1197 * XML Schema Dates/Times Datatypes Handling *
1198 * *
1199 ****************************************************************/
1200
1201/**
1202 * PARSE_DIGITS:
1203 * @num: the integer to fill in
1204 * @cur: an #xmlChar *
1205 * @num_type: an integer flag
1206 *
1207 * Parses a digits integer and updates @num with the value. @cur is
1208 * updated to point just after the integer.
1209 * In case of error, @num_type is set to -1, values of @num and
1210 * @cur are undefined.
1211 */
1212#define PARSE_DIGITS(num, cur, num_type) \
1213 if ((*cur < '0') || (*cur > '9')) \
1214 num_type = -1; \
1215 else \
1216 while ((*cur >= '0') && (*cur <= '9')) { \
1217 num = num * 10 + (*cur - '0'); \
1218 cur++; \
1219 }
1220
1221/**
1222 * PARSE_NUM:
1223 * @num: the double to fill in
1224 * @cur: an #xmlChar *
1225 * @num_type: an integer flag
1226 *
1227 * Parses a float or integer and updates @num with the value. @cur is
1228 * updated to point just after the number. If the number is a float,
1229 * then it must have an integer part and a decimal part; @num_type will
1230 * be set to 1. If there is no decimal part, @num_type is set to zero.
1231 * In case of error, @num_type is set to -1, values of @num and
1232 * @cur are undefined.
1233 */
1234#define PARSE_NUM(num, cur, num_type) \
1235 num = 0; \
1236 PARSE_DIGITS(num, cur, num_type); \
1237 if (!num_type && (*cur == '.')) { \
1238 double mult = 1; \
1239 cur++; \
1240 if ((*cur < '0') || (*cur > '9')) \
1241 num_type = -1; \
1242 else \
1243 num_type = 1; \
1244 while ((*cur >= '0') && (*cur <= '9')) { \
1245 mult /= 10; \
1246 num += (*cur - '0') * mult; \
1247 cur++; \
1248 } \
1249 }
1250
1251/**
Daniel Veillard5a872412002-05-22 06:40:27 +00001252 * xmlSchemaValidateDates:
Daniel Veillard455cc072003-03-31 10:13:23 +00001253 * @type: the expected type or XML_SCHEMAS_UNKNOWN
Daniel Veillard070803b2002-05-03 07:29:38 +00001254 * @dateTime: string to analyze
1255 * @val: the return computed value
1256 *
1257 * Check that @dateTime conforms to the lexical space of one of the date types.
1258 * if true a value is computed and returned in @val.
1259 *
1260 * Returns 0 if this validates, a positive error code number otherwise
1261 * and -1 in case of internal or API error.
1262 */
1263static int
Daniel Veillard455cc072003-03-31 10:13:23 +00001264xmlSchemaValidateDates (xmlSchemaValType type,
Daniel Veillard118aed72002-09-24 14:13:13 +00001265 const xmlChar *dateTime, xmlSchemaValPtr *val) {
Daniel Veillard070803b2002-05-03 07:29:38 +00001266 xmlSchemaValPtr dt;
1267 int ret;
1268 const xmlChar *cur = dateTime;
1269
1270#define RETURN_TYPE_IF_VALID(t) \
1271 if (IS_TZO_CHAR(*cur)) { \
1272 ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur); \
1273 if (ret == 0) { \
1274 if (*cur != 0) \
1275 goto error; \
1276 dt->type = t; \
Daniel Veillard455cc072003-03-31 10:13:23 +00001277 goto done; \
Daniel Veillard070803b2002-05-03 07:29:38 +00001278 } \
1279 }
1280
1281 if (dateTime == NULL)
1282 return -1;
1283
1284 if ((*cur != '-') && (*cur < '0') && (*cur > '9'))
1285 return 1;
1286
1287 dt = xmlSchemaNewValue(XML_SCHEMAS_UNKNOWN);
1288 if (dt == NULL)
1289 return -1;
1290
1291 if ((cur[0] == '-') && (cur[1] == '-')) {
1292 /*
1293 * It's an incomplete date (xs:gMonthDay, xs:gMonth or
1294 * xs:gDay)
1295 */
1296 cur += 2;
1297
1298 /* is it an xs:gDay? */
1299 if (*cur == '-') {
Daniel Veillard455cc072003-03-31 10:13:23 +00001300 if (type == XML_SCHEMAS_GMONTH)
1301 goto error;
Daniel Veillard070803b2002-05-03 07:29:38 +00001302 ++cur;
1303 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
1304 if (ret != 0)
1305 goto error;
1306
1307 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GDAY);
1308
1309 goto error;
1310 }
1311
1312 /*
1313 * it should be an xs:gMonthDay or xs:gMonth
1314 */
1315 ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
1316 if (ret != 0)
1317 goto error;
1318
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001319 /*
1320 * a '-' char could indicate this type is xs:gMonthDay or
1321 * a negative time zone offset. Check for xs:gMonthDay first.
1322 * Also the first three char's of a negative tzo (-MM:SS) can
1323 * appear to be a valid day; so even if the day portion
1324 * of the xs:gMonthDay verifies, we must insure it was not
1325 * a tzo.
1326 */
1327 if (*cur == '-') {
1328 const xmlChar *rewnd = cur;
1329 cur++;
Daniel Veillard070803b2002-05-03 07:29:38 +00001330
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001331 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
1332 if ((ret == 0) && ((*cur == 0) || (*cur != ':'))) {
1333
1334 /*
1335 * we can use the VALID_MDAY macro to validate the month
1336 * and day because the leap year test will flag year zero
1337 * as a leap year (even though zero is an invalid year).
1338 */
1339 if (VALID_MDAY((&(dt->value.date)))) {
1340
1341 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTHDAY);
1342
1343 goto error;
1344 }
1345 }
1346
1347 /*
1348 * not xs:gMonthDay so rewind and check if just xs:gMonth
1349 * with an optional time zone.
1350 */
1351 cur = rewnd;
1352 }
1353
1354 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTH);
Daniel Veillard070803b2002-05-03 07:29:38 +00001355
1356 goto error;
1357 }
1358
1359 /*
1360 * It's a right-truncated date or an xs:time.
1361 * Try to parse an xs:time then fallback on right-truncated dates.
1362 */
1363 if ((*cur >= '0') && (*cur <= '9')) {
1364 ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
1365 if (ret == 0) {
1366 /* it's an xs:time */
1367 RETURN_TYPE_IF_VALID(XML_SCHEMAS_TIME);
1368 }
1369 }
1370
1371 /* fallback on date parsing */
1372 cur = dateTime;
1373
1374 ret = _xmlSchemaParseGYear(&(dt->value.date), &cur);
1375 if (ret != 0)
1376 goto error;
1377
1378 /* is it an xs:gYear? */
1379 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEAR);
1380
1381 if (*cur != '-')
1382 goto error;
1383 cur++;
1384
1385 ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
1386 if (ret != 0)
1387 goto error;
1388
1389 /* is it an xs:gYearMonth? */
1390 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEARMONTH);
1391
1392 if (*cur != '-')
1393 goto error;
1394 cur++;
1395
1396 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
1397 if ((ret != 0) || !VALID_DATE((&(dt->value.date))))
1398 goto error;
1399
1400 /* is it an xs:date? */
1401 RETURN_TYPE_IF_VALID(XML_SCHEMAS_DATE);
1402
1403 if (*cur != 'T')
1404 goto error;
1405 cur++;
1406
1407 /* it should be an xs:dateTime */
1408 ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
1409 if (ret != 0)
1410 goto error;
1411
1412 ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur);
1413 if ((ret != 0) || (*cur != 0) || !VALID_DATETIME((&(dt->value.date))))
1414 goto error;
1415
Daniel Veillard455cc072003-03-31 10:13:23 +00001416
Daniel Veillard070803b2002-05-03 07:29:38 +00001417 dt->type = XML_SCHEMAS_DATETIME;
1418
Daniel Veillard455cc072003-03-31 10:13:23 +00001419done:
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001420#if 1
1421 if ((type != XML_SCHEMAS_UNKNOWN) && (type != dt->type))
1422 goto error;
1423#else
1424 /*
1425 * insure the parsed type is equal to or less significant (right
1426 * truncated) than the desired type.
1427 */
1428 if ((type != XML_SCHEMAS_UNKNOWN) && (type != dt->type)) {
1429
1430 /* time only matches time */
1431 if ((type == XML_SCHEMAS_TIME) && (dt->type == XML_SCHEMAS_TIME))
1432 goto error;
1433
1434 if ((type == XML_SCHEMAS_DATETIME) &&
1435 ((dt->type != XML_SCHEMAS_DATE) ||
1436 (dt->type != XML_SCHEMAS_GYEARMONTH) ||
1437 (dt->type != XML_SCHEMAS_GYEAR)))
1438 goto error;
1439
1440 if ((type == XML_SCHEMAS_DATE) &&
1441 ((dt->type != XML_SCHEMAS_GYEAR) ||
1442 (dt->type != XML_SCHEMAS_GYEARMONTH)))
1443 goto error;
1444
1445 if ((type == XML_SCHEMAS_GYEARMONTH) && (dt->type != XML_SCHEMAS_GYEAR))
1446 goto error;
1447
1448 if ((type == XML_SCHEMAS_GMONTHDAY) && (dt->type != XML_SCHEMAS_GMONTH))
1449 goto error;
1450 }
Daniel Veillard455cc072003-03-31 10:13:23 +00001451#endif
1452
Daniel Veillard070803b2002-05-03 07:29:38 +00001453 if (val != NULL)
1454 *val = dt;
Daniel Veillard80b19092003-03-28 13:29:53 +00001455 else
1456 xmlSchemaFreeValue(dt);
Daniel Veillard070803b2002-05-03 07:29:38 +00001457
1458 return 0;
1459
1460error:
1461 if (dt != NULL)
1462 xmlSchemaFreeValue(dt);
1463 return 1;
1464}
1465
1466/**
Daniel Veillard5a872412002-05-22 06:40:27 +00001467 * xmlSchemaValidateDuration:
Daniel Veillard070803b2002-05-03 07:29:38 +00001468 * @type: the predefined type
1469 * @duration: string to analyze
1470 * @val: the return computed value
1471 *
1472 * Check that @duration conforms to the lexical space of the duration type.
1473 * if true a value is computed and returned in @val.
1474 *
1475 * Returns 0 if this validates, a positive error code number otherwise
1476 * and -1 in case of internal or API error.
1477 */
1478static int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00001479xmlSchemaValidateDuration (xmlSchemaTypePtr type ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +00001480 const xmlChar *duration, xmlSchemaValPtr *val) {
Daniel Veillard070803b2002-05-03 07:29:38 +00001481 const xmlChar *cur = duration;
1482 xmlSchemaValPtr dur;
1483 int isneg = 0;
1484 unsigned int seq = 0;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001485 double num;
1486 int num_type = 0; /* -1 = invalid, 0 = int, 1 = floating */
1487 const xmlChar desig[] = {'Y', 'M', 'D', 'H', 'M', 'S'};
1488 const double multi[] = { 0.0, 0.0, 86400.0, 3600.0, 60.0, 1.0, 0.0};
Daniel Veillard070803b2002-05-03 07:29:38 +00001489
1490 if (duration == NULL)
1491 return -1;
1492
1493 if (*cur == '-') {
1494 isneg = 1;
1495 cur++;
1496 }
1497
1498 /* duration must start with 'P' (after sign) */
1499 if (*cur++ != 'P')
1500 return 1;
1501
Daniel Veillard80b19092003-03-28 13:29:53 +00001502 if (*cur == 0)
1503 return 1;
1504
Daniel Veillard070803b2002-05-03 07:29:38 +00001505 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
1506 if (dur == NULL)
1507 return -1;
1508
1509 while (*cur != 0) {
Daniel Veillard070803b2002-05-03 07:29:38 +00001510
1511 /* input string should be empty or invalid date/time item */
1512 if (seq >= sizeof(desig))
1513 goto error;
1514
1515 /* T designator must be present for time items */
1516 if (*cur == 'T') {
1517 if (seq <= 3) {
1518 seq = 3;
1519 cur++;
1520 } else
1521 return 1;
1522 } else if (seq == 3)
1523 goto error;
1524
1525 /* parse the number portion of the item */
1526 PARSE_NUM(num, cur, num_type);
1527
1528 if ((num_type == -1) || (*cur == 0))
1529 goto error;
1530
1531 /* update duration based on item type */
1532 while (seq < sizeof(desig)) {
1533 if (*cur == desig[seq]) {
1534
1535 /* verify numeric type; only seconds can be float */
1536 if ((num_type != 0) && (seq < (sizeof(desig)-1)))
1537 goto error;
1538
1539 switch (seq) {
1540 case 0:
1541 dur->value.dur.mon = (long)num * 12;
1542 break;
1543 case 1:
1544 dur->value.dur.mon += (long)num;
1545 break;
1546 default:
1547 /* convert to seconds using multiplier */
1548 dur->value.dur.sec += num * multi[seq];
1549 seq++;
1550 break;
1551 }
1552
1553 break; /* exit loop */
1554 }
1555 /* no date designators found? */
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00001556 if ((++seq == 3) || (seq == 6))
Daniel Veillard070803b2002-05-03 07:29:38 +00001557 goto error;
1558 }
1559 cur++;
1560 }
1561
1562 if (isneg) {
1563 dur->value.dur.mon = -dur->value.dur.mon;
1564 dur->value.dur.day = -dur->value.dur.day;
1565 dur->value.dur.sec = -dur->value.dur.sec;
1566 }
1567
1568 if (val != NULL)
1569 *val = dur;
Daniel Veillard80b19092003-03-28 13:29:53 +00001570 else
1571 xmlSchemaFreeValue(dur);
Daniel Veillard070803b2002-05-03 07:29:38 +00001572
1573 return 0;
1574
1575error:
1576 if (dur != NULL)
1577 xmlSchemaFreeValue(dur);
1578 return 1;
1579}
1580
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001581/**
1582 * xmlSchemaStrip:
1583 * @value: a value
1584 *
1585 * Removes the leading and ending spaces of a string
1586 *
1587 * Returns the new string or NULL if no change was required.
1588 */
1589static xmlChar *
1590xmlSchemaStrip(const xmlChar *value) {
1591 const xmlChar *start = value, *end, *f;
1592
1593 if (value == NULL) return(NULL);
William M. Brack76e95df2003-10-18 16:20:14 +00001594 while ((*start != 0) && (IS_BLANK_CH(*start))) start++;
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001595 end = start;
1596 while (*end != 0) end++;
1597 f = end;
1598 end--;
William M. Brack76e95df2003-10-18 16:20:14 +00001599 while ((end > start) && (IS_BLANK_CH(*end))) end--;
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001600 end++;
1601 if ((start == value) && (f == end)) return(NULL);
1602 return(xmlStrndup(start, end - start));
1603}
Daniel Veillard96a4b252003-02-06 08:22:32 +00001604
1605/**
Kasimier T. Buchcik91feaf82004-11-12 14:04:58 +00001606 * xmlSchemaWhiteSpaceReplace:
1607 * @value: a value
1608 *
1609 * Replaces 0xd, 0x9 and 0xa with a space.
1610 *
1611 * Returns the new string or NULL if no change was required.
1612 */
1613xmlChar *
1614xmlSchemaWhiteSpaceReplace(const xmlChar *value) {
1615 const xmlChar *cur = value;
1616 xmlChar *ret = NULL, *mcur;
1617
1618 if (value == NULL)
1619 return(NULL);
1620
1621 while ((*cur != 0) &&
1622 (((*cur) != 0xd) && ((*cur) != 0x9) && ((*cur) != 0xa))) {
1623 cur++;
1624 }
1625 if (*cur == 0)
1626 return (NULL);
1627 ret = xmlStrdup(value);
1628 /* TODO FIXME: I guess gcc will bark at this. */
1629 mcur = (xmlChar *) (ret + (cur - value));
1630 do {
1631 if ( ((*mcur) == 0xd) || ((*mcur) == 0x9) || ((*mcur) == 0xa) )
1632 *mcur = ' ';
1633 mcur++;
1634 } while (*mcur != 0);
1635 return(ret);
1636}
1637
1638/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001639 * xmlSchemaCollapseString:
1640 * @value: a value
1641 *
1642 * Removes and normalize white spaces in the string
1643 *
1644 * Returns the new string or NULL if no change was required.
1645 */
Daniel Veillard01fa6152004-06-29 17:04:39 +00001646xmlChar *
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001647xmlSchemaCollapseString(const xmlChar *value) {
1648 const xmlChar *start = value, *end, *f;
1649 xmlChar *g;
1650 int col = 0;
1651
1652 if (value == NULL) return(NULL);
William M. Brack76e95df2003-10-18 16:20:14 +00001653 while ((*start != 0) && (IS_BLANK_CH(*start))) start++;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001654 end = start;
1655 while (*end != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00001656 if ((*end == ' ') && (IS_BLANK_CH(end[1]))) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001657 col = end - start;
1658 break;
1659 } else if ((*end == 0xa) || (*end == 0x9) || (*end == 0xd)) {
1660 col = end - start;
1661 break;
1662 }
1663 end++;
1664 }
1665 if (col == 0) {
1666 f = end;
1667 end--;
William M. Brack76e95df2003-10-18 16:20:14 +00001668 while ((end > start) && (IS_BLANK_CH(*end))) end--;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001669 end++;
1670 if ((start == value) && (f == end)) return(NULL);
1671 return(xmlStrndup(start, end - start));
1672 }
1673 start = xmlStrdup(start);
1674 if (start == NULL) return(NULL);
1675 g = (xmlChar *) (start + col);
1676 end = g;
1677 while (*end != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00001678 if (IS_BLANK_CH(*end)) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001679 end++;
William M. Brack76e95df2003-10-18 16:20:14 +00001680 while (IS_BLANK_CH(*end)) end++;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001681 if (*end != 0)
1682 *g++ = ' ';
1683 } else
1684 *g++ = *end++;
1685 }
1686 *g = 0;
1687 return((xmlChar *) start);
1688}
1689
1690/**
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001691 * xmlSchemaValAtomicListNode:
1692 * @type: the predefined atomic type for a token in the list
1693 * @value: the list value to check
1694 * @ret: the return computed value
1695 * @node: the node containing the value
1696 *
1697 * Check that a value conforms to the lexical space of the predefined
1698 * list type. if true a value is computed and returned in @ret.
1699 *
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001700 * Returns the number of items if this validates, a negative error code
1701 * number otherwise
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001702 */
1703static int
1704xmlSchemaValAtomicListNode(xmlSchemaTypePtr type, const xmlChar *value,
1705 xmlSchemaValPtr *ret, xmlNodePtr node) {
1706 xmlChar *val, *cur, *endval;
1707 int nb_values = 0;
Daniel Veillard580ced82003-03-21 21:22:48 +00001708 int tmp = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001709
1710 if (value == NULL) {
1711 return(-1);
1712 }
1713 val = xmlStrdup(value);
1714 if (val == NULL) {
1715 return(-1);
1716 }
Daniel Veillard6fc5db02005-01-16 00:05:58 +00001717 if (ret != NULL) {
1718 *ret = NULL;
1719 }
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001720 cur = val;
1721 /*
1722 * Split the list
1723 */
William M. Brack76e95df2003-10-18 16:20:14 +00001724 while (IS_BLANK_CH(*cur)) *cur++ = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001725 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00001726 if (IS_BLANK_CH(*cur)) {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001727 *cur = 0;
1728 cur++;
William M. Brack76e95df2003-10-18 16:20:14 +00001729 while (IS_BLANK_CH(*cur)) *cur++ = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001730 } else {
1731 nb_values++;
1732 cur++;
William M. Brack76e95df2003-10-18 16:20:14 +00001733 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001734 }
1735 }
1736 if (nb_values == 0) {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001737 xmlFree(val);
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001738 return(nb_values);
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001739 }
1740 endval = cur;
1741 cur = val;
1742 while ((*cur == 0) && (cur != endval)) cur++;
1743 while (cur != endval) {
1744 tmp = xmlSchemaValPredefTypeNode(type, cur, NULL, node);
1745 if (tmp != 0)
1746 break;
1747 while (*cur != 0) cur++;
1748 while ((*cur == 0) && (cur != endval)) cur++;
1749 }
Daniel Veillard6fc5db02005-01-16 00:05:58 +00001750 /* TODO what return value ? c.f. bug #158628
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001751 if (ret != NULL) {
1752 TODO
Daniel Veillard6fc5db02005-01-16 00:05:58 +00001753 } */
1754 xmlFree(val);
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001755 if (tmp == 0)
1756 return(nb_values);
1757 return(-1);
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001758}
1759
1760/**
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001761 * xmlSchemaParseUInt:
1762 * @str: pointer to the string R/W
1763 * @llo: pointer to the low result
1764 * @lmi: pointer to the mid result
1765 * @lhi: pointer to the high result
1766 *
1767 * Parse an unsigned long into 3 fields.
1768 *
William M. Brackec3b4b72005-03-15 15:50:17 +00001769 * Returns the number of significant digits in the number or
1770 * -1 if overflow of the capacity
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001771 */
1772static int
1773xmlSchemaParseUInt(const xmlChar **str, unsigned long *llo,
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00001774 unsigned long *lmi, unsigned long *lhi) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001775 unsigned long lo = 0, mi = 0, hi = 0;
1776 const xmlChar *tmp, *cur = *str;
1777 int ret = 0, i = 0;
1778
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00001779 while (*cur == '0') { /* ignore leading zeroes */
1780 cur++;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001781 }
1782 tmp = cur;
1783 while ((*tmp != 0) && (*tmp >= '0') && (*tmp <= '9')) {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00001784 i++;tmp++;ret++;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001785 }
1786 if (i > 24) {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00001787 *str = tmp;
1788 return(-1);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001789 }
1790 while (i > 16) {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00001791 hi = hi * 10 + (*cur++ - '0');
1792 i--;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001793 }
1794 while (i > 8) {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00001795 mi = mi * 10 + (*cur++ - '0');
1796 i--;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001797 }
1798 while (i > 0) {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00001799 lo = lo * 10 + (*cur++ - '0');
1800 i--;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001801 }
1802
1803 *str = cur;
1804 *llo = lo;
1805 *lmi = mi;
1806 *lhi = hi;
1807 return(ret);
1808}
1809
1810/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001811 * xmlSchemaValAtomicType:
1812 * @type: the predefined type
1813 * @value: the value to check
1814 * @val: the return computed value
1815 * @node: the node containing the value
1816 * flags: flags to control the vlidation
1817 *
1818 * Check that a value conforms to the lexical space of the atomic type.
1819 * if true a value is computed and returned in @val.
Daniel Veillard01fa6152004-06-29 17:04:39 +00001820 * This checks the value space for list types as well (IDREFS, NMTOKENS).
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001821 *
1822 * Returns 0 if this validates, a positive error code number otherwise
1823 * and -1 in case of internal or API error.
1824 */
1825static int
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001826xmlSchemaValAtomicType(xmlSchemaTypePtr type, const xmlChar * value,
1827 xmlSchemaValPtr * val, xmlNodePtr node, int flags)
1828{
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001829 xmlSchemaValPtr v;
1830 xmlChar *norm = NULL;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001831 int ret = 0;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001832
1833 if (xmlSchemaTypesInitialized == 0)
Daniel Veillard01fa6152004-06-29 17:04:39 +00001834 xmlSchemaInitTypes();
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001835 if (type == NULL)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001836 return (-1);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001837
Daniel Veillardeebd6332004-08-26 10:30:44 +00001838 /*
1839 * validating a non existant text node is similar to validating
1840 * an empty one.
1841 */
1842 if (value == NULL)
1843 value = BAD_CAST "";
1844
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001845 if (val != NULL)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001846 *val = NULL;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001847 if ((flags == 0) && (value != NULL)) {
Kasimier T. Buchcik91feaf82004-11-12 14:04:58 +00001848
Daniel Veillard01fa6152004-06-29 17:04:39 +00001849 if ((type->builtInType != XML_SCHEMAS_STRING) &&
Kasimier T. Buchcik91feaf82004-11-12 14:04:58 +00001850 (type->builtInType != XML_SCHEMAS_ANYTYPE) &&
1851 (type->builtInType != XML_SCHEMAS_ANYSIMPLETYPE)) {
1852 if (type->builtInType == XML_SCHEMAS_NORMSTRING)
1853 norm = xmlSchemaWhiteSpaceReplace(value);
1854 else
1855 norm = xmlSchemaCollapseString(value);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001856 if (norm != NULL)
1857 value = norm;
1858 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001859 }
1860
Daniel Veillard01fa6152004-06-29 17:04:39 +00001861 switch (type->builtInType) {
William M. Brack2f2a6632004-08-20 23:09:47 +00001862 case XML_SCHEMAS_UNKNOWN:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001863 goto error;
William M. Brack2f2a6632004-08-20 23:09:47 +00001864 case XML_SCHEMAS_ANYTYPE:
1865 case XML_SCHEMAS_ANYSIMPLETYPE:
1866 goto return0;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001867 case XML_SCHEMAS_STRING:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001868 goto return0;
Daniel Veillard1516d5b2004-01-22 07:27:45 +00001869 case XML_SCHEMAS_NORMSTRING:{
1870 const xmlChar *cur = value;
1871
1872 while (*cur != 0) {
1873 if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) {
1874 goto return1;
1875 } else {
1876 cur++;
1877 }
1878 }
1879 if (val != NULL) {
1880 v = xmlSchemaNewValue(XML_SCHEMAS_NORMSTRING);
1881 if (v != NULL) {
1882 v->value.str = xmlStrdup(value);
1883 *val = v;
1884 } else {
1885 goto error;
1886 }
1887 }
1888 goto return0;
1889 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001890 case XML_SCHEMAS_DECIMAL:{
William M. Brack273670f2005-03-11 15:55:14 +00001891 const xmlChar *cur = value;
1892 unsigned int len, neg = 0;
1893 xmlChar cval[25];
1894 xmlChar *cptr = cval;
1895 int dec = -1;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001896
1897 if (cur == NULL)
1898 goto return1;
William M. Brack273670f2005-03-11 15:55:14 +00001899 /* First we handle an optional sign */
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001900 if (*cur == '+')
1901 cur++;
1902 else if (*cur == '-') {
1903 neg = 1;
1904 cur++;
1905 }
William M. Brack273670f2005-03-11 15:55:14 +00001906 /*
1907 * Next we "pre-parse" the number, in preparation for calling
1908 * the common routine xmlSchemaParseUInt. We get rid of any
1909 * leading zeroes (because we have reserved only 25 chars),
1910 * and note the position of any decimal point.
1911 */
1912 len = 0;
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00001913 /*
1914 * Skip leading zeroes.
1915 */
1916 while (*cur == '0')
William M. Brack273670f2005-03-11 15:55:14 +00001917 cur++;
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00001918 if (*cur != 0) {
1919 while (len < 24) {
1920 if ((*cur >= '0') && (*cur <= '9')) {
1921 *cptr++ = *cur++;
1922 len++;
1923 } else if (*cur == '.') {
1924 if (dec != -1)
1925 goto return1; /* multiple decimal points */
1926 cur++;
1927 if ((*cur == 0) && (cur -1 == value))
1928 goto return1;
1929
1930 dec = len;
1931 while ((len < 24) && (*cur >= '0') &&
1932 (*cur <= '9')) {
1933 *cptr++ = *cur++;
1934 len++;
1935 }
1936 break;
1937 } else
1938 break;
1939 }
William M. Brack273670f2005-03-11 15:55:14 +00001940 }
1941 if (*cur != 0)
1942 goto return1; /* error if any extraneous chars */
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001943 if (val != NULL) {
1944 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
1945 if (v != NULL) {
William M. Brack273670f2005-03-11 15:55:14 +00001946 /*
1947 * If a mixed decimal, get rid of trailing zeroes
1948 */
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00001949 if (dec != -1) {
William M. Brack273670f2005-03-11 15:55:14 +00001950 while ((cptr > cval) && (*(cptr-1) == '0')) {
1951 cptr--;
1952 len--;
1953 }
1954 }
1955 *cptr = 0; /* Terminate our (preparsed) string */
1956 cptr = cval;
1957 /*
1958 * Now evaluate the significant digits of the number
1959 */
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00001960 if (*cptr != 0)
1961 xmlSchemaParseUInt((const xmlChar **)&cptr,
William M. Brack273670f2005-03-11 15:55:14 +00001962 &v->value.decimal.lo,
1963 &v->value.decimal.mi,
1964 &v->value.decimal.hi);
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00001965 /*
1966 * Set the total digits to 1 if a zero value.
1967 */
1968 if (len == 0)
1969 len++;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001970 v->value.decimal.sign = neg;
William M. Brack273670f2005-03-11 15:55:14 +00001971 if (dec == -1) {
1972 v->value.decimal.frac = 0;
1973 v->value.decimal.total = len;
1974 } else {
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00001975 v->value.decimal.frac = len - dec;
1976 v->value.decimal.total = len;
William M. Brack273670f2005-03-11 15:55:14 +00001977 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001978 *val = v;
1979 }
1980 }
1981 goto return0;
1982 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001983 case XML_SCHEMAS_TIME:
1984 case XML_SCHEMAS_GDAY:
1985 case XML_SCHEMAS_GMONTH:
1986 case XML_SCHEMAS_GMONTHDAY:
1987 case XML_SCHEMAS_GYEAR:
1988 case XML_SCHEMAS_GYEARMONTH:
1989 case XML_SCHEMAS_DATE:
1990 case XML_SCHEMAS_DATETIME:
Daniel Veillard01fa6152004-06-29 17:04:39 +00001991 ret = xmlSchemaValidateDates(type->builtInType, value, val);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001992 break;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001993 case XML_SCHEMAS_DURATION:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001994 ret = xmlSchemaValidateDuration(type, value, val);
1995 break;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001996 case XML_SCHEMAS_FLOAT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001997 case XML_SCHEMAS_DOUBLE:{
1998 const xmlChar *cur = value;
1999 int neg = 0;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002000
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002001 if (cur == NULL)
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00002002 goto return1;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002003 if ((cur[0] == 'N') && (cur[1] == 'a') && (cur[2] == 'N')) {
2004 cur += 3;
2005 if (*cur != 0)
2006 goto return1;
2007 if (val != NULL) {
2008 if (type == xmlSchemaTypeFloatDef) {
2009 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
2010 if (v != NULL) {
2011 v->value.f = (float) xmlXPathNAN;
2012 } else {
2013 xmlSchemaFreeValue(v);
2014 goto error;
2015 }
2016 } else {
2017 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
2018 if (v != NULL) {
2019 v->value.d = xmlXPathNAN;
2020 } else {
2021 xmlSchemaFreeValue(v);
2022 goto error;
2023 }
2024 }
2025 *val = v;
2026 }
2027 goto return0;
2028 }
2029 if (*cur == '-') {
2030 neg = 1;
2031 cur++;
2032 }
2033 if ((cur[0] == 'I') && (cur[1] == 'N') && (cur[2] == 'F')) {
2034 cur += 3;
2035 if (*cur != 0)
2036 goto return1;
2037 if (val != NULL) {
2038 if (type == xmlSchemaTypeFloatDef) {
2039 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
2040 if (v != NULL) {
2041 if (neg)
2042 v->value.f = (float) xmlXPathNINF;
2043 else
2044 v->value.f = (float) xmlXPathPINF;
2045 } else {
2046 xmlSchemaFreeValue(v);
2047 goto error;
2048 }
2049 } else {
2050 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
2051 if (v != NULL) {
2052 if (neg)
2053 v->value.d = xmlXPathNINF;
2054 else
2055 v->value.d = xmlXPathPINF;
2056 } else {
2057 xmlSchemaFreeValue(v);
2058 goto error;
2059 }
2060 }
2061 *val = v;
2062 }
2063 goto return0;
2064 }
2065 if ((neg == 0) && (*cur == '+'))
2066 cur++;
2067 if ((cur[0] == 0) || (cur[0] == '+') || (cur[0] == '-'))
2068 goto return1;
2069 while ((*cur >= '0') && (*cur <= '9')) {
2070 cur++;
2071 }
2072 if (*cur == '.') {
2073 cur++;
2074 while ((*cur >= '0') && (*cur <= '9'))
2075 cur++;
2076 }
2077 if ((*cur == 'e') || (*cur == 'E')) {
2078 cur++;
2079 if ((*cur == '-') || (*cur == '+'))
2080 cur++;
2081 while ((*cur >= '0') && (*cur <= '9'))
2082 cur++;
2083 }
2084 if (*cur != 0)
2085 goto return1;
2086 if (val != NULL) {
2087 if (type == xmlSchemaTypeFloatDef) {
2088 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
2089 if (v != NULL) {
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00002090 /*
2091 * TODO: sscanf seems not to give the correct
2092 * value for extremely high/low values.
2093 * E.g. "1E-149" results in zero.
2094 */
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002095 if (sscanf((const char *) value, "%f",
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002096 &(v->value.f)) == 1) {
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00002097 *val = v;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002098 } else {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002099 xmlSchemaFreeValue(v);
2100 goto return1;
2101 }
2102 } else {
2103 goto error;
2104 }
2105 } else {
2106 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
2107 if (v != NULL) {
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00002108 /*
2109 * TODO: sscanf seems not to give the correct
2110 * value for extremely high/low values.
2111 */
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002112 if (sscanf((const char *) value, "%lf",
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002113 &(v->value.d)) == 1) {
2114 *val = v;
2115 } else {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002116 xmlSchemaFreeValue(v);
2117 goto return1;
2118 }
2119 } else {
2120 goto error;
2121 }
2122 }
2123 }
2124 goto return0;
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00002125 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002126 case XML_SCHEMAS_BOOLEAN:{
2127 const xmlChar *cur = value;
2128
2129 if ((cur[0] == '0') && (cur[1] == 0))
2130 ret = 0;
2131 else if ((cur[0] == '1') && (cur[1] == 0))
2132 ret = 1;
2133 else if ((cur[0] == 't') && (cur[1] == 'r')
2134 && (cur[2] == 'u') && (cur[3] == 'e')
2135 && (cur[4] == 0))
2136 ret = 1;
2137 else if ((cur[0] == 'f') && (cur[1] == 'a')
2138 && (cur[2] == 'l') && (cur[3] == 's')
2139 && (cur[4] == 'e') && (cur[5] == 0))
2140 ret = 0;
2141 else
2142 goto return1;
2143 if (val != NULL) {
2144 v = xmlSchemaNewValue(XML_SCHEMAS_BOOLEAN);
2145 if (v != NULL) {
2146 v->value.b = ret;
2147 *val = v;
2148 } else {
2149 goto error;
2150 }
2151 }
2152 goto return0;
2153 }
2154 case XML_SCHEMAS_TOKEN:{
2155 const xmlChar *cur = value;
2156
William M. Brack76e95df2003-10-18 16:20:14 +00002157 if (IS_BLANK_CH(*cur))
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002158 goto return1;
2159
2160 while (*cur != 0) {
2161 if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) {
2162 goto return1;
2163 } else if (*cur == ' ') {
2164 cur++;
2165 if (*cur == 0)
2166 goto return1;
2167 if (*cur == ' ')
2168 goto return1;
2169 } else {
2170 cur++;
2171 }
2172 }
2173 if (val != NULL) {
2174 v = xmlSchemaNewValue(XML_SCHEMAS_TOKEN);
2175 if (v != NULL) {
2176 v->value.str = xmlStrdup(value);
2177 *val = v;
2178 } else {
2179 goto error;
2180 }
2181 }
2182 goto return0;
2183 }
2184 case XML_SCHEMAS_LANGUAGE:
2185 if (xmlCheckLanguageID(value) == 1) {
2186 if (val != NULL) {
2187 v = xmlSchemaNewValue(XML_SCHEMAS_LANGUAGE);
2188 if (v != NULL) {
2189 v->value.str = xmlStrdup(value);
2190 *val = v;
2191 } else {
2192 goto error;
2193 }
2194 }
2195 goto return0;
2196 }
2197 goto return1;
2198 case XML_SCHEMAS_NMTOKEN:
2199 if (xmlValidateNMToken(value, 1) == 0) {
2200 if (val != NULL) {
2201 v = xmlSchemaNewValue(XML_SCHEMAS_NMTOKEN);
2202 if (v != NULL) {
2203 v->value.str = xmlStrdup(value);
2204 *val = v;
2205 } else {
2206 goto error;
2207 }
2208 }
2209 goto return0;
2210 }
2211 goto return1;
2212 case XML_SCHEMAS_NMTOKENS:
2213 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeNmtokenDef,
2214 value, val, node);
2215 if (ret > 0)
2216 ret = 0;
2217 else
2218 ret = 1;
2219 goto done;
2220 case XML_SCHEMAS_NAME:
2221 ret = xmlValidateName(value, 1);
Daniel Veillarddf292f72005-01-16 19:00:15 +00002222 if ((ret == 0) && (val != NULL) && (value != NULL)) {
2223 v = xmlSchemaNewValue(XML_SCHEMAS_NAME);
2224 if (v != NULL) {
2225 const xmlChar *start = value, *end;
2226 while (IS_BLANK_CH(*start)) start++;
2227 end = start;
2228 while ((*end != 0) && (!IS_BLANK_CH(*end))) end++;
2229 v->value.str = xmlStrndup(start, end - start);
2230 *val = v;
2231 } else {
2232 goto error;
2233 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002234 }
2235 goto done;
2236 case XML_SCHEMAS_QNAME:{
2237 xmlChar *uri = NULL;
2238 xmlChar *local = NULL;
2239
2240 ret = xmlValidateQName(value, 1);
2241 if ((ret == 0) && (node != NULL)) {
2242 xmlChar *prefix;
2243
2244 local = xmlSplitQName2(value, &prefix);
2245 if (prefix != NULL) {
2246 xmlNsPtr ns;
2247
2248 ns = xmlSearchNs(node->doc, node, prefix);
2249 if (ns == NULL)
2250 ret = 1;
2251 else if (val != NULL)
2252 uri = xmlStrdup(ns->href);
2253 }
2254 if ((local != NULL) && ((val == NULL) || (ret != 0)))
2255 xmlFree(local);
2256 if (prefix != NULL)
2257 xmlFree(prefix);
2258 }
2259 if ((ret == 0) && (val != NULL)) {
2260 v = xmlSchemaNewValue(XML_SCHEMAS_QNAME);
2261 if (v != NULL) {
2262 if (local != NULL)
2263 v->value.qname.name = local;
2264 else
2265 v->value.qname.name = xmlStrdup(value);
2266 if (uri != NULL)
2267 v->value.qname.uri = uri;
2268
2269 *val = v;
2270 } else {
2271 if (local != NULL)
2272 xmlFree(local);
2273 if (uri != NULL)
2274 xmlFree(uri);
2275 goto error;
2276 }
2277 }
2278 goto done;
2279 }
2280 case XML_SCHEMAS_NCNAME:
2281 ret = xmlValidateNCName(value, 1);
2282 if ((ret == 0) && (val != NULL)) {
2283 v = xmlSchemaNewValue(XML_SCHEMAS_NCNAME);
2284 if (v != NULL) {
2285 v->value.str = xmlStrdup(value);
2286 *val = v;
2287 } else {
2288 goto error;
2289 }
2290 }
2291 goto done;
2292 case XML_SCHEMAS_ID:
2293 ret = xmlValidateNCName(value, 1);
2294 if ((ret == 0) && (val != NULL)) {
2295 v = xmlSchemaNewValue(XML_SCHEMAS_ID);
2296 if (v != NULL) {
2297 v->value.str = xmlStrdup(value);
2298 *val = v;
2299 } else {
2300 goto error;
2301 }
2302 }
2303 if ((ret == 0) && (node != NULL) &&
2304 (node->type == XML_ATTRIBUTE_NODE)) {
2305 xmlAttrPtr attr = (xmlAttrPtr) node;
2306
2307 /*
2308 * NOTE: the IDness might have already be declared in the DTD
2309 */
2310 if (attr->atype != XML_ATTRIBUTE_ID) {
2311 xmlIDPtr res;
2312 xmlChar *strip;
2313
2314 strip = xmlSchemaStrip(value);
2315 if (strip != NULL) {
2316 res = xmlAddID(NULL, node->doc, strip, attr);
2317 xmlFree(strip);
2318 } else
2319 res = xmlAddID(NULL, node->doc, value, attr);
2320 if (res == NULL) {
2321 ret = 2;
2322 } else {
2323 attr->atype = XML_ATTRIBUTE_ID;
2324 }
2325 }
2326 }
2327 goto done;
2328 case XML_SCHEMAS_IDREF:
2329 ret = xmlValidateNCName(value, 1);
2330 if ((ret == 0) && (val != NULL)) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00002331 v = xmlSchemaNewValue(XML_SCHEMAS_IDREF);
2332 if (v == NULL)
2333 goto error;
2334 v->value.str = xmlStrdup(value);
2335 *val = v;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002336 }
2337 if ((ret == 0) && (node != NULL) &&
2338 (node->type == XML_ATTRIBUTE_NODE)) {
2339 xmlAttrPtr attr = (xmlAttrPtr) node;
2340 xmlChar *strip;
2341
2342 strip = xmlSchemaStrip(value);
2343 if (strip != NULL) {
2344 xmlAddRef(NULL, node->doc, strip, attr);
2345 xmlFree(strip);
2346 } else
2347 xmlAddRef(NULL, node->doc, value, attr);
2348 attr->atype = XML_ATTRIBUTE_IDREF;
2349 }
2350 goto done;
2351 case XML_SCHEMAS_IDREFS:
2352 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeIdrefDef,
2353 value, val, node);
2354 if (ret < 0)
2355 ret = 2;
2356 else
2357 ret = 0;
2358 if ((ret == 0) && (node != NULL) &&
2359 (node->type == XML_ATTRIBUTE_NODE)) {
2360 xmlAttrPtr attr = (xmlAttrPtr) node;
2361
2362 attr->atype = XML_ATTRIBUTE_IDREFS;
2363 }
2364 goto done;
2365 case XML_SCHEMAS_ENTITY:{
2366 xmlChar *strip;
2367
2368 ret = xmlValidateNCName(value, 1);
2369 if ((node == NULL) || (node->doc == NULL))
2370 ret = 3;
2371 if (ret == 0) {
2372 xmlEntityPtr ent;
2373
2374 strip = xmlSchemaStrip(value);
2375 if (strip != NULL) {
2376 ent = xmlGetDocEntity(node->doc, strip);
2377 xmlFree(strip);
2378 } else {
2379 ent = xmlGetDocEntity(node->doc, value);
2380 }
2381 if ((ent == NULL) ||
2382 (ent->etype !=
2383 XML_EXTERNAL_GENERAL_UNPARSED_ENTITY))
2384 ret = 4;
2385 }
2386 if ((ret == 0) && (val != NULL)) {
2387 TODO;
2388 }
2389 if ((ret == 0) && (node != NULL) &&
2390 (node->type == XML_ATTRIBUTE_NODE)) {
2391 xmlAttrPtr attr = (xmlAttrPtr) node;
2392
2393 attr->atype = XML_ATTRIBUTE_ENTITY;
2394 }
2395 goto done;
2396 }
2397 case XML_SCHEMAS_ENTITIES:
2398 if ((node == NULL) || (node->doc == NULL))
2399 goto return3;
2400 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeEntityDef,
2401 value, val, node);
2402 if (ret <= 0)
2403 ret = 1;
2404 else
2405 ret = 0;
2406 if ((ret == 0) && (node != NULL) &&
2407 (node->type == XML_ATTRIBUTE_NODE)) {
2408 xmlAttrPtr attr = (xmlAttrPtr) node;
2409
2410 attr->atype = XML_ATTRIBUTE_ENTITIES;
2411 }
2412 goto done;
2413 case XML_SCHEMAS_NOTATION:{
2414 xmlChar *uri = NULL;
2415 xmlChar *local = NULL;
2416
2417 ret = xmlValidateQName(value, 1);
2418 if ((ret == 0) && (node != NULL)) {
2419 xmlChar *prefix;
2420
2421 local = xmlSplitQName2(value, &prefix);
2422 if (prefix != NULL) {
2423 xmlNsPtr ns;
2424
2425 ns = xmlSearchNs(node->doc, node, prefix);
2426 if (ns == NULL)
2427 ret = 1;
2428 else if (val != NULL)
2429 uri = xmlStrdup(ns->href);
2430 }
2431 if ((local != NULL) && ((val == NULL) || (ret != 0)))
2432 xmlFree(local);
2433 if (prefix != NULL)
2434 xmlFree(prefix);
2435 }
2436 if ((node == NULL) || (node->doc == NULL))
2437 ret = 3;
2438 if (ret == 0) {
2439 ret = xmlValidateNotationUse(NULL, node->doc, value);
2440 if (ret == 1)
2441 ret = 0;
2442 else
2443 ret = 1;
2444 }
2445 if ((ret == 0) && (val != NULL)) {
2446 v = xmlSchemaNewValue(XML_SCHEMAS_NOTATION);
2447 if (v != NULL) {
2448 if (local != NULL)
2449 v->value.qname.name = local;
2450 else
2451 v->value.qname.name = xmlStrdup(value);
2452 if (uri != NULL)
2453 v->value.qname.uri = uri;
2454
2455 *val = v;
2456 } else {
2457 if (local != NULL)
2458 xmlFree(local);
2459 if (uri != NULL)
2460 xmlFree(uri);
2461 goto error;
2462 }
2463 }
2464 goto done;
2465 }
2466 case XML_SCHEMAS_ANYURI:{
Daniel Veillard11c466a2004-03-14 12:20:15 +00002467 if (*value != 0) {
2468 xmlURIPtr uri = xmlParseURI((const char *) value);
2469 if (uri == NULL)
2470 goto return1;
2471 xmlFreeURI(uri);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002472 }
Daniel Veillard11c466a2004-03-14 12:20:15 +00002473
2474 if (val != NULL) {
2475 v = xmlSchemaNewValue(XML_SCHEMAS_ANYURI);
2476 if (v == NULL)
2477 goto error;
2478 v->value.str = xmlStrdup(value);
2479 *val = v;
2480 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002481 goto return0;
2482 }
2483 case XML_SCHEMAS_HEXBINARY:{
2484 const xmlChar *cur = value;
2485 xmlChar *base;
2486 int total, i = 0;
2487
Daniel Veillardf34a20e2004-08-31 08:42:17 +00002488 if (cur == NULL)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002489 goto return1;
2490
2491 while (((*cur >= '0') && (*cur <= '9')) ||
2492 ((*cur >= 'A') && (*cur <= 'F')) ||
2493 ((*cur >= 'a') && (*cur <= 'f'))) {
2494 i++;
2495 cur++;
2496 }
2497
2498 if (*cur != 0)
2499 goto return1;
2500 if ((i % 2) != 0)
2501 goto return1;
2502
2503 if (val != NULL) {
2504
2505 v = xmlSchemaNewValue(XML_SCHEMAS_HEXBINARY);
2506 if (v == NULL)
2507 goto error;
2508
2509 cur = xmlStrdup(value);
2510 if (cur == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002511 xmlSchemaTypeErrMemory(node, "allocating hexbin data");
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002512 xmlFree(v);
2513 goto return1;
2514 }
2515
2516 total = i / 2; /* number of octets */
2517
2518 base = (xmlChar *) cur;
2519 while (i-- > 0) {
2520 if (*base >= 'a')
2521 *base = *base - ('a' - 'A');
2522 base++;
2523 }
2524
2525 v->value.hex.str = (xmlChar *) cur;
2526 v->value.hex.total = total;
2527 *val = v;
2528 }
2529 goto return0;
2530 }
2531 case XML_SCHEMAS_BASE64BINARY:{
2532 /* ISSUE:
2533 *
2534 * Ignore all stray characters? (yes, currently)
2535 * Worry about long lines? (no, currently)
2536 *
2537 * rfc2045.txt:
2538 *
2539 * "The encoded output stream must be represented in lines of
2540 * no more than 76 characters each. All line breaks or other
2541 * characters not found in Table 1 must be ignored by decoding
2542 * software. In base64 data, characters other than those in
2543 * Table 1, line breaks, and other white space probably
2544 * indicate a transmission error, about which a warning
2545 * message or even a message rejection might be appropriate
2546 * under some circumstances." */
2547 const xmlChar *cur = value;
2548 xmlChar *base;
2549 int total, i = 0, pad = 0;
2550
2551 if (cur == NULL)
2552 goto return1;
2553
2554 for (; *cur; ++cur) {
2555 int decc;
2556
2557 decc = _xmlSchemaBase64Decode(*cur);
2558 if (decc < 0) ;
2559 else if (decc < 64)
2560 i++;
2561 else
2562 break;
2563 }
2564 for (; *cur; ++cur) {
2565 int decc;
2566
2567 decc = _xmlSchemaBase64Decode(*cur);
2568 if (decc < 0) ;
2569 else if (decc < 64)
2570 goto return1;
2571 if (decc == 64)
2572 pad++;
2573 }
2574
2575 /* rfc2045.txt: "Special processing is performed if fewer than
2576 * 24 bits are available at the end of the data being encoded.
2577 * A full encoding quantum is always completed at the end of a
2578 * body. When fewer than 24 input bits are available in an
2579 * input group, zero bits are added (on the right) to form an
2580 * integral number of 6-bit groups. Padding at the end of the
2581 * data is performed using the "=" character. Since all
2582 * base64 input is an integral number of octets, only the
2583 * following cases can arise: (1) the final quantum of
2584 * encoding input is an integral multiple of 24 bits; here,
2585 * the final unit of encoded output will be an integral
2586 * multiple ofindent: Standard input:701: Warning:old style
2587 * assignment ambiguity in "=*". Assuming "= *" 4 characters
2588 * with no "=" padding, (2) the final
2589 * quantum of encoding input is exactly 8 bits; here, the
2590 * final unit of encoded output will be two characters
2591 * followed by two "=" padding characters, or (3) the final
2592 * quantum of encoding input is exactly 16 bits; here, the
2593 * final unit of encoded output will be three characters
2594 * followed by one "=" padding character." */
2595
2596 total = 3 * (i / 4);
2597 if (pad == 0) {
2598 if (i % 4 != 0)
2599 goto return1;
2600 } else if (pad == 1) {
2601 int decc;
2602
2603 if (i % 4 != 3)
2604 goto return1;
2605 for (decc = _xmlSchemaBase64Decode(*cur);
2606 (decc < 0) || (decc > 63);
2607 decc = _xmlSchemaBase64Decode(*cur))
2608 --cur;
2609 /* 16bits in 24bits means 2 pad bits: nnnnnn nnmmmm mmmm00*/
2610 /* 00111100 -> 0x3c */
2611 if (decc & ~0x3c)
2612 goto return1;
2613 total += 2;
2614 } else if (pad == 2) {
2615 int decc;
2616
2617 if (i % 4 != 2)
2618 goto return1;
2619 for (decc = _xmlSchemaBase64Decode(*cur);
2620 (decc < 0) || (decc > 63);
2621 decc = _xmlSchemaBase64Decode(*cur))
2622 --cur;
2623 /* 8bits in 12bits means 4 pad bits: nnnnnn nn0000 */
2624 /* 00110000 -> 0x30 */
2625 if (decc & ~0x30)
2626 goto return1;
2627 total += 1;
2628 } else
2629 goto return1;
2630
2631 if (val != NULL) {
2632 v = xmlSchemaNewValue(XML_SCHEMAS_BASE64BINARY);
2633 if (v == NULL)
2634 goto error;
2635 base =
2636 (xmlChar *) xmlMallocAtomic((i + pad + 1) *
2637 sizeof(xmlChar));
2638 if (base == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002639 xmlSchemaTypeErrMemory(node, "allocating base64 data");
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002640 xmlFree(v);
2641 goto return1;
2642 }
2643 v->value.base64.str = base;
2644 for (cur = value; *cur; ++cur)
2645 if (_xmlSchemaBase64Decode(*cur) >= 0) {
2646 *base = *cur;
2647 ++base;
2648 }
2649 *base = 0;
2650 v->value.base64.total = total;
2651 *val = v;
2652 }
2653 goto return0;
2654 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002655 case XML_SCHEMAS_INTEGER:
2656 case XML_SCHEMAS_PINTEGER:
2657 case XML_SCHEMAS_NPINTEGER:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002658 case XML_SCHEMAS_NINTEGER:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002659 case XML_SCHEMAS_NNINTEGER:{
2660 const xmlChar *cur = value;
2661 unsigned long lo, mi, hi;
William M. Brackec3b4b72005-03-15 15:50:17 +00002662 int sign = 0;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002663
2664 if (cur == NULL)
2665 goto return1;
2666 if (*cur == '-') {
2667 sign = 1;
2668 cur++;
2669 } else if (*cur == '+')
2670 cur++;
William M. Brackec3b4b72005-03-15 15:50:17 +00002671 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2672 if (ret == -1)
2673 goto return1;
2674 if (*cur != 0)
2675 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002676 if (type->builtInType == XML_SCHEMAS_NPINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002677 if ((sign == 0) &&
2678 ((hi != 0) || (mi != 0) || (lo != 0)))
2679 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002680 } else if (type->builtInType == XML_SCHEMAS_PINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002681 if (sign == 1)
2682 goto return1;
2683 if ((hi == 0) && (mi == 0) && (lo == 0))
2684 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002685 } else if (type->builtInType == XML_SCHEMAS_NINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002686 if (sign == 0)
2687 goto return1;
2688 if ((hi == 0) && (mi == 0) && (lo == 0))
2689 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002690 } else if (type->builtInType == XML_SCHEMAS_NNINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002691 if ((sign == 1) &&
2692 ((hi != 0) || (mi != 0) || (lo != 0)))
2693 goto return1;
2694 }
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00002695 if (val != NULL) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00002696 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002697 if (v != NULL) {
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00002698 if (ret == 0)
2699 ret++;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002700 v->value.decimal.lo = lo;
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00002701 v->value.decimal.mi = mi;
2702 v->value.decimal.hi = hi;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002703 v->value.decimal.sign = sign;
2704 v->value.decimal.frac = 0;
William M. Brackec3b4b72005-03-15 15:50:17 +00002705 v->value.decimal.total = ret;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002706 *val = v;
2707 }
2708 }
2709 goto return0;
2710 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002711 case XML_SCHEMAS_LONG:
2712 case XML_SCHEMAS_BYTE:
2713 case XML_SCHEMAS_SHORT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002714 case XML_SCHEMAS_INT:{
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00002715 const xmlChar *cur = value;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002716 unsigned long lo, mi, hi;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002717 int sign = 0;
2718
2719 if (cur == NULL)
2720 goto return1;
2721 if (*cur == '-') {
2722 sign = 1;
2723 cur++;
2724 } else if (*cur == '+')
2725 cur++;
William M. Brackec3b4b72005-03-15 15:50:17 +00002726 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2727 if (ret < 0)
2728 goto return1;
2729 if (*cur != 0)
2730 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002731 if (type->builtInType == XML_SCHEMAS_LONG) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002732 if (hi >= 922) {
2733 if (hi > 922)
2734 goto return1;
2735 if (mi >= 33720368) {
2736 if (mi > 33720368)
2737 goto return1;
2738 if ((sign == 0) && (lo > 54775807))
2739 goto return1;
2740 if ((sign == 1) && (lo > 54775808))
2741 goto return1;
2742 }
2743 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002744 } else if (type->builtInType == XML_SCHEMAS_INT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002745 if (hi != 0)
2746 goto return1;
2747 if (mi >= 21) {
2748 if (mi > 21)
2749 goto return1;
2750 if ((sign == 0) && (lo > 47483647))
2751 goto return1;
2752 if ((sign == 1) && (lo > 47483648))
2753 goto return1;
2754 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002755 } else if (type->builtInType == XML_SCHEMAS_SHORT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002756 if ((mi != 0) || (hi != 0))
2757 goto return1;
2758 if ((sign == 1) && (lo > 32768))
2759 goto return1;
2760 if ((sign == 0) && (lo > 32767))
2761 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002762 } else if (type->builtInType == XML_SCHEMAS_BYTE) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002763 if ((mi != 0) || (hi != 0))
2764 goto return1;
2765 if ((sign == 1) && (lo > 128))
2766 goto return1;
2767 if ((sign == 0) && (lo > 127))
2768 goto return1;
2769 }
2770 if (val != NULL) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00002771 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002772 if (v != NULL) {
2773 v->value.decimal.lo = lo;
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00002774 v->value.decimal.mi = mi;
2775 v->value.decimal.hi = hi;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002776 v->value.decimal.sign = sign;
2777 v->value.decimal.frac = 0;
William M. Brackec3b4b72005-03-15 15:50:17 +00002778 v->value.decimal.total = ret;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002779 *val = v;
2780 }
2781 }
2782 goto return0;
2783 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002784 case XML_SCHEMAS_UINT:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002785 case XML_SCHEMAS_ULONG:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002786 case XML_SCHEMAS_USHORT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002787 case XML_SCHEMAS_UBYTE:{
2788 const xmlChar *cur = value;
2789 unsigned long lo, mi, hi;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002790
2791 if (cur == NULL)
2792 goto return1;
William M. Brackec3b4b72005-03-15 15:50:17 +00002793 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2794 if (ret < 0)
2795 goto return1;
2796 if (*cur != 0)
2797 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002798 if (type->builtInType == XML_SCHEMAS_ULONG) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002799 if (hi >= 1844) {
2800 if (hi > 1844)
2801 goto return1;
2802 if (mi >= 67440737) {
2803 if (mi > 67440737)
2804 goto return1;
2805 if (lo > 9551615)
2806 goto return1;
2807 }
2808 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002809 } else if (type->builtInType == XML_SCHEMAS_UINT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002810 if (hi != 0)
2811 goto return1;
2812 if (mi >= 42) {
2813 if (mi > 42)
2814 goto return1;
2815 if (lo > 94967295)
2816 goto return1;
2817 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002818 } else if (type->builtInType == XML_SCHEMAS_USHORT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002819 if ((mi != 0) || (hi != 0))
2820 goto return1;
2821 if (lo > 65535)
2822 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002823 } else if (type->builtInType == XML_SCHEMAS_UBYTE) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002824 if ((mi != 0) || (hi != 0))
2825 goto return1;
2826 if (lo > 255)
2827 goto return1;
2828 }
2829 if (val != NULL) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00002830 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002831 if (v != NULL) {
2832 v->value.decimal.lo = lo;
2833 v->value.decimal.mi = mi;
2834 v->value.decimal.hi = hi;
2835 v->value.decimal.sign = 0;
2836 v->value.decimal.frac = 0;
William M. Brackec3b4b72005-03-15 15:50:17 +00002837 v->value.decimal.total = ret;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002838 *val = v;
2839 }
2840 }
2841 goto return0;
2842 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002843 }
2844
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002845 done:
2846 if (norm != NULL)
2847 xmlFree(norm);
2848 return (ret);
2849 return3:
2850 if (norm != NULL)
2851 xmlFree(norm);
2852 return (3);
2853 return1:
2854 if (norm != NULL)
2855 xmlFree(norm);
2856 return (1);
2857 return0:
2858 if (norm != NULL)
2859 xmlFree(norm);
2860 return (0);
2861 error:
2862 if (norm != NULL)
2863 xmlFree(norm);
2864 return (-1);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002865}
2866
2867/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002868 * xmlSchemaValPredefTypeNode:
Daniel Veillard4255d502002-04-16 15:50:10 +00002869 * @type: the predefined type
2870 * @value: the value to check
2871 * @val: the return computed value
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002872 * @node: the node containing the value
Daniel Veillard4255d502002-04-16 15:50:10 +00002873 *
2874 * Check that a value conforms to the lexical space of the predefined type.
2875 * if true a value is computed and returned in @val.
2876 *
2877 * Returns 0 if this validates, a positive error code number otherwise
2878 * and -1 in case of internal or API error.
2879 */
2880int
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002881xmlSchemaValPredefTypeNode(xmlSchemaTypePtr type, const xmlChar *value,
2882 xmlSchemaValPtr *val, xmlNodePtr node) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002883 return(xmlSchemaValAtomicType(type, value, val, node, 0));
Daniel Veillard4255d502002-04-16 15:50:10 +00002884}
2885
2886/**
Daniel Veillardc0826a72004-08-10 14:17:33 +00002887 * xmlSchemaValPredefTypeNodeNoNorm:
2888 * @type: the predefined type
2889 * @value: the value to check
2890 * @val: the return computed value
2891 * @node: the node containing the value
2892 *
2893 * Check that a value conforms to the lexical space of the predefined type.
2894 * if true a value is computed and returned in @val.
2895 * This one does apply any normalization to the value.
2896 *
2897 * Returns 0 if this validates, a positive error code number otherwise
2898 * and -1 in case of internal or API error.
2899 */
2900int
2901xmlSchemaValPredefTypeNodeNoNorm(xmlSchemaTypePtr type, const xmlChar *value,
2902 xmlSchemaValPtr *val, xmlNodePtr node) {
2903 return(xmlSchemaValAtomicType(type, value, val, node, 1));
2904}
2905
2906/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002907 * xmlSchemaValidatePredefinedType:
2908 * @type: the predefined type
2909 * @value: the value to check
2910 * @val: the return computed value
2911 *
2912 * Check that a value conforms to the lexical space of the predefined type.
2913 * if true a value is computed and returned in @val.
2914 *
2915 * Returns 0 if this validates, a positive error code number otherwise
2916 * and -1 in case of internal or API error.
2917 */
2918int
2919xmlSchemaValidatePredefinedType(xmlSchemaTypePtr type, const xmlChar *value,
2920 xmlSchemaValPtr *val) {
2921 return(xmlSchemaValPredefTypeNode(type, value, val, NULL));
2922}
2923
2924/**
Daniel Veillard4255d502002-04-16 15:50:10 +00002925 * xmlSchemaCompareDecimals:
2926 * @x: a first decimal value
2927 * @y: a second decimal value
2928 *
2929 * Compare 2 decimals
2930 *
2931 * Returns -1 if x < y, 0 if x == y, 1 if x > y and -2 in case of error
2932 */
2933static int
2934xmlSchemaCompareDecimals(xmlSchemaValPtr x, xmlSchemaValPtr y)
2935{
2936 xmlSchemaValPtr swp;
William M. Brack273670f2005-03-11 15:55:14 +00002937 int order = 1, integx, integy, dlen;
2938 unsigned long hi, mi, lo;
Daniel Veillard4255d502002-04-16 15:50:10 +00002939
William M. Brack273670f2005-03-11 15:55:14 +00002940 /*
2941 * First test: If x is -ve and not zero
2942 */
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002943 if ((x->value.decimal.sign) &&
2944 ((x->value.decimal.lo != 0) ||
2945 (x->value.decimal.mi != 0) ||
2946 (x->value.decimal.hi != 0))) {
William M. Brack273670f2005-03-11 15:55:14 +00002947 /*
2948 * Then if y is -ve and not zero reverse the compare
2949 */
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002950 if ((y->value.decimal.sign) &&
2951 ((y->value.decimal.lo != 0) ||
2952 (y->value.decimal.mi != 0) ||
2953 (y->value.decimal.hi != 0)))
Daniel Veillard80b19092003-03-28 13:29:53 +00002954 order = -1;
William M. Brack273670f2005-03-11 15:55:14 +00002955 /*
2956 * Otherwise (y >= 0) we have the answer
2957 */
Daniel Veillard80b19092003-03-28 13:29:53 +00002958 else
2959 return (-1);
William M. Brack273670f2005-03-11 15:55:14 +00002960 /*
2961 * If x is not -ve and y is -ve we have the answer
2962 */
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002963 } else if ((y->value.decimal.sign) &&
2964 ((y->value.decimal.lo != 0) ||
2965 (y->value.decimal.mi != 0) ||
2966 (y->value.decimal.hi != 0))) {
Daniel Veillard4255d502002-04-16 15:50:10 +00002967 return (1);
Daniel Veillard80b19092003-03-28 13:29:53 +00002968 }
William M. Brack273670f2005-03-11 15:55:14 +00002969 /*
2970 * If it's not simply determined by a difference in sign,
2971 * then we need to compare the actual values of the two nums.
2972 * To do this, we start by looking at the integral parts.
2973 * If the number of integral digits differ, then we have our
2974 * answer.
2975 */
2976 integx = x->value.decimal.total - x->value.decimal.frac;
2977 integy = y->value.decimal.total - y->value.decimal.frac;
2978 if (integx > integy)
2979 return order;
2980 else if (integy > integx)
2981 return -order;
2982 /*
2983 * If the number of integral digits is the same for both numbers,
2984 * then things get a little more complicated. We need to "normalize"
2985 * the numbers in order to properly compare them. To do this, we
2986 * look at the total length of each number (length => number of
2987 * significant digits), and divide the "shorter" by 10 (decreasing
2988 * the length) until they are of equal length.
2989 */
2990 dlen = x->value.decimal.total - y->value.decimal.total;
2991 if (dlen < 0) { /* y has more digits than x */
2992 swp = x;
2993 hi = y->value.decimal.hi;
2994 mi = y->value.decimal.mi;
2995 lo = y->value.decimal.lo;
2996 dlen = -dlen;
2997 order = -order;
2998 } else { /* x has more digits than y */
2999 swp = y;
3000 hi = x->value.decimal.hi;
3001 mi = x->value.decimal.mi;
3002 lo = x->value.decimal.lo;
Daniel Veillard4255d502002-04-16 15:50:10 +00003003 }
William M. Brack273670f2005-03-11 15:55:14 +00003004 while (dlen > 8) { /* in effect, right shift by 10**8 */
3005 lo = mi;
3006 mi = hi;
3007 hi = 0;
3008 dlen -= 8;
Daniel Veillard4255d502002-04-16 15:50:10 +00003009 }
William M. Brack273670f2005-03-11 15:55:14 +00003010 while (dlen > 0) {
3011 unsigned long rem1, rem2;
3012 rem1 = (hi % 10) * 100000000L;
3013 hi = hi / 10;
3014 rem2 = (mi % 10) * 100000000L;
3015 mi = (mi + rem1) / 10;
3016 lo = (lo + rem2) / 10;
3017 dlen--;
3018 }
3019 if (hi > swp->value.decimal.hi) {
3020 return order;
3021 } else if (hi == swp->value.decimal.hi) {
3022 if (mi > swp->value.decimal.mi) {
3023 return order;
3024 } else if (mi == swp->value.decimal.mi) {
3025 if (lo > swp->value.decimal.lo) {
3026 return order;
3027 } else if (lo == swp->value.decimal.lo) {
3028 if (x->value.decimal.total == y->value.decimal.total) {
3029 return 0;
3030 } else {
3031 return order;
3032 }
3033 }
3034 }
3035 }
3036 return -order;
Daniel Veillard4255d502002-04-16 15:50:10 +00003037}
3038
3039/**
Daniel Veillard070803b2002-05-03 07:29:38 +00003040 * xmlSchemaCompareDurations:
3041 * @x: a first duration value
3042 * @y: a second duration value
3043 *
3044 * Compare 2 durations
3045 *
3046 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3047 * case of error
3048 */
3049static int
3050xmlSchemaCompareDurations(xmlSchemaValPtr x, xmlSchemaValPtr y)
3051{
3052 long carry, mon, day;
3053 double sec;
Daniel Veillard80b19092003-03-28 13:29:53 +00003054 int invert = 1;
3055 long xmon, xday, myear, minday, maxday;
Daniel Veillard070803b2002-05-03 07:29:38 +00003056 static const long dayRange [2][12] = {
3057 { 0, 28, 59, 89, 120, 150, 181, 212, 242, 273, 303, 334, },
3058 { 0, 31, 62, 92, 123, 153, 184, 215, 245, 276, 306, 337} };
3059
3060 if ((x == NULL) || (y == NULL))
Daniel Veillard5a872412002-05-22 06:40:27 +00003061 return -2;
Daniel Veillard070803b2002-05-03 07:29:38 +00003062
3063 /* months */
3064 mon = x->value.dur.mon - y->value.dur.mon;
3065
3066 /* seconds */
3067 sec = x->value.dur.sec - y->value.dur.sec;
3068 carry = (long)sec / SECS_PER_DAY;
3069 sec -= (double)(carry * SECS_PER_DAY);
3070
3071 /* days */
3072 day = x->value.dur.day - y->value.dur.day + carry;
3073
3074 /* easy test */
3075 if (mon == 0) {
3076 if (day == 0)
3077 if (sec == 0.0)
3078 return 0;
3079 else if (sec < 0.0)
3080 return -1;
3081 else
3082 return 1;
3083 else if (day < 0)
3084 return -1;
3085 else
3086 return 1;
3087 }
3088
3089 if (mon > 0) {
3090 if ((day >= 0) && (sec >= 0.0))
3091 return 1;
3092 else {
3093 xmon = mon;
3094 xday = -day;
3095 }
3096 } else if ((day <= 0) && (sec <= 0.0)) {
3097 return -1;
3098 } else {
Daniel Veillard80b19092003-03-28 13:29:53 +00003099 invert = -1;
Daniel Veillard070803b2002-05-03 07:29:38 +00003100 xmon = -mon;
3101 xday = day;
3102 }
3103
3104 myear = xmon / 12;
Daniel Veillard80b19092003-03-28 13:29:53 +00003105 if (myear == 0) {
3106 minday = 0;
3107 maxday = 0;
3108 } else {
3109 maxday = 366 * ((myear + 3) / 4) +
3110 365 * ((myear - 1) % 4);
3111 minday = maxday - 1;
3112 }
3113
Daniel Veillard070803b2002-05-03 07:29:38 +00003114 xmon = xmon % 12;
3115 minday += dayRange[0][xmon];
3116 maxday += dayRange[1][xmon];
3117
Daniel Veillard80b19092003-03-28 13:29:53 +00003118 if ((maxday == minday) && (maxday == xday))
3119 return(0); /* can this really happen ? */
Daniel Veillard070803b2002-05-03 07:29:38 +00003120 if (maxday < xday)
Daniel Veillard80b19092003-03-28 13:29:53 +00003121 return(-invert);
3122 if (minday > xday)
3123 return(invert);
Daniel Veillard070803b2002-05-03 07:29:38 +00003124
3125 /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00003126 return 2;
3127}
3128
3129/*
3130 * macros for adding date/times and durations
3131 */
3132#define FQUOTIENT(a,b) (floor(((double)a/(double)b)))
3133#define MODULO(a,b) (a - FQUOTIENT(a,b) * b)
3134#define FQUOTIENT_RANGE(a,low,high) (FQUOTIENT((a-low),(high-low)))
3135#define MODULO_RANGE(a,low,high) ((MODULO((a-low),(high-low)))+low)
3136
3137/**
Daniel Veillard669adfc2004-05-29 20:12:46 +00003138 * xmlSchemaDupVal:
3139 * @v: the #xmlSchemaValPtr value to duplicate
3140 *
3141 * Makes a copy of @v. The calling program is responsible for freeing
3142 * the returned value.
3143 *
3144 * returns a pointer to a duplicated #xmlSchemaValPtr or NULL if error.
3145 */
3146static xmlSchemaValPtr
3147xmlSchemaDupVal (xmlSchemaValPtr v)
3148{
3149 xmlSchemaValPtr ret = xmlSchemaNewValue(v->type);
3150 if (ret == NULL)
3151 return NULL;
3152
3153 memcpy(ret, v, sizeof(xmlSchemaVal));
3154 return ret;
3155}
3156
3157/**
Kasimier T. Buchcik285ebab2005-03-04 18:04:59 +00003158 * xmlSchemaCopyValue:
3159 * @val: the precomputed value to be copied
3160 *
3161 * Copies the precomputed value. This duplicates any string within.
3162 *
3163 * Returns the copy or NULL if a copy for a data-type is not implemented.
3164 */
3165xmlSchemaValPtr
3166xmlSchemaCopyValue(xmlSchemaValPtr val)
3167{
3168 xmlSchemaValPtr ret;
3169
3170 if (val == NULL)
3171 return (NULL);
3172 /*
3173 * Copy the string values.
3174 */
3175 switch (val->type) {
3176 case XML_SCHEMAS_IDREFS:
3177 case XML_SCHEMAS_ENTITIES:
3178 case XML_SCHEMAS_NMTOKENS:
3179 case XML_SCHEMAS_ANYTYPE:
3180 case XML_SCHEMAS_ANYSIMPLETYPE:
3181 return (NULL);
3182 case XML_SCHEMAS_STRING:
3183 case XML_SCHEMAS_NORMSTRING:
3184 case XML_SCHEMAS_TOKEN:
3185 case XML_SCHEMAS_LANGUAGE:
3186 case XML_SCHEMAS_NAME:
3187 case XML_SCHEMAS_NCNAME:
3188 case XML_SCHEMAS_ID:
3189 case XML_SCHEMAS_IDREF:
3190 case XML_SCHEMAS_ENTITY:
3191 case XML_SCHEMAS_NMTOKEN:
Kasimier T. Buchcik2ee855d2005-03-07 11:14:14 +00003192 case XML_SCHEMAS_ANYURI:
Kasimier T. Buchcik285ebab2005-03-04 18:04:59 +00003193 ret = xmlSchemaDupVal(val);
3194 if (val->value.str != NULL)
3195 ret->value.str = xmlStrdup(BAD_CAST val->value.str);
3196 return (ret);
Kasimier T. Buchcik2ee855d2005-03-07 11:14:14 +00003197 case XML_SCHEMAS_QNAME:
Kasimier T. Buchcik285ebab2005-03-04 18:04:59 +00003198 case XML_SCHEMAS_NOTATION:
3199 ret = xmlSchemaDupVal(val);
3200 if (val->value.qname.name != NULL)
3201 ret->value.qname.name =
3202 xmlStrdup(BAD_CAST val->value.qname.name);
3203 if (val->value.qname.uri != NULL)
3204 ret->value.qname.uri =
3205 xmlStrdup(BAD_CAST val->value.qname.uri);
3206 return (ret);
3207 case XML_SCHEMAS_HEXBINARY:
3208 ret = xmlSchemaDupVal(val);
3209 if (val->value.hex.str != NULL)
3210 ret->value.hex.str = xmlStrdup(BAD_CAST val->value.hex.str);
3211 return (ret);
3212 case XML_SCHEMAS_BASE64BINARY:
3213 ret = xmlSchemaDupVal(val);
3214 if (val->value.base64.str != NULL)
3215 ret->value.base64.str =
3216 xmlStrdup(BAD_CAST val->value.base64.str);
3217 return (ret);
3218 default:
3219 return (xmlSchemaDupVal(val));
3220 }
3221 return (NULL);
3222}
3223
3224/**
Daniel Veillard5a872412002-05-22 06:40:27 +00003225 * _xmlSchemaDateAdd:
3226 * @dt: an #xmlSchemaValPtr
3227 * @dur: an #xmlSchemaValPtr of type #XS_DURATION
3228 *
3229 * Compute a new date/time from @dt and @dur. This function assumes @dt
3230 * is either #XML_SCHEMAS_DATETIME, #XML_SCHEMAS_DATE, #XML_SCHEMAS_GYEARMONTH,
Daniel Veillard669adfc2004-05-29 20:12:46 +00003231 * or #XML_SCHEMAS_GYEAR. The returned #xmlSchemaVal is the same type as
3232 * @dt. The calling program is responsible for freeing the returned value.
Daniel Veillard5a872412002-05-22 06:40:27 +00003233 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00003234 * Returns a pointer to a new #xmlSchemaVal or NULL if error.
Daniel Veillard5a872412002-05-22 06:40:27 +00003235 */
3236static xmlSchemaValPtr
3237_xmlSchemaDateAdd (xmlSchemaValPtr dt, xmlSchemaValPtr dur)
3238{
Daniel Veillard669adfc2004-05-29 20:12:46 +00003239 xmlSchemaValPtr ret, tmp;
Daniel Veillard5a872412002-05-22 06:40:27 +00003240 long carry, tempdays, temp;
3241 xmlSchemaValDatePtr r, d;
3242 xmlSchemaValDurationPtr u;
3243
3244 if ((dt == NULL) || (dur == NULL))
3245 return NULL;
3246
3247 ret = xmlSchemaNewValue(dt->type);
3248 if (ret == NULL)
3249 return NULL;
3250
Daniel Veillard669adfc2004-05-29 20:12:46 +00003251 /* make a copy so we don't alter the original value */
3252 tmp = xmlSchemaDupVal(dt);
3253 if (tmp == NULL) {
3254 xmlSchemaFreeValue(ret);
3255 return NULL;
3256 }
3257
Daniel Veillard5a872412002-05-22 06:40:27 +00003258 r = &(ret->value.date);
Daniel Veillard669adfc2004-05-29 20:12:46 +00003259 d = &(tmp->value.date);
Daniel Veillard5a872412002-05-22 06:40:27 +00003260 u = &(dur->value.dur);
3261
3262 /* normalization */
3263 if (d->mon == 0)
3264 d->mon = 1;
3265
3266 /* normalize for time zone offset */
3267 u->sec -= (d->tzo * 60);
3268 d->tzo = 0;
3269
3270 /* normalization */
3271 if (d->day == 0)
3272 d->day = 1;
3273
3274 /* month */
3275 carry = d->mon + u->mon;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003276 r->mon = (unsigned int) MODULO_RANGE(carry, 1, 13);
3277 carry = (long) FQUOTIENT_RANGE(carry, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00003278
3279 /* year (may be modified later) */
3280 r->year = d->year + carry;
3281 if (r->year == 0) {
3282 if (d->year > 0)
3283 r->year--;
3284 else
3285 r->year++;
3286 }
3287
3288 /* time zone */
3289 r->tzo = d->tzo;
3290 r->tz_flag = d->tz_flag;
3291
3292 /* seconds */
3293 r->sec = d->sec + u->sec;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003294 carry = (long) FQUOTIENT((long)r->sec, 60);
Daniel Veillard5a872412002-05-22 06:40:27 +00003295 if (r->sec != 0.0) {
3296 r->sec = MODULO(r->sec, 60.0);
3297 }
3298
3299 /* minute */
3300 carry += d->min;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003301 r->min = (unsigned int) MODULO(carry, 60);
3302 carry = (long) FQUOTIENT(carry, 60);
Daniel Veillard5a872412002-05-22 06:40:27 +00003303
3304 /* hours */
3305 carry += d->hour;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003306 r->hour = (unsigned int) MODULO(carry, 24);
3307 carry = (long)FQUOTIENT(carry, 24);
Daniel Veillard5a872412002-05-22 06:40:27 +00003308
3309 /*
3310 * days
3311 * Note we use tempdays because the temporary values may need more
3312 * than 5 bits
3313 */
3314 if ((VALID_YEAR(r->year)) && (VALID_MONTH(r->mon)) &&
3315 (d->day > MAX_DAYINMONTH(r->year, r->mon)))
3316 tempdays = MAX_DAYINMONTH(r->year, r->mon);
3317 else if (d->day < 1)
3318 tempdays = 1;
3319 else
3320 tempdays = d->day;
3321
3322 tempdays += u->day + carry;
3323
3324 while (1) {
3325 if (tempdays < 1) {
Daniel Veillardebe25d42004-03-25 09:35:49 +00003326 long tmon = (long) MODULO_RANGE(r->mon-1, 1, 13);
3327 long tyr = r->year + (long)FQUOTIENT_RANGE(r->mon-1, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00003328 if (tyr == 0)
3329 tyr--;
3330 tempdays += MAX_DAYINMONTH(tyr, tmon);
3331 carry = -1;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003332 } else if (tempdays > (long) MAX_DAYINMONTH(r->year, r->mon)) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003333 tempdays = tempdays - MAX_DAYINMONTH(r->year, r->mon);
3334 carry = 1;
3335 } else
3336 break;
3337
3338 temp = r->mon + carry;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003339 r->mon = (unsigned int) MODULO_RANGE(temp, 1, 13);
3340 r->year = r->year + (unsigned int) FQUOTIENT_RANGE(temp, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00003341 if (r->year == 0) {
3342 if (temp < 1)
3343 r->year--;
3344 else
3345 r->year++;
3346 }
3347 }
3348
3349 r->day = tempdays;
3350
3351 /*
3352 * adjust the date/time type to the date values
3353 */
3354 if (ret->type != XML_SCHEMAS_DATETIME) {
3355 if ((r->hour) || (r->min) || (r->sec))
3356 ret->type = XML_SCHEMAS_DATETIME;
3357 else if (ret->type != XML_SCHEMAS_DATE) {
3358 if ((r->mon != 1) && (r->day != 1))
3359 ret->type = XML_SCHEMAS_DATE;
3360 else if ((ret->type != XML_SCHEMAS_GYEARMONTH) && (r->mon != 1))
3361 ret->type = XML_SCHEMAS_GYEARMONTH;
3362 }
3363 }
3364
Daniel Veillard669adfc2004-05-29 20:12:46 +00003365 xmlSchemaFreeValue(tmp);
Daniel Veillard5a872412002-05-22 06:40:27 +00003366
Daniel Veillard5a872412002-05-22 06:40:27 +00003367 return ret;
3368}
3369
3370/**
3371 * xmlSchemaDateNormalize:
Daniel Veillard669adfc2004-05-29 20:12:46 +00003372 * @dt: an #xmlSchemaValPtr of a date/time type value.
3373 * @offset: number of seconds to adjust @dt by.
Daniel Veillard5a872412002-05-22 06:40:27 +00003374 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00003375 * Normalize @dt to GMT time. The @offset parameter is subtracted from
3376 * the return value is a time-zone offset is present on @dt.
Daniel Veillard5a872412002-05-22 06:40:27 +00003377 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00003378 * Returns a normalized copy of @dt or NULL if error.
Daniel Veillard5a872412002-05-22 06:40:27 +00003379 */
3380static xmlSchemaValPtr
3381xmlSchemaDateNormalize (xmlSchemaValPtr dt, double offset)
3382{
3383 xmlSchemaValPtr dur, ret;
3384
3385 if (dt == NULL)
3386 return NULL;
3387
3388 if (((dt->type != XML_SCHEMAS_TIME) &&
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00003389 (dt->type != XML_SCHEMAS_DATETIME) &&
3390 (dt->type != XML_SCHEMAS_DATE)) || (dt->value.date.tzo == 0))
Daniel Veillard5a872412002-05-22 06:40:27 +00003391 return xmlSchemaDupVal(dt);
3392
3393 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
3394 if (dur == NULL)
3395 return NULL;
3396
3397 dur->value.date.sec -= offset;
3398
3399 ret = _xmlSchemaDateAdd(dt, dur);
3400 if (ret == NULL)
3401 return NULL;
3402
3403 xmlSchemaFreeValue(dur);
3404
3405 /* ret->value.date.tzo = 0; */
3406 return ret;
3407}
3408
3409/**
3410 * _xmlSchemaDateCastYMToDays:
3411 * @dt: an #xmlSchemaValPtr
3412 *
3413 * Convert mon and year of @dt to total number of days. Take the
3414 * number of years since (or before) 1 AD and add the number of leap
3415 * years. This is a function because negative
3416 * years must be handled a little differently and there is no zero year.
3417 *
3418 * Returns number of days.
3419 */
3420static long
3421_xmlSchemaDateCastYMToDays (const xmlSchemaValPtr dt)
3422{
3423 long ret;
Daniel Veillard49e89632004-09-23 16:24:36 +00003424 int mon;
Daniel Veillard5a872412002-05-22 06:40:27 +00003425
Daniel Veillard49e89632004-09-23 16:24:36 +00003426 mon = dt->value.date.mon;
3427 if (mon <= 0) mon = 1; /* normalization */
3428
3429 if (dt->value.date.year <= 0)
Daniel Veillard5a872412002-05-22 06:40:27 +00003430 ret = (dt->value.date.year * 365) +
3431 (((dt->value.date.year+1)/4)-((dt->value.date.year+1)/100)+
3432 ((dt->value.date.year+1)/400)) +
Daniel Veillard49e89632004-09-23 16:24:36 +00003433 DAY_IN_YEAR(0, mon, dt->value.date.year);
Daniel Veillard5a872412002-05-22 06:40:27 +00003434 else
3435 ret = ((dt->value.date.year-1) * 365) +
3436 (((dt->value.date.year-1)/4)-((dt->value.date.year-1)/100)+
3437 ((dt->value.date.year-1)/400)) +
Daniel Veillard49e89632004-09-23 16:24:36 +00003438 DAY_IN_YEAR(0, mon, dt->value.date.year);
Daniel Veillard5a872412002-05-22 06:40:27 +00003439
3440 return ret;
3441}
3442
3443/**
3444 * TIME_TO_NUMBER:
3445 * @dt: an #xmlSchemaValPtr
3446 *
3447 * Calculates the number of seconds in the time portion of @dt.
3448 *
3449 * Returns seconds.
3450 */
3451#define TIME_TO_NUMBER(dt) \
3452 ((double)((dt->value.date.hour * SECS_PER_HOUR) + \
Daniel Veillardb3721c22003-03-31 11:22:25 +00003453 (dt->value.date.min * SECS_PER_MIN) + \
3454 (dt->value.date.tzo * SECS_PER_MIN)) + \
3455 dt->value.date.sec)
Daniel Veillard5a872412002-05-22 06:40:27 +00003456
3457/**
3458 * xmlSchemaCompareDates:
3459 * @x: a first date/time value
3460 * @y: a second date/time value
3461 *
3462 * Compare 2 date/times
3463 *
3464 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3465 * case of error
3466 */
3467static int
3468xmlSchemaCompareDates (xmlSchemaValPtr x, xmlSchemaValPtr y)
3469{
3470 unsigned char xmask, ymask, xor_mask, and_mask;
3471 xmlSchemaValPtr p1, p2, q1, q2;
3472 long p1d, p2d, q1d, q2d;
3473
3474 if ((x == NULL) || (y == NULL))
3475 return -2;
3476
3477 if (x->value.date.tz_flag) {
3478
3479 if (!y->value.date.tz_flag) {
3480 p1 = xmlSchemaDateNormalize(x, 0);
3481 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3482 /* normalize y + 14:00 */
3483 q1 = xmlSchemaDateNormalize(y, (14 * SECS_PER_HOUR));
3484
3485 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003486 if (p1d < q1d) {
3487 xmlSchemaFreeValue(p1);
3488 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003489 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003490 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003491 double sec;
3492
3493 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00003494 if (sec < 0.0) {
3495 xmlSchemaFreeValue(p1);
3496 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003497 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003498 } else {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003499 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003500 /* normalize y - 14:00 */
3501 q2 = xmlSchemaDateNormalize(y, -(14 * SECS_PER_HOUR));
3502 q2d = _xmlSchemaDateCastYMToDays(q2) + q2->value.date.day;
3503 if (p1d > q2d)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003504 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003505 else if (p1d == q2d) {
3506 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q2);
3507 if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003508 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003509 else
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003510 ret = 2; /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00003511 }
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003512 xmlSchemaFreeValue(p1);
3513 xmlSchemaFreeValue(q1);
3514 xmlSchemaFreeValue(q2);
3515 if (ret != 0)
3516 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003517 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00003518 } else {
3519 xmlSchemaFreeValue(p1);
3520 xmlSchemaFreeValue(q1);
3521 }
Daniel Veillard5a872412002-05-22 06:40:27 +00003522 }
3523 } else if (y->value.date.tz_flag) {
3524 q1 = xmlSchemaDateNormalize(y, 0);
3525 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
3526
3527 /* normalize x - 14:00 */
3528 p1 = xmlSchemaDateNormalize(x, -(14 * SECS_PER_HOUR));
3529 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3530
Daniel Veillardfdc91562002-07-01 21:52:03 +00003531 if (p1d < q1d) {
3532 xmlSchemaFreeValue(p1);
3533 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003534 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003535 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003536 double sec;
3537
3538 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00003539 if (sec < 0.0) {
3540 xmlSchemaFreeValue(p1);
3541 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003542 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003543 } else {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003544 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003545 /* normalize x + 14:00 */
3546 p2 = xmlSchemaDateNormalize(x, (14 * SECS_PER_HOUR));
3547 p2d = _xmlSchemaDateCastYMToDays(p2) + p2->value.date.day;
3548
Daniel Veillard6560a422003-03-27 21:25:38 +00003549 if (p2d > q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003550 ret = 1;
Daniel Veillard6560a422003-03-27 21:25:38 +00003551 } else if (p2d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003552 sec = TIME_TO_NUMBER(p2) - TIME_TO_NUMBER(q1);
3553 if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003554 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003555 else
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003556 ret = 2; /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00003557 }
Daniel Veillard6560a422003-03-27 21:25:38 +00003558 xmlSchemaFreeValue(p1);
3559 xmlSchemaFreeValue(q1);
3560 xmlSchemaFreeValue(p2);
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003561 if (ret != 0)
3562 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003563 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00003564 } else {
3565 xmlSchemaFreeValue(p1);
3566 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003567 }
3568 }
3569
3570 /*
3571 * if the same type then calculate the difference
3572 */
3573 if (x->type == y->type) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003574 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003575 q1 = xmlSchemaDateNormalize(y, 0);
3576 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
3577
3578 p1 = xmlSchemaDateNormalize(x, 0);
3579 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3580
Daniel Veillardfdc91562002-07-01 21:52:03 +00003581 if (p1d < q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003582 ret = -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003583 } else if (p1d > q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003584 ret = 1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003585 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00003586 double sec;
3587
3588 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
3589 if (sec < 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003590 ret = -1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003591 else if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003592 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003593
3594 }
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003595 xmlSchemaFreeValue(p1);
3596 xmlSchemaFreeValue(q1);
3597 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003598 }
3599
3600 switch (x->type) {
3601 case XML_SCHEMAS_DATETIME:
3602 xmask = 0xf;
3603 break;
3604 case XML_SCHEMAS_DATE:
3605 xmask = 0x7;
3606 break;
3607 case XML_SCHEMAS_GYEAR:
3608 xmask = 0x1;
3609 break;
3610 case XML_SCHEMAS_GMONTH:
3611 xmask = 0x2;
3612 break;
3613 case XML_SCHEMAS_GDAY:
3614 xmask = 0x3;
3615 break;
3616 case XML_SCHEMAS_GYEARMONTH:
3617 xmask = 0x3;
3618 break;
3619 case XML_SCHEMAS_GMONTHDAY:
3620 xmask = 0x6;
3621 break;
3622 case XML_SCHEMAS_TIME:
3623 xmask = 0x8;
3624 break;
3625 default:
3626 xmask = 0;
3627 break;
3628 }
3629
3630 switch (y->type) {
3631 case XML_SCHEMAS_DATETIME:
3632 ymask = 0xf;
3633 break;
3634 case XML_SCHEMAS_DATE:
3635 ymask = 0x7;
3636 break;
3637 case XML_SCHEMAS_GYEAR:
3638 ymask = 0x1;
3639 break;
3640 case XML_SCHEMAS_GMONTH:
3641 ymask = 0x2;
3642 break;
3643 case XML_SCHEMAS_GDAY:
3644 ymask = 0x3;
3645 break;
3646 case XML_SCHEMAS_GYEARMONTH:
3647 ymask = 0x3;
3648 break;
3649 case XML_SCHEMAS_GMONTHDAY:
3650 ymask = 0x6;
3651 break;
3652 case XML_SCHEMAS_TIME:
3653 ymask = 0x8;
3654 break;
3655 default:
3656 ymask = 0;
3657 break;
3658 }
3659
3660 xor_mask = xmask ^ ymask; /* mark type differences */
3661 and_mask = xmask & ymask; /* mark field specification */
3662
3663 /* year */
3664 if (xor_mask & 1)
3665 return 2; /* indeterminate */
3666 else if (and_mask & 1) {
3667 if (x->value.date.year < y->value.date.year)
3668 return -1;
3669 else if (x->value.date.year > y->value.date.year)
3670 return 1;
3671 }
3672
3673 /* month */
3674 if (xor_mask & 2)
3675 return 2; /* indeterminate */
3676 else if (and_mask & 2) {
3677 if (x->value.date.mon < y->value.date.mon)
3678 return -1;
3679 else if (x->value.date.mon > y->value.date.mon)
3680 return 1;
3681 }
3682
3683 /* day */
3684 if (xor_mask & 4)
3685 return 2; /* indeterminate */
3686 else if (and_mask & 4) {
3687 if (x->value.date.day < y->value.date.day)
3688 return -1;
3689 else if (x->value.date.day > y->value.date.day)
3690 return 1;
3691 }
3692
3693 /* time */
3694 if (xor_mask & 8)
3695 return 2; /* indeterminate */
3696 else if (and_mask & 8) {
3697 if (x->value.date.hour < y->value.date.hour)
3698 return -1;
3699 else if (x->value.date.hour > y->value.date.hour)
3700 return 1;
3701 else if (x->value.date.min < y->value.date.min)
3702 return -1;
3703 else if (x->value.date.min > y->value.date.min)
3704 return 1;
3705 else if (x->value.date.sec < y->value.date.sec)
3706 return -1;
3707 else if (x->value.date.sec > y->value.date.sec)
3708 return 1;
3709 }
3710
Daniel Veillard070803b2002-05-03 07:29:38 +00003711 return 0;
3712}
3713
3714/**
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003715 * xmlSchemaComparePreserveReplaceStrings:
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003716 * @x: a first string value
3717 * @y: a second string value
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003718 * @invert: inverts the result if x < y or x > y.
3719 *
3720 * Compare 2 string for their normalized values.
3721 * @x is a string with whitespace of "preserve", @y is
3722 * a string with a whitespace of "replace". I.e. @x could
3723 * be an "xsd:string" and @y an "xsd:normalizedString".
3724 *
3725 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
3726 * case of error
3727 */
3728static int
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003729xmlSchemaComparePreserveReplaceStrings(const xmlChar *x,
3730 const xmlChar *y,
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003731 int invert)
3732{
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003733 int tmp;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003734
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003735 while ((*x != 0) && (*y != 0)) {
3736 if (IS_WSP_REPLACE_CH(*y)) {
3737 if (! IS_WSP_SPACE_CH(*x)) {
3738 if ((*x - 0x20) < 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003739 if (invert)
3740 return(1);
3741 else
3742 return(-1);
3743 } else {
3744 if (invert)
3745 return(-1);
3746 else
3747 return(1);
3748 }
3749 }
3750 } else {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003751 tmp = *x - *y;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003752 if (tmp < 0) {
3753 if (invert)
3754 return(1);
3755 else
3756 return(-1);
3757 }
3758 if (tmp > 0) {
3759 if (invert)
3760 return(-1);
3761 else
3762 return(1);
3763 }
3764 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003765 x++;
3766 y++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003767 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003768 if (*x != 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003769 if (invert)
3770 return(-1);
3771 else
3772 return(1);
3773 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003774 if (*y != 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003775 if (invert)
3776 return(1);
3777 else
3778 return(-1);
3779 }
3780 return(0);
3781}
3782
3783/**
3784 * xmlSchemaComparePreserveCollapseStrings:
3785 * @x: a first string value
3786 * @y: a second string value
3787 *
3788 * Compare 2 string for their normalized values.
3789 * @x is a string with whitespace of "preserve", @y is
3790 * a string with a whitespace of "collapse". I.e. @x could
3791 * be an "xsd:string" and @y an "xsd:normalizedString".
3792 *
3793 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
3794 * case of error
3795 */
3796static int
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003797xmlSchemaComparePreserveCollapseStrings(const xmlChar *x,
3798 const xmlChar *y,
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003799 int invert)
3800{
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003801 int tmp;
3802
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003803 /*
3804 * Skip leading blank chars of the collapsed string.
3805 */
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003806 while IS_WSP_BLANK_CH(*y)
3807 y++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003808
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003809 while ((*x != 0) && (*y != 0)) {
3810 if IS_WSP_BLANK_CH(*y) {
3811 if (! IS_WSP_SPACE_CH(*x)) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003812 /*
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003813 * The yv character would have been replaced to 0x20.
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003814 */
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003815 if ((*x - 0x20) < 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003816 if (invert)
3817 return(1);
3818 else
3819 return(-1);
3820 } else {
3821 if (invert)
3822 return(-1);
3823 else
3824 return(1);
3825 }
3826 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003827 x++;
3828 y++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003829 /*
3830 * Skip contiguous blank chars of the collapsed string.
3831 */
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003832 while IS_WSP_BLANK_CH(*y)
3833 y++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003834 } else {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003835 tmp = *x++ - *y++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003836 if (tmp < 0) {
3837 if (invert)
3838 return(1);
3839 else
3840 return(-1);
3841 }
3842 if (tmp > 0) {
3843 if (invert)
3844 return(-1);
3845 else
3846 return(1);
3847 }
3848 }
3849 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003850 if (*x != 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003851 if (invert)
3852 return(-1);
3853 else
3854 return(1);
3855 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003856 if (*y != 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003857 /*
3858 * Skip trailing blank chars of the collapsed string.
3859 */
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003860 while IS_WSP_BLANK_CH(*y)
3861 y++;
3862 if (*y != 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003863 if (invert)
3864 return(1);
3865 else
3866 return(-1);
3867 }
3868 }
3869 return(0);
3870}
3871
3872/**
3873 * xmlSchemaComparePreserveCollapseStrings:
3874 * @x: a first string value
3875 * @y: a second string value
3876 *
3877 * Compare 2 string for their normalized values.
3878 * @x is a string with whitespace of "preserve", @y is
3879 * a string with a whitespace of "collapse". I.e. @x could
3880 * be an "xsd:string" and @y an "xsd:normalizedString".
3881 *
3882 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
3883 * case of error
3884 */
3885static int
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003886xmlSchemaCompareReplaceCollapseStrings(const xmlChar *x,
3887 const xmlChar *y,
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003888 int invert)
3889{
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003890 int tmp;
3891
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003892 /*
3893 * Skip leading blank chars of the collapsed string.
3894 */
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003895 while IS_WSP_BLANK_CH(*y)
3896 y++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003897
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003898 while ((*x != 0) && (*y != 0)) {
3899 if IS_WSP_BLANK_CH(*y) {
3900 if (! IS_WSP_BLANK_CH(*x)) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003901 /*
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003902 * The yv character would have been replaced to 0x20.
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003903 */
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003904 if ((*x - 0x20) < 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003905 if (invert)
3906 return(1);
3907 else
3908 return(-1);
3909 } else {
3910 if (invert)
3911 return(-1);
3912 else
3913 return(1);
3914 }
3915 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003916 x++;
3917 y++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003918 /*
3919 * Skip contiguous blank chars of the collapsed string.
3920 */
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003921 while IS_WSP_BLANK_CH(*y)
3922 y++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003923 } else {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003924 if IS_WSP_BLANK_CH(*x) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003925 /*
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003926 * The xv character would have been replaced to 0x20.
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003927 */
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003928 if ((0x20 - *y) < 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003929 if (invert)
3930 return(1);
3931 else
3932 return(-1);
3933 } else {
3934 if (invert)
3935 return(-1);
3936 else
3937 return(1);
3938 }
3939 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003940 tmp = *x++ - *y++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003941 if (tmp < 0)
3942 return(-1);
3943 if (tmp > 0)
3944 return(1);
3945 }
3946 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003947 if (*x != 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003948 if (invert)
3949 return(-1);
3950 else
3951 return(1);
3952 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003953 if (*y != 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003954 /*
3955 * Skip trailing blank chars of the collapsed string.
3956 */
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003957 while IS_WSP_BLANK_CH(*y)
3958 y++;
3959 if (*y != 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003960 if (invert)
3961 return(1);
3962 else
3963 return(-1);
3964 }
3965 }
3966 return(0);
3967}
3968
3969
3970/**
3971 * xmlSchemaCompareReplacedStrings:
3972 * @x: a first string value
3973 * @y: a second string value
3974 *
3975 * Compare 2 string for their normalized values.
3976 *
3977 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
3978 * case of error
3979 */
3980static int
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003981xmlSchemaCompareReplacedStrings(const xmlChar *x,
3982 const xmlChar *y)
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003983{
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003984 int tmp;
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003985
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003986 while ((*x != 0) && (*y != 0)) {
3987 if IS_WSP_BLANK_CH(*y) {
3988 if (! IS_WSP_BLANK_CH(*x)) {
3989 if ((*x - 0x20) < 0)
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003990 return(-1);
3991 else
3992 return(1);
3993 }
3994 } else {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003995 if IS_WSP_BLANK_CH(*x) {
3996 if ((0x20 - *y) < 0)
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003997 return(-1);
3998 else
3999 return(1);
4000 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004001 tmp = *x - *y;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004002 if (tmp < 0)
4003 return(-1);
4004 if (tmp > 0)
4005 return(1);
4006 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004007 x++;
4008 y++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004009 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004010 if (*x != 0)
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004011 return(1);
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004012 if (*y != 0)
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004013 return(-1);
4014 return(0);
4015}
4016
4017/**
Daniel Veillardc4c21552003-03-29 10:53:38 +00004018 * xmlSchemaCompareNormStrings:
4019 * @x: a first string value
4020 * @y: a second string value
4021 *
4022 * Compare 2 string for their normalized values.
4023 *
4024 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
4025 * case of error
4026 */
4027static int
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004028xmlSchemaCompareNormStrings(const xmlChar *x,
4029 const xmlChar *y) {
Daniel Veillardc4c21552003-03-29 10:53:38 +00004030 int tmp;
Daniel Veillardc4c21552003-03-29 10:53:38 +00004031
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004032 while (IS_BLANK_CH(*x)) x++;
4033 while (IS_BLANK_CH(*y)) y++;
4034 while ((*x != 0) && (*y != 0)) {
4035 if (IS_BLANK_CH(*x)) {
4036 if (!IS_BLANK_CH(*y)) {
4037 tmp = *x - *y;
Daniel Veillardc4c21552003-03-29 10:53:38 +00004038 return(tmp);
4039 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004040 while (IS_BLANK_CH(*x)) x++;
4041 while (IS_BLANK_CH(*y)) y++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00004042 } else {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004043 tmp = *x++ - *y++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00004044 if (tmp < 0)
4045 return(-1);
4046 if (tmp > 0)
4047 return(1);
4048 }
4049 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004050 if (*x != 0) {
4051 while (IS_BLANK_CH(*x)) x++;
4052 if (*x != 0)
Daniel Veillardc4c21552003-03-29 10:53:38 +00004053 return(1);
4054 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004055 if (*y != 0) {
4056 while (IS_BLANK_CH(*y)) y++;
4057 if (*y != 0)
Daniel Veillardc4c21552003-03-29 10:53:38 +00004058 return(-1);
4059 }
4060 return(0);
4061}
4062
4063/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00004064 * xmlSchemaCompareFloats:
4065 * @x: a first float or double value
4066 * @y: a second float or double value
4067 *
4068 * Compare 2 values
4069 *
4070 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
4071 * case of error
4072 */
4073static int
4074xmlSchemaCompareFloats(xmlSchemaValPtr x, xmlSchemaValPtr y) {
4075 double d1, d2;
4076
4077 if ((x == NULL) || (y == NULL))
4078 return(-2);
4079
4080 /*
4081 * Cast everything to doubles.
4082 */
4083 if (x->type == XML_SCHEMAS_DOUBLE)
4084 d1 = x->value.d;
4085 else if (x->type == XML_SCHEMAS_FLOAT)
4086 d1 = x->value.f;
4087 else
4088 return(-2);
4089
4090 if (y->type == XML_SCHEMAS_DOUBLE)
4091 d2 = y->value.d;
4092 else if (y->type == XML_SCHEMAS_FLOAT)
4093 d2 = y->value.f;
4094 else
4095 return(-2);
4096
4097 /*
4098 * Check for special cases.
4099 */
4100 if (xmlXPathIsNaN(d1)) {
4101 if (xmlXPathIsNaN(d2))
4102 return(0);
4103 return(1);
4104 }
4105 if (xmlXPathIsNaN(d2))
4106 return(-1);
4107 if (d1 == xmlXPathPINF) {
4108 if (d2 == xmlXPathPINF)
4109 return(0);
4110 return(1);
4111 }
4112 if (d2 == xmlXPathPINF)
4113 return(-1);
4114 if (d1 == xmlXPathNINF) {
4115 if (d2 == xmlXPathNINF)
4116 return(0);
4117 return(-1);
4118 }
4119 if (d2 == xmlXPathNINF)
4120 return(1);
4121
4122 /*
4123 * basic tests, the last one we should have equality, but
4124 * portability is more important than speed and handling
4125 * NaN or Inf in a portable way is always a challenge, so ...
4126 */
4127 if (d1 < d2)
4128 return(-1);
4129 if (d1 > d2)
4130 return(1);
4131 if (d1 == d2)
4132 return(0);
4133 return(2);
4134}
4135
4136/**
Daniel Veillard4255d502002-04-16 15:50:10 +00004137 * xmlSchemaCompareValues:
4138 * @x: a first value
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004139 * @xvalue: the first value as a string (optional)
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004140 * @xwtsp: the whitespace type
Daniel Veillard4255d502002-04-16 15:50:10 +00004141 * @y: a second value
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004142 * @xvalue: the second value as a string (optional)
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004143 * @ywtsp: the whitespace type
Daniel Veillard4255d502002-04-16 15:50:10 +00004144 *
4145 * Compare 2 values
4146 *
Daniel Veillard5a872412002-05-22 06:40:27 +00004147 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
4148 * case of error
Daniel Veillard4255d502002-04-16 15:50:10 +00004149 */
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004150static int
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004151xmlSchemaCompareValuesInternal(xmlSchemaValType xtype,
4152 xmlSchemaValPtr x,
4153 const xmlChar *xvalue,
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004154 xmlSchemaWhitespaceValueType xws,
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004155 xmlSchemaValType ytype,
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004156 xmlSchemaValPtr y,
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004157 const xmlChar *yvalue,
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004158 xmlSchemaWhitespaceValueType yws)
4159{
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004160 switch (xtype) {
Daniel Veillard80b19092003-03-28 13:29:53 +00004161 case XML_SCHEMAS_UNKNOWN:
William M. Brack2f2a6632004-08-20 23:09:47 +00004162 case XML_SCHEMAS_ANYTYPE:
Daniel Veillard80b19092003-03-28 13:29:53 +00004163 return(-2);
4164 case XML_SCHEMAS_INTEGER:
4165 case XML_SCHEMAS_NPINTEGER:
4166 case XML_SCHEMAS_NINTEGER:
4167 case XML_SCHEMAS_NNINTEGER:
4168 case XML_SCHEMAS_PINTEGER:
4169 case XML_SCHEMAS_INT:
4170 case XML_SCHEMAS_UINT:
4171 case XML_SCHEMAS_LONG:
4172 case XML_SCHEMAS_ULONG:
4173 case XML_SCHEMAS_SHORT:
4174 case XML_SCHEMAS_USHORT:
4175 case XML_SCHEMAS_BYTE:
4176 case XML_SCHEMAS_UBYTE:
Daniel Veillard4255d502002-04-16 15:50:10 +00004177 case XML_SCHEMAS_DECIMAL:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004178 if ((x == NULL) || (y == NULL))
4179 return(-2);
4180 if (ytype == xtype)
Daniel Veillard80b19092003-03-28 13:29:53 +00004181 return(xmlSchemaCompareDecimals(x, y));
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004182 if ((ytype == XML_SCHEMAS_DECIMAL) ||
4183 (ytype == XML_SCHEMAS_INTEGER) ||
4184 (ytype == XML_SCHEMAS_NPINTEGER) ||
4185 (ytype == XML_SCHEMAS_NINTEGER) ||
4186 (ytype == XML_SCHEMAS_NNINTEGER) ||
4187 (ytype == XML_SCHEMAS_PINTEGER) ||
4188 (ytype == XML_SCHEMAS_INT) ||
4189 (ytype == XML_SCHEMAS_UINT) ||
4190 (ytype == XML_SCHEMAS_LONG) ||
4191 (ytype == XML_SCHEMAS_ULONG) ||
4192 (ytype == XML_SCHEMAS_SHORT) ||
4193 (ytype == XML_SCHEMAS_USHORT) ||
4194 (ytype == XML_SCHEMAS_BYTE) ||
4195 (ytype == XML_SCHEMAS_UBYTE))
Daniel Veillard4255d502002-04-16 15:50:10 +00004196 return(xmlSchemaCompareDecimals(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00004197 return(-2);
Daniel Veillard070803b2002-05-03 07:29:38 +00004198 case XML_SCHEMAS_DURATION:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004199 if ((x == NULL) || (y == NULL))
4200 return(-2);
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004201 if (ytype == XML_SCHEMAS_DURATION)
Daniel Veillard070803b2002-05-03 07:29:38 +00004202 return(xmlSchemaCompareDurations(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00004203 return(-2);
4204 case XML_SCHEMAS_TIME:
4205 case XML_SCHEMAS_GDAY:
4206 case XML_SCHEMAS_GMONTH:
4207 case XML_SCHEMAS_GMONTHDAY:
4208 case XML_SCHEMAS_GYEAR:
4209 case XML_SCHEMAS_GYEARMONTH:
4210 case XML_SCHEMAS_DATE:
4211 case XML_SCHEMAS_DATETIME:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004212 if ((x == NULL) || (y == NULL))
4213 return(-2);
4214 if ((ytype == XML_SCHEMAS_DATETIME) ||
4215 (ytype == XML_SCHEMAS_TIME) ||
4216 (ytype == XML_SCHEMAS_GDAY) ||
4217 (ytype == XML_SCHEMAS_GMONTH) ||
4218 (ytype == XML_SCHEMAS_GMONTHDAY) ||
4219 (ytype == XML_SCHEMAS_GYEAR) ||
4220 (ytype == XML_SCHEMAS_DATE) ||
4221 (ytype == XML_SCHEMAS_GYEARMONTH))
Daniel Veillard5a872412002-05-22 06:40:27 +00004222 return (xmlSchemaCompareDates(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00004223 return (-2);
Kasimier T. Buchcik2ee855d2005-03-07 11:14:14 +00004224 /*
4225 * Note that we will support comparison of string types against
4226 * anySimpleType as well.
4227 */
4228 case XML_SCHEMAS_ANYSIMPLETYPE:
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004229 case XML_SCHEMAS_STRING:
4230 case XML_SCHEMAS_NORMSTRING:
Daniel Veillard80b19092003-03-28 13:29:53 +00004231 case XML_SCHEMAS_TOKEN:
4232 case XML_SCHEMAS_LANGUAGE:
4233 case XML_SCHEMAS_NMTOKEN:
Daniel Veillard80b19092003-03-28 13:29:53 +00004234 case XML_SCHEMAS_NAME:
Daniel Veillard80b19092003-03-28 13:29:53 +00004235 case XML_SCHEMAS_NCNAME:
4236 case XML_SCHEMAS_ID:
4237 case XML_SCHEMAS_IDREF:
Daniel Veillard80b19092003-03-28 13:29:53 +00004238 case XML_SCHEMAS_ENTITY:
Daniel Veillard80b19092003-03-28 13:29:53 +00004239 case XML_SCHEMAS_ANYURI:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004240 {
4241 const xmlChar *xv, *yv;
4242
4243 if (x == NULL)
4244 xv = xvalue;
4245 else
4246 xv = x->value.str;
4247 if (y == NULL)
4248 yv = yvalue;
4249 else
4250 yv = y->value.str;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004251 /*
4252 * TODO: Compare those against QName.
4253 */
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004254 if (ytype == XML_SCHEMAS_QNAME) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004255 TODO
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004256 if (y == NULL)
4257 return(-2);
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004258 return (-2);
4259 }
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004260 if ((ytype == XML_SCHEMAS_ANYSIMPLETYPE) ||
4261 (ytype == XML_SCHEMAS_STRING) ||
4262 (ytype == XML_SCHEMAS_NORMSTRING) ||
4263 (ytype == XML_SCHEMAS_TOKEN) ||
4264 (ytype == XML_SCHEMAS_LANGUAGE) ||
4265 (ytype == XML_SCHEMAS_NMTOKEN) ||
4266 (ytype == XML_SCHEMAS_NAME) ||
4267 (ytype == XML_SCHEMAS_NCNAME) ||
4268 (ytype == XML_SCHEMAS_ID) ||
4269 (ytype == XML_SCHEMAS_IDREF) ||
4270 (ytype == XML_SCHEMAS_ENTITY) ||
4271 (ytype == XML_SCHEMAS_NOTATION) ||
4272 (ytype == XML_SCHEMAS_ANYURI)) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004273
4274 if (xws == XML_SCHEMA_WHITESPACE_PRESERVE) {
4275
4276 if (yws == XML_SCHEMA_WHITESPACE_PRESERVE) {
4277 /* TODO: What about x < y or x > y. */
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004278 if (xmlStrEqual(xv, yv))
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004279 return (0);
4280 else
4281 return (2);
4282 } else if (yws == XML_SCHEMA_WHITESPACE_REPLACE)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004283 return (xmlSchemaComparePreserveReplaceStrings(xv, yv, 0));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004284 else if (yws == XML_SCHEMA_WHITESPACE_COLLAPSE)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004285 return (xmlSchemaComparePreserveCollapseStrings(xv, yv, 0));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004286
4287 } else if (xws == XML_SCHEMA_WHITESPACE_REPLACE) {
4288
4289 if (yws == XML_SCHEMA_WHITESPACE_PRESERVE)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004290 return (xmlSchemaComparePreserveReplaceStrings(yv, xv, 1));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004291 if (yws == XML_SCHEMA_WHITESPACE_REPLACE)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004292 return (xmlSchemaCompareReplacedStrings(xv, yv));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004293 if (yws == XML_SCHEMA_WHITESPACE_COLLAPSE)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004294 return (xmlSchemaCompareReplaceCollapseStrings(xv, yv, 0));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004295
4296 } else if (xws == XML_SCHEMA_WHITESPACE_COLLAPSE) {
4297
4298 if (yws == XML_SCHEMA_WHITESPACE_PRESERVE)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004299 return (xmlSchemaComparePreserveCollapseStrings(yv, xv, 1));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004300 if (yws == XML_SCHEMA_WHITESPACE_REPLACE)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004301 return (xmlSchemaCompareReplaceCollapseStrings(yv, xv, 1));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004302 if (yws == XML_SCHEMA_WHITESPACE_COLLAPSE)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004303 return (xmlSchemaCompareNormStrings(xv, yv));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004304 } else
4305 return (-2);
4306
4307 }
Daniel Veillardc4c21552003-03-29 10:53:38 +00004308 return (-2);
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004309 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004310 case XML_SCHEMAS_QNAME:
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00004311 case XML_SCHEMAS_NOTATION:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004312 if ((x == NULL) || (y == NULL))
4313 return(-2);
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00004314 if ((ytype == XML_SCHEMAS_QNAME) ||
4315 (ytype == XML_SCHEMAS_NOTATION)) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004316 if ((xmlStrEqual(x->value.qname.name, y->value.qname.name)) &&
4317 (xmlStrEqual(x->value.qname.uri, y->value.qname.uri)))
4318 return(0);
4319 return(2);
4320 }
4321 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00004322 case XML_SCHEMAS_FLOAT:
4323 case XML_SCHEMAS_DOUBLE:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004324 if ((x == NULL) || (y == NULL))
4325 return(-2);
4326 if ((ytype == XML_SCHEMAS_FLOAT) ||
4327 (ytype == XML_SCHEMAS_DOUBLE))
Daniel Veillardb6c7f412003-03-29 16:41:55 +00004328 return (xmlSchemaCompareFloats(x, y));
4329 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00004330 case XML_SCHEMAS_BOOLEAN:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004331 if ((x == NULL) || (y == NULL))
4332 return(-2);
4333 if (ytype == XML_SCHEMAS_BOOLEAN) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00004334 if (x->value.b == y->value.b)
4335 return(0);
4336 if (x->value.b == 0)
4337 return(-1);
4338 return(1);
4339 }
4340 return (-2);
Daniel Veillard560c2a42003-07-06 21:13:49 +00004341 case XML_SCHEMAS_HEXBINARY:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004342 if ((x == NULL) || (y == NULL))
4343 return(-2);
4344 if (ytype == XML_SCHEMAS_HEXBINARY) {
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004345 if (x->value.hex.total == y->value.hex.total) {
4346 int ret = xmlStrcmp(x->value.hex.str, y->value.hex.str);
4347 if (ret > 0)
4348 return(1);
4349 else if (ret == 0)
4350 return(0);
4351 }
4352 else if (x->value.hex.total > y->value.hex.total)
4353 return(1);
4354
4355 return(-1);
4356 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00004357 return (-2);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00004358 case XML_SCHEMAS_BASE64BINARY:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004359 if ((x == NULL) || (y == NULL))
4360 return(-2);
4361 if (ytype == XML_SCHEMAS_BASE64BINARY) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00004362 if (x->value.base64.total == y->value.base64.total) {
4363 int ret = xmlStrcmp(x->value.base64.str,
4364 y->value.base64.str);
4365 if (ret > 0)
4366 return(1);
4367 else if (ret == 0)
4368 return(0);
4369 }
4370 else if (x->value.base64.total > y->value.base64.total)
4371 return(1);
4372 else
4373 return(-1);
4374 }
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004375 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00004376 case XML_SCHEMAS_IDREFS:
4377 case XML_SCHEMAS_ENTITIES:
4378 case XML_SCHEMAS_NMTOKENS:
4379 TODO
4380 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00004381 }
Daniel Veillard5a872412002-05-22 06:40:27 +00004382 return -2;
Daniel Veillard4255d502002-04-16 15:50:10 +00004383}
4384
4385/**
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004386 * xmlSchemaCompareValues:
4387 * @x: a first value
4388 * @y: a second value
4389 *
4390 * Compare 2 values
4391 *
4392 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
4393 * case of error
4394 */
4395int
4396xmlSchemaCompareValues(xmlSchemaValPtr x, xmlSchemaValPtr y) {
4397 xmlSchemaWhitespaceValueType xws, yws;
4398
Daniel Veillard5e094142005-02-18 19:36:12 +00004399 if ((x == NULL) || (y == NULL))
4400 return(-2);
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004401 if (x->type == XML_SCHEMAS_STRING)
4402 xws = XML_SCHEMA_WHITESPACE_PRESERVE;
4403 else if (x->type == XML_SCHEMAS_NORMSTRING)
4404 xws = XML_SCHEMA_WHITESPACE_REPLACE;
4405 else
4406 xws = XML_SCHEMA_WHITESPACE_COLLAPSE;
4407
4408 if (y->type == XML_SCHEMAS_STRING)
4409 yws = XML_SCHEMA_WHITESPACE_PRESERVE;
4410 else if (x->type == XML_SCHEMAS_NORMSTRING)
4411 yws = XML_SCHEMA_WHITESPACE_REPLACE;
4412 else
4413 yws = XML_SCHEMA_WHITESPACE_COLLAPSE;
4414
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004415 return(xmlSchemaCompareValuesInternal(x->type, x, NULL, xws, y->type,
4416 y, NULL, yws));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004417}
4418
4419/**
4420 * xmlSchemaCompareValuesWhtsp:
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 */
4431int
4432xmlSchemaCompareValuesWhtsp(xmlSchemaValPtr x,
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004433 xmlSchemaWhitespaceValueType xws,
4434 xmlSchemaValPtr y,
4435 xmlSchemaWhitespaceValueType yws)
4436{
Kasimier T. Buchcik9dbb0ce2005-03-16 16:39:23 +00004437 if ((x == NULL) || (y == NULL))
4438 return(-2);
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004439 return(xmlSchemaCompareValuesInternal(x->type, x, NULL, xws, y->type,
4440 y, NULL, yws));
4441}
4442
4443/**
4444 * xmlSchemaCompareValuesWhtspExt:
4445 * @x: a first value
4446 * @xws: the whitespace value of x
4447 * @y: a second value
4448 * @yws: the whitespace value of y
4449 *
4450 * Compare 2 values
4451 *
4452 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
4453 * case of error
4454 */
4455static int
4456xmlSchemaCompareValuesWhtspExt(xmlSchemaValType xtype,
4457 xmlSchemaValPtr x,
4458 const xmlChar *xvalue,
4459 xmlSchemaWhitespaceValueType xws,
4460 xmlSchemaValType ytype,
4461 xmlSchemaValPtr y,
4462 const xmlChar *yvalue,
4463 xmlSchemaWhitespaceValueType yws)
4464{
4465 return(xmlSchemaCompareValuesInternal(xtype, x, xvalue, xws, ytype, y,
4466 yvalue, yws));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004467}
4468
4469/**
Daniel Veillardc4c21552003-03-29 10:53:38 +00004470 * xmlSchemaNormLen:
4471 * @value: a string
4472 *
4473 * Computes the UTF8 length of the normalized value of the string
4474 *
4475 * Returns the length or -1 in case of error.
4476 */
4477static int
4478xmlSchemaNormLen(const xmlChar *value) {
4479 const xmlChar *utf;
4480 int ret = 0;
4481
4482 if (value == NULL)
4483 return(-1);
4484 utf = value;
William M. Brack76e95df2003-10-18 16:20:14 +00004485 while (IS_BLANK_CH(*utf)) utf++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00004486 while (*utf != 0) {
4487 if (utf[0] & 0x80) {
4488 if ((utf[1] & 0xc0) != 0x80)
4489 return(-1);
4490 if ((utf[0] & 0xe0) == 0xe0) {
4491 if ((utf[2] & 0xc0) != 0x80)
4492 return(-1);
4493 if ((utf[0] & 0xf0) == 0xf0) {
4494 if ((utf[0] & 0xf8) != 0xf0 || (utf[3] & 0xc0) != 0x80)
4495 return(-1);
4496 utf += 4;
4497 } else {
4498 utf += 3;
4499 }
4500 } else {
4501 utf += 2;
4502 }
William M. Brack76e95df2003-10-18 16:20:14 +00004503 } else if (IS_BLANK_CH(*utf)) {
4504 while (IS_BLANK_CH(*utf)) utf++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00004505 if (*utf == 0)
4506 break;
4507 } else {
4508 utf++;
4509 }
4510 ret++;
4511 }
4512 return(ret);
4513}
4514
Daniel Veillard6927b102004-10-27 17:29:04 +00004515/**
4516 * xmlSchemaGetFacetValueAsULong:
4517 * @facet: an schemas type facet
4518 *
4519 * Extract the value of a facet
4520 *
4521 * Returns the value as a long
4522 */
Daniel Veillardc0826a72004-08-10 14:17:33 +00004523unsigned long
4524xmlSchemaGetFacetValueAsULong(xmlSchemaFacetPtr facet)
4525{
4526 /*
4527 * TODO: Check if this is a decimal.
4528 */
William M. Brack094dd862004-11-14 14:28:34 +00004529 if (facet == NULL)
4530 return 0;
Daniel Veillardc0826a72004-08-10 14:17:33 +00004531 return ((unsigned long) facet->val->value.decimal.lo);
4532}
4533
Daniel Veillardc4c21552003-03-29 10:53:38 +00004534/**
Daniel Veillard01fa6152004-06-29 17:04:39 +00004535 * xmlSchemaValidateListSimpleTypeFacet:
4536 * @facet: the facet to check
4537 * @value: the lexical repr of the value to validate
4538 * @actualLen: the number of list items
4539 * @expectedLen: the resulting expected number of list items
4540 *
4541 * Checks the value of a list simple type against a facet.
4542 *
4543 * Returns 0 if the value is valid, a positive error code
4544 * number otherwise and -1 in case of an internal error.
4545 */
4546int
4547xmlSchemaValidateListSimpleTypeFacet(xmlSchemaFacetPtr facet,
4548 const xmlChar *value,
4549 unsigned long actualLen,
4550 unsigned long *expectedLen)
4551{
Daniel Veillardce682bc2004-11-05 17:22:25 +00004552 if (facet == NULL)
4553 return(-1);
Daniel Veillard01fa6152004-06-29 17:04:39 +00004554 /*
4555 * TODO: Check if this will work with large numbers.
4556 * (compare value.decimal.mi and value.decimal.hi as well?).
4557 */
4558 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
4559 if (actualLen != facet->val->value.decimal.lo) {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004560 if (expectedLen != NULL)
Daniel Veillardc0826a72004-08-10 14:17:33 +00004561 *expectedLen = facet->val->value.decimal.lo;
Daniel Veillard01fa6152004-06-29 17:04:39 +00004562 return (XML_SCHEMAV_CVC_LENGTH_VALID);
4563 }
4564 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
4565 if (actualLen < facet->val->value.decimal.lo) {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004566 if (expectedLen != NULL)
Daniel Veillardc0826a72004-08-10 14:17:33 +00004567 *expectedLen = facet->val->value.decimal.lo;
Daniel Veillard01fa6152004-06-29 17:04:39 +00004568 return (XML_SCHEMAV_CVC_MINLENGTH_VALID);
4569 }
4570 } else if (facet->type == XML_SCHEMA_FACET_MAXLENGTH) {
4571 if (actualLen > facet->val->value.decimal.lo) {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004572 if (expectedLen != NULL)
Daniel Veillardc0826a72004-08-10 14:17:33 +00004573 *expectedLen = facet->val->value.decimal.lo;
Daniel Veillard01fa6152004-06-29 17:04:39 +00004574 return (XML_SCHEMAV_CVC_MAXLENGTH_VALID);
4575 }
4576 } else
4577 /*
4578 * NOTE: That we can pass NULL as xmlSchemaValPtr to
4579 * xmlSchemaValidateFacet, since the remaining facet types
4580 * are: XML_SCHEMA_FACET_PATTERN, XML_SCHEMA_FACET_ENUMERATION.
4581 */
4582 return(xmlSchemaValidateFacet(NULL, facet, value, NULL));
4583 return (0);
4584}
4585
4586/**
Daniel Veillard6927b102004-10-27 17:29:04 +00004587 * xmlSchemaValidateLengthFacet:
Daniel Veillardc0826a72004-08-10 14:17:33 +00004588 * @type: the built-in type
4589 * @facet: the facet to check
4590 * @value: the lexical repr. of the value to be validated
4591 * @val: the precomputed value
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004592 * @ws: the whitespace type of the value
4593 * @length: the actual length of the value
4594 *
4595 * Checka a value against a "length", "minLength" and "maxLength"
4596 * facet; sets @length to the computed length of @value.
4597 *
4598 * Returns 0 if the value is valid, a positive error code
4599 * otherwise and -1 in case of an internal or API error.
4600 */
4601static int
4602xmlSchemaValidateLengthFacetInternal(xmlSchemaFacetPtr facet,
4603 xmlSchemaTypeType valType,
4604 const xmlChar *value,
4605 xmlSchemaValPtr val,
4606 unsigned long *length,
4607 xmlSchemaWhitespaceValueType ws)
4608{
4609 unsigned int len = 0;
4610
4611 if ((length == NULL) || (facet == NULL))
4612 return (-1);
4613 *length = 0;
4614 if ((facet->type != XML_SCHEMA_FACET_LENGTH) &&
4615 (facet->type != XML_SCHEMA_FACET_MAXLENGTH) &&
4616 (facet->type != XML_SCHEMA_FACET_MINLENGTH))
4617 return (-1);
4618
4619 /*
4620 * TODO: length, maxLength and minLength must be of type
4621 * nonNegativeInteger only. Check if decimal is used somehow.
4622 */
4623 if ((facet->val == NULL) ||
4624 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
4625 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
4626 (facet->val->value.decimal.frac != 0)) {
4627 return(-1);
4628 }
4629 if ((val != NULL) && (val->type == XML_SCHEMAS_HEXBINARY))
4630 len = val->value.hex.total;
4631 else if ((val != NULL) && (val->type == XML_SCHEMAS_BASE64BINARY))
4632 len = val->value.base64.total;
4633 else {
4634 switch (valType) {
4635 case XML_SCHEMAS_STRING:
4636 case XML_SCHEMAS_NORMSTRING:
4637 if (ws == XML_SCHEMA_WHITESPACE_UNKNOWN) {
4638 /*
4639 * This is to ensure API compatibility with the old
4640 * xmlSchemaValidateLengthFacet(). Anyway, this was and
4641 * is not the correct handling.
4642 * TODO: Get rid of this case somehow.
4643 */
4644 if (valType == XML_SCHEMAS_STRING)
4645 len = xmlUTF8Strlen(value);
4646 else
4647 len = xmlSchemaNormLen(value);
4648 } else if (value != NULL) {
4649 if (ws == XML_SCHEMA_WHITESPACE_COLLAPSE)
4650 len = xmlSchemaNormLen(value);
4651 else
4652 /*
4653 * Should be OK for "preserve" as well.
4654 */
4655 len = xmlUTF8Strlen(value);
4656 }
4657 break;
4658 case XML_SCHEMAS_IDREF:
4659 case XML_SCHEMAS_TOKEN:
4660 case XML_SCHEMAS_LANGUAGE:
4661 case XML_SCHEMAS_NMTOKEN:
4662 case XML_SCHEMAS_NAME:
4663 case XML_SCHEMAS_NCNAME:
4664 case XML_SCHEMAS_ID:
4665 /*
4666 * FIXME: What exactly to do with anyURI?
4667 */
4668 case XML_SCHEMAS_ANYURI:
4669 if (value != NULL)
4670 len = xmlSchemaNormLen(value);
4671 break;
4672 default:
4673 TODO
4674 }
4675 }
4676 *length = (unsigned long) len;
4677 /*
4678 * TODO: Return the whole expected value, i.e. "lo", "mi" and "hi".
4679 */
4680 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
4681 if (len != facet->val->value.decimal.lo)
4682 return(XML_SCHEMAV_CVC_LENGTH_VALID);
4683 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
4684 if (len < facet->val->value.decimal.lo)
4685 return(XML_SCHEMAV_CVC_MINLENGTH_VALID);
4686 } else {
4687 if (len > facet->val->value.decimal.lo)
4688 return(XML_SCHEMAV_CVC_MAXLENGTH_VALID);
4689 }
4690
4691 return (0);
4692}
4693
4694/**
4695 * xmlSchemaValidateLengthFacet:
4696 * @type: the built-in type
4697 * @facet: the facet to check
4698 * @value: the lexical repr. of the value to be validated
4699 * @val: the precomputed value
Daniel Veillardc0826a72004-08-10 14:17:33 +00004700 * @length: the actual length of the value
4701 *
4702 * Checka a value against a "length", "minLength" and "maxLength"
4703 * facet; sets @length to the computed length of @value.
4704 *
4705 * Returns 0 if the value is valid, a positive error code
4706 * otherwise and -1 in case of an internal or API error.
4707 */
4708int
4709xmlSchemaValidateLengthFacet(xmlSchemaTypePtr type,
4710 xmlSchemaFacetPtr facet,
4711 const xmlChar *value,
4712 xmlSchemaValPtr val,
4713 unsigned long *length)
4714{
Daniel Veillardcc5e2332005-03-16 21:55:35 +00004715 if (type == NULL)
4716 return(-1);
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004717 return (xmlSchemaValidateLengthFacetInternal(facet,
4718 type->builtInType, value, val, length,
4719 XML_SCHEMA_WHITESPACE_UNKNOWN));
4720}
Daniel Veillardc0826a72004-08-10 14:17:33 +00004721
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004722/**
4723 * xmlSchemaValidateLengthFacetWhtsp:
4724 * @facet: the facet to check
4725 * @valType: the built-in type
4726 * @value: the lexical repr. of the value to be validated
4727 * @val: the precomputed value
4728 * @ws: the whitespace type of the value
4729 * @length: the actual length of the value
4730 *
4731 * Checka a value against a "length", "minLength" and "maxLength"
4732 * facet; sets @length to the computed length of @value.
4733 *
4734 * Returns 0 if the value is valid, a positive error code
4735 * otherwise and -1 in case of an internal or API error.
4736 */
4737int
4738xmlSchemaValidateLengthFacetWhtsp(xmlSchemaFacetPtr facet,
4739 xmlSchemaValType valType,
4740 const xmlChar *value,
4741 xmlSchemaValPtr val,
4742 unsigned long *length,
4743 xmlSchemaWhitespaceValueType ws)
4744{
4745 return (xmlSchemaValidateLengthFacetInternal(facet, valType, value, val,
4746 length, ws));
Daniel Veillardc0826a72004-08-10 14:17:33 +00004747}
4748
4749/**
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004750 * xmlSchemaValidateFacetInternal:
Daniel Veillard4255d502002-04-16 15:50:10 +00004751 * @facet: the facet to check
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004752 * @fws: the whitespace type of the facet's value
4753 * @valType: the built-in type of the value
Daniel Veillard4255d502002-04-16 15:50:10 +00004754 * @value: the lexical repr of the value to validate
4755 * @val: the precomputed value
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004756 * @ws: the whitespace type of the value
Daniel Veillard4255d502002-04-16 15:50:10 +00004757 *
4758 * Check a value against a facet condition
4759 *
4760 * Returns 0 if the element is schemas valid, a positive error code
4761 * number otherwise and -1 in case of internal or API error.
4762 */
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004763static int
4764xmlSchemaValidateFacetInternal(xmlSchemaFacetPtr facet,
4765 xmlSchemaWhitespaceValueType fws,
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004766 xmlSchemaValType valType,
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004767 const xmlChar *value,
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004768 xmlSchemaValPtr val,
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004769 xmlSchemaWhitespaceValueType ws)
Daniel Veillard4255d502002-04-16 15:50:10 +00004770{
4771 int ret;
4772
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004773 if (facet == NULL)
4774 return(-1);
4775
Daniel Veillard4255d502002-04-16 15:50:10 +00004776 switch (facet->type) {
4777 case XML_SCHEMA_FACET_PATTERN:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004778 /*
4779 * NOTE that for patterns, the @value needs to be the normalized
4780 * value, *not* the lexical initial value or the canonical value.
4781 */
4782 if (value == NULL)
4783 return(-1);
Daniel Veillard4255d502002-04-16 15:50:10 +00004784 ret = xmlRegexpExec(facet->regexp, value);
4785 if (ret == 1)
4786 return(0);
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004787 if (ret == 0)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004788 return(XML_SCHEMAV_CVC_PATTERN_VALID);
Daniel Veillard4255d502002-04-16 15:50:10 +00004789 return(ret);
4790 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
4791 ret = xmlSchemaCompareValues(val, facet->val);
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004792 if (ret == -2)
Daniel Veillard4255d502002-04-16 15:50:10 +00004793 return(-1);
Daniel Veillard4255d502002-04-16 15:50:10 +00004794 if (ret == -1)
4795 return(0);
Daniel Veillard01fa6152004-06-29 17:04:39 +00004796 return(XML_SCHEMAV_CVC_MAXEXCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00004797 case XML_SCHEMA_FACET_MAXINCLUSIVE:
4798 ret = xmlSchemaCompareValues(val, facet->val);
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004799 if (ret == -2)
Daniel Veillard070803b2002-05-03 07:29:38 +00004800 return(-1);
Daniel Veillard070803b2002-05-03 07:29:38 +00004801 if ((ret == -1) || (ret == 0))
4802 return(0);
Daniel Veillard01fa6152004-06-29 17:04:39 +00004803 return(XML_SCHEMAV_CVC_MAXINCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00004804 case XML_SCHEMA_FACET_MINEXCLUSIVE:
4805 ret = xmlSchemaCompareValues(val, facet->val);
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004806 if (ret == -2)
Daniel Veillard070803b2002-05-03 07:29:38 +00004807 return(-1);
Daniel Veillard070803b2002-05-03 07:29:38 +00004808 if (ret == 1)
4809 return(0);
Daniel Veillard01fa6152004-06-29 17:04:39 +00004810 return(XML_SCHEMAV_CVC_MINEXCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00004811 case XML_SCHEMA_FACET_MININCLUSIVE:
4812 ret = xmlSchemaCompareValues(val, facet->val);
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004813 if (ret == -2)
Daniel Veillard070803b2002-05-03 07:29:38 +00004814 return(-1);
Daniel Veillard070803b2002-05-03 07:29:38 +00004815 if ((ret == 1) || (ret == 0))
4816 return(0);
Daniel Veillard01fa6152004-06-29 17:04:39 +00004817 return(XML_SCHEMAV_CVC_MININCLUSIVE_VALID);
Daniel Veillard8651f532002-04-17 09:06:27 +00004818 case XML_SCHEMA_FACET_WHITESPACE:
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004819 /* TODO whitespaces */
Daniel Veillard01fa6152004-06-29 17:04:39 +00004820 /*
4821 * NOTE: Whitespace should be handled to normalize
4822 * the value to be validated against a the facets;
4823 * not to normalize the value in-between.
4824 */
Daniel Veillard8651f532002-04-17 09:06:27 +00004825 return(0);
Daniel Veillard88c58912002-04-23 07:12:20 +00004826 case XML_SCHEMA_FACET_ENUMERATION:
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004827 if (ws == XML_SCHEMA_WHITESPACE_UNKNOWN) {
4828 /*
4829 * This is to ensure API compatibility with the old
4830 * xmlSchemaValidateFacet().
4831 * TODO: Get rid of this case.
4832 */
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004833 if ((facet->value != NULL) &&
4834 (xmlStrEqual(facet->value, value)))
4835 return(0);
4836 } else {
4837 ret = xmlSchemaCompareValuesWhtspExt(facet->val->type,
4838 facet->val, facet->value, fws, valType, val,
4839 value, ws);
4840 if (ret == -2)
4841 return(-1);
4842 if (ret == 0)
4843 return(0);
4844 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00004845 return(XML_SCHEMAV_CVC_ENUMERATION_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004846 case XML_SCHEMA_FACET_LENGTH:
Kasimier T. Buchcikaba15f72005-04-01 15:17:27 +00004847 /*
4848 * SPEC (1.3) "if {primitive type definition} is QName or NOTATION,
4849 * then any {value} is facet-valid."
4850 */
4851 if ((valType == XML_SCHEMAS_QNAME) ||
4852 (valType == XML_SCHEMAS_NOTATION))
4853 return (0);
4854 /* No break on purpose. */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004855 case XML_SCHEMA_FACET_MAXLENGTH:
4856 case XML_SCHEMA_FACET_MINLENGTH: {
4857 unsigned int len = 0;
4858
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004859 /*
4860 * TODO: length, maxLength and minLength must be of type
4861 * nonNegativeInteger only. Check if decimal is used somehow.
4862 */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004863 if ((facet->val == NULL) ||
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004864 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
4865 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004866 (facet->val->value.decimal.frac != 0)) {
4867 return(-1);
4868 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00004869 if ((val != NULL) && (val->type == XML_SCHEMAS_HEXBINARY))
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004870 len = val->value.hex.total;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00004871 else if ((val != NULL) && (val->type == XML_SCHEMAS_BASE64BINARY))
4872 len = val->value.base64.total;
4873 else {
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004874 switch (valType) {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004875 case XML_SCHEMAS_STRING:
4876 case XML_SCHEMAS_NORMSTRING:
4877 if (ws == XML_SCHEMA_WHITESPACE_UNKNOWN) {
4878 /*
4879 * This is to ensure API compatibility with the old
4880 * xmlSchemaValidateFacet(). Anyway, this was and
4881 * is not the correct handling.
4882 * TODO: Get rid of this case somehow.
4883 */
4884 if (valType == XML_SCHEMAS_STRING)
4885 len = xmlUTF8Strlen(value);
4886 else
4887 len = xmlSchemaNormLen(value);
4888 } else if (value != NULL) {
4889 if (ws == XML_SCHEMA_WHITESPACE_COLLAPSE)
4890 len = xmlSchemaNormLen(value);
4891 else
4892 /*
4893 * Should be OK for "preserve" as well.
4894 */
4895 len = xmlUTF8Strlen(value);
4896 }
4897 break;
4898 case XML_SCHEMAS_IDREF:
Daniel Veillard560c2a42003-07-06 21:13:49 +00004899 case XML_SCHEMAS_TOKEN:
4900 case XML_SCHEMAS_LANGUAGE:
4901 case XML_SCHEMAS_NMTOKEN:
4902 case XML_SCHEMAS_NAME:
4903 case XML_SCHEMAS_NCNAME:
4904 case XML_SCHEMAS_ID:
Daniel Veillard01fa6152004-06-29 17:04:39 +00004905 case XML_SCHEMAS_ANYURI:
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004906 if (value != NULL)
4907 len = xmlSchemaNormLen(value);
4908 break;
Daniel Veillard560c2a42003-07-06 21:13:49 +00004909 default:
4910 TODO
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004911 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004912 }
4913 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004914 if (len != facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004915 return(XML_SCHEMAV_CVC_LENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004916 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004917 if (len < facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004918 return(XML_SCHEMAV_CVC_MINLENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004919 } else {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004920 if (len > facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004921 return(XML_SCHEMAV_CVC_MAXLENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004922 }
4923 break;
4924 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00004925 case XML_SCHEMA_FACET_TOTALDIGITS:
4926 case XML_SCHEMA_FACET_FRACTIONDIGITS:
4927
4928 if ((facet->val == NULL) ||
4929 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
4930 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
4931 (facet->val->value.decimal.frac != 0)) {
4932 return(-1);
4933 }
4934 if ((val == NULL) ||
4935 ((val->type != XML_SCHEMAS_DECIMAL) &&
4936 (val->type != XML_SCHEMAS_INTEGER) &&
4937 (val->type != XML_SCHEMAS_NPINTEGER) &&
4938 (val->type != XML_SCHEMAS_NINTEGER) &&
4939 (val->type != XML_SCHEMAS_NNINTEGER) &&
4940 (val->type != XML_SCHEMAS_PINTEGER) &&
4941 (val->type != XML_SCHEMAS_INT) &&
4942 (val->type != XML_SCHEMAS_UINT) &&
4943 (val->type != XML_SCHEMAS_LONG) &&
4944 (val->type != XML_SCHEMAS_ULONG) &&
4945 (val->type != XML_SCHEMAS_SHORT) &&
4946 (val->type != XML_SCHEMAS_USHORT) &&
4947 (val->type != XML_SCHEMAS_BYTE) &&
4948 (val->type != XML_SCHEMAS_UBYTE))) {
4949 return(-1);
4950 }
4951 if (facet->type == XML_SCHEMA_FACET_TOTALDIGITS) {
4952 if (val->value.decimal.total > facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004953 return(XML_SCHEMAV_CVC_TOTALDIGITS_VALID);
Daniel Veillard560c2a42003-07-06 21:13:49 +00004954
4955 } else if (facet->type == XML_SCHEMA_FACET_FRACTIONDIGITS) {
4956 if (val->value.decimal.frac > facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004957 return(XML_SCHEMAV_CVC_FRACTIONDIGITS_VALID);
Daniel Veillard560c2a42003-07-06 21:13:49 +00004958 }
4959 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00004960 default:
4961 TODO
4962 }
4963 return(0);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00004964
Daniel Veillard4255d502002-04-16 15:50:10 +00004965}
4966
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004967/**
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004968 * xmlSchemaValidateFacet:
4969 * @base: the base type
4970 * @facet: the facet to check
4971 * @value: the lexical repr of the value to validate
4972 * @val: the precomputed value
4973 *
4974 * Check a value against a facet condition
4975 *
4976 * Returns 0 if the element is schemas valid, a positive error code
4977 * number otherwise and -1 in case of internal or API error.
4978 */
4979int
Kasimier T. Buchcik9dbb0ce2005-03-16 16:39:23 +00004980xmlSchemaValidateFacet(xmlSchemaTypePtr base,
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004981 xmlSchemaFacetPtr facet,
4982 const xmlChar *value,
4983 xmlSchemaValPtr val)
4984{
4985 /*
4986 * This tries to ensure API compatibility regarding the old
4987 * xmlSchemaValidateFacet() and the new xmlSchemaValidateFacetInternal() and
4988 * xmlSchemaValidateFacetWhtsp().
4989 */
Kasimier T. Buchcik9dbb0ce2005-03-16 16:39:23 +00004990 if (val != NULL)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004991 return(xmlSchemaValidateFacetInternal(facet,
Kasimier T. Buchcik9dbb0ce2005-03-16 16:39:23 +00004992 XML_SCHEMA_WHITESPACE_UNKNOWN, val->type, value, val,
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004993 XML_SCHEMA_WHITESPACE_UNKNOWN));
Kasimier T. Buchcik9dbb0ce2005-03-16 16:39:23 +00004994 else if (base != NULL)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004995 return(xmlSchemaValidateFacetInternal(facet,
Kasimier T. Buchcik9dbb0ce2005-03-16 16:39:23 +00004996 XML_SCHEMA_WHITESPACE_UNKNOWN, base->builtInType, value, val,
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004997 XML_SCHEMA_WHITESPACE_UNKNOWN));
Kasimier T. Buchcik9dbb0ce2005-03-16 16:39:23 +00004998 return(-1);
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004999}
5000
5001/**
5002 * xmlSchemaValidateFacetWhtsp:
5003 * @facet: the facet to check
5004 * @fws: the whitespace type of the facet's value
5005 * @valType: the built-in type of the value
5006 * @value: the lexical (or normalized for pattern) repr of the value to validate
5007 * @val: the precomputed value
5008 * @ws: the whitespace type of the value
5009 *
5010 * Check a value against a facet condition. This takes value normalization
5011 * according to the specified whitespace types into account.
5012 * Note that @value needs to be the *normalized* value if the facet
5013 * is of type "pattern".
5014 *
5015 * Returns 0 if the element is schemas valid, a positive error code
5016 * number otherwise and -1 in case of internal or API error.
5017 */
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005018int
5019xmlSchemaValidateFacetWhtsp(xmlSchemaFacetPtr facet,
5020 xmlSchemaWhitespaceValueType fws,
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005021 xmlSchemaValType valType,
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005022 const xmlChar *value,
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005023 xmlSchemaValPtr val,
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005024 xmlSchemaWhitespaceValueType ws)
5025{
5026 return(xmlSchemaValidateFacetInternal(facet, fws, valType,
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005027 value, val, ws));
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005028}
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005029
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00005030#if 0
5031#ifndef DBL_DIG
5032#define DBL_DIG 16
5033#endif
5034#ifndef DBL_EPSILON
5035#define DBL_EPSILON 1E-9
5036#endif
5037
5038#define INTEGER_DIGITS DBL_DIG
5039#define FRACTION_DIGITS (DBL_DIG + 1)
5040#define EXPONENT_DIGITS (3 + 2)
5041
5042/**
5043 * xmlXPathFormatNumber:
5044 * @number: number to format
5045 * @buffer: output buffer
5046 * @buffersize: size of output buffer
5047 *
5048 * Convert the number into a string representation.
5049 */
5050static void
5051xmlSchemaFormatFloat(double number, char buffer[], int buffersize)
5052{
5053 switch (xmlXPathIsInf(number)) {
5054 case 1:
5055 if (buffersize > (int)sizeof("INF"))
5056 snprintf(buffer, buffersize, "INF");
5057 break;
5058 case -1:
5059 if (buffersize > (int)sizeof("-INF"))
5060 snprintf(buffer, buffersize, "-INF");
5061 break;
5062 default:
5063 if (xmlXPathIsNaN(number)) {
5064 if (buffersize > (int)sizeof("NaN"))
5065 snprintf(buffer, buffersize, "NaN");
5066 } else if (number == 0) {
5067 snprintf(buffer, buffersize, "0.0E0");
5068 } else {
5069 /* 3 is sign, decimal point, and terminating zero */
5070 char work[DBL_DIG + EXPONENT_DIGITS + 3];
5071 int integer_place, fraction_place;
5072 char *ptr;
5073 char *after_fraction;
5074 double absolute_value;
5075 int size;
5076
5077 absolute_value = fabs(number);
5078
5079 /*
5080 * Result is in work, and after_fraction points
5081 * just past the fractional part.
5082 * Use scientific notation
5083 */
5084 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
5085 fraction_place = DBL_DIG - 1;
5086 snprintf(work, sizeof(work),"%*.*e",
5087 integer_place, fraction_place, number);
5088 after_fraction = strchr(work + DBL_DIG, 'e');
5089 /* Remove fractional trailing zeroes */
5090 ptr = after_fraction;
5091 while (*(--ptr) == '0')
5092 ;
5093 if (*ptr != '.')
5094 ptr++;
5095 while ((*ptr++ = *after_fraction++) != 0);
5096
5097 /* Finally copy result back to caller */
5098 size = strlen(work) + 1;
5099 if (size > buffersize) {
5100 work[buffersize - 1] = 0;
5101 size = buffersize;
5102 }
5103 memmove(buffer, work, size);
5104 }
5105 break;
5106 }
5107}
5108#endif
5109
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005110/**
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00005111 * xmlSchemaGetCanonValue:
5112 * @val: the precomputed value
5113 * @retValue: the returned value
5114 *
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005115 * Get a the cononical lexical representation of the value.
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00005116 * The caller has to FREE the returned retValue.
5117 *
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005118 * WARNING: Some value types are not supported yet, resulting
5119 * in a @retValue of "???".
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00005120 *
5121 * TODO: XML Schema 1.0 does not define canonical representations
5122 * for: duration, gYearMonth, gYear, gMonthDay, gMonth, gDay,
5123 * anyURI, QName, NOTATION. This will be fixed in XML Schema 1.1.
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00005124 *
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00005125 *
5126 * Returns 0 if the value could be built, 1 if the value type is
5127 * not supported yet and -1 in case of API errors.
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00005128 */
5129int
Daniel Veillardb5839c32005-02-19 18:27:14 +00005130xmlSchemaGetCanonValue(xmlSchemaValPtr val, const xmlChar **retValue)
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00005131{
Daniel Veillardb5839c32005-02-19 18:27:14 +00005132 if ((retValue == NULL) || (val == NULL))
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00005133 return (-1);
5134 *retValue = NULL;
5135 switch (val->type) {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005136 case XML_SCHEMAS_STRING:
5137 if (val->value.str == NULL)
5138 *retValue = BAD_CAST xmlStrdup(BAD_CAST "");
5139 else
5140 *retValue =
5141 BAD_CAST xmlStrdup((const xmlChar *) val->value.str);
5142 break;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00005143 case XML_SCHEMAS_NORMSTRING:
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005144 if (val->value.str == NULL)
5145 *retValue = BAD_CAST xmlStrdup(BAD_CAST "");
5146 else {
5147 *retValue = xmlSchemaWhiteSpaceReplace(
5148 (const xmlChar *) val->value.str);
5149 if ((*retValue) == NULL)
5150 *retValue = BAD_CAST xmlStrdup(
5151 (const xmlChar *) val->value.str);
5152 }
5153 break;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00005154 case XML_SCHEMAS_TOKEN:
5155 case XML_SCHEMAS_LANGUAGE:
5156 case XML_SCHEMAS_NMTOKEN:
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005157 case XML_SCHEMAS_NAME:
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00005158 case XML_SCHEMAS_NCNAME:
5159 case XML_SCHEMAS_ID:
5160 case XML_SCHEMAS_IDREF:
5161 case XML_SCHEMAS_ENTITY:
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00005162 case XML_SCHEMAS_NOTATION: /* Unclear */
5163 case XML_SCHEMAS_ANYURI: /* Unclear */
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00005164 if (val->value.str == NULL)
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005165 return (-1);
Kasimier T. Buchcikaba15f72005-04-01 15:17:27 +00005166 *retValue =
5167 BAD_CAST xmlSchemaCollapseString(BAD_CAST val->value.str);
5168 if (*retValue == NULL)
5169 *retValue =
5170 BAD_CAST xmlStrdup((const xmlChar *) val->value.str);
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005171 break;
5172 case XML_SCHEMAS_QNAME:
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00005173 /* TODO: Unclear in XML Schema 1.0. */
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005174 if (val->value.qname.uri == NULL) {
5175 *retValue = BAD_CAST xmlStrdup(BAD_CAST val->value.qname.name);
5176 return (0);
5177 } else {
5178 *retValue = BAD_CAST xmlStrdup(BAD_CAST "{");
5179 *retValue = BAD_CAST xmlStrcat((xmlChar *) (*retValue),
5180 BAD_CAST val->value.qname.uri);
5181 *retValue = BAD_CAST xmlStrcat((xmlChar *) (*retValue),
5182 BAD_CAST "}");
5183 *retValue = BAD_CAST xmlStrcat((xmlChar *) (*retValue),
5184 BAD_CAST val->value.qname.uri);
5185 }
5186 break;
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00005187 case XML_SCHEMAS_DECIMAL:
5188 /*
5189 * TODO: Lookout for a more simple implementation.
5190 */
5191 if ((val->value.decimal.total == 1) &&
5192 (val->value.decimal.lo == 0)) {
5193 *retValue = xmlStrdup(BAD_CAST "0.0");
5194 } else {
5195 xmlSchemaValDecimal dec = val->value.decimal;
5196 int bufsize;
5197 char *buf = NULL, *offs;
5198
5199 /* Add room for the decimal point as well. */
5200 bufsize = dec.total + 2;
5201 if (dec.sign)
5202 bufsize++;
5203 /* Add room for leading/trailing zero. */
5204 if ((dec.frac == 0) || (dec.frac == dec.total))
5205 bufsize++;
5206 buf = xmlMalloc(bufsize);
5207 offs = buf;
5208 if (dec.sign)
5209 *offs++ = '-';
5210 if (dec.frac == dec.total) {
5211 *offs++ = '0';
5212 *offs++ = '.';
5213 }
5214 if (dec.hi != 0)
5215 snprintf(offs, bufsize - (offs - buf),
5216 "%lu%lu%lu", dec.hi, dec.mi, dec.lo);
5217 else if (dec.mi != 0)
5218 snprintf(offs, bufsize - (offs - buf),
5219 "%lu%lu", dec.mi, dec.lo);
5220 else
5221 snprintf(offs, bufsize - (offs - buf),
5222 "%lu", dec.lo);
5223
5224 if (dec.frac != 0) {
5225 if (dec.frac != dec.total) {
5226 int diff = dec.total - dec.frac;
5227 /*
5228 * Insert the decimal point.
5229 */
5230 memmove(offs + diff + 1, offs + diff, dec.frac +1);
5231 offs[diff] = '.';
5232 } else {
5233 unsigned int i = 0;
5234 /*
5235 * Insert missing zeroes behind the decimal point.
5236 */
5237 while (*(offs + i) != 0)
5238 i++;
5239 if (i < dec.total) {
5240 memmove(offs + (dec.total - i), offs, i +1);
5241 memset(offs, '0', dec.total - i);
5242 }
5243 }
5244 } else {
5245 /*
5246 * Append decimal point and zero.
5247 */
5248 offs = buf + bufsize - 1;
5249 *offs-- = 0;
5250 *offs-- = '0';
5251 *offs-- = '.';
5252 }
5253 *retValue = BAD_CAST buf;
5254 }
5255 break;
5256 case XML_SCHEMAS_INTEGER:
5257 case XML_SCHEMAS_PINTEGER:
5258 case XML_SCHEMAS_NPINTEGER:
5259 case XML_SCHEMAS_NINTEGER:
5260 case XML_SCHEMAS_NNINTEGER:
5261 case XML_SCHEMAS_LONG:
5262 case XML_SCHEMAS_BYTE:
5263 case XML_SCHEMAS_SHORT:
5264 case XML_SCHEMAS_INT:
5265 case XML_SCHEMAS_UINT:
5266 case XML_SCHEMAS_ULONG:
5267 case XML_SCHEMAS_USHORT:
5268 case XML_SCHEMAS_UBYTE:
5269 if ((val->value.decimal.total == 1) &&
5270 (val->value.decimal.lo == 0))
5271 *retValue = xmlStrdup(BAD_CAST "0");
5272 else {
5273 xmlSchemaValDecimal dec = val->value.decimal;
5274 int bufsize = dec.total + 1;
5275
5276 /* Add room for the decimal point as well. */
5277 if (dec.sign)
5278 bufsize++;
5279 *retValue = xmlMalloc(bufsize);
5280 if (dec.hi != 0) {
5281 if (dec.sign)
5282 snprintf((char *) *retValue, bufsize,
5283 "-%lu%lu%lu", dec.hi, dec.mi, dec.lo);
5284 else
5285 snprintf((char *) *retValue, bufsize,
5286 "%lu%lu%lu", dec.hi, dec.mi, dec.lo);
5287 } else if (dec.mi != 0) {
5288 if (dec.sign)
5289 snprintf((char *) *retValue, bufsize,
5290 "-%lu%lu", dec.mi, dec.lo);
5291 else
5292 snprintf((char *) *retValue, bufsize,
5293 "%lu%lu", dec.mi, dec.lo);
5294 } else {
5295 if (dec.sign)
5296 snprintf((char *) *retValue, bufsize, "-%lu", dec.lo);
5297 else
5298 snprintf((char *) *retValue, bufsize, "%lu", dec.lo);
5299 }
5300 }
5301 break;
5302 case XML_SCHEMAS_BOOLEAN:
5303 if (val->value.b)
5304 *retValue = BAD_CAST xmlStrdup(BAD_CAST "true");
5305 else
5306 *retValue = BAD_CAST xmlStrdup(BAD_CAST "false");
5307 break;
5308 case XML_SCHEMAS_DURATION: {
5309 char buf[100];
5310 unsigned long year;
5311 unsigned long mon, day, hour = 0, min = 0;
5312 double sec = 0, left;
5313
5314 /* TODO: Unclear in XML Schema 1.0 */
5315 /*
5316 * TODO: This results in a normalized output of the value
5317 * - which is NOT conformant to the spec -
5318 * since the exact values of each property are not
5319 * recoverable. Think about extending the structure to
5320 * provide a field for every property.
5321 */
5322 year = (unsigned long) FQUOTIENT(labs(val->value.dur.mon), 12);
5323 mon = labs(val->value.dur.mon) - 12 * year;
5324
5325 day = (unsigned long) FQUOTIENT(fabs(val->value.dur.sec), 86400);
5326 left = fabs(val->value.dur.sec) - day * 86400;
5327 if (left > 0) {
5328 hour = (unsigned long) FQUOTIENT(left, 3600);
5329 left = left - (hour * 3600);
5330 if (left > 0) {
5331 min = (unsigned long) FQUOTIENT(left, 60);
5332 sec = left - (min * 60);
5333 }
5334 }
5335 if ((val->value.dur.mon < 0) || (val->value.dur.sec < 0))
5336 snprintf(buf, 100, "P%luY%luM%luDT%luH%luM%.14gS",
5337 year, mon, day, hour, min, sec);
5338 else
5339 snprintf(buf, 100, "-P%luY%luM%luDT%luH%luM%.14gS",
5340 year, mon, day, hour, min, sec);
5341 *retValue = BAD_CAST xmlStrdup(BAD_CAST buf);
5342 }
5343 break;
5344 case XML_SCHEMAS_GYEAR: {
5345 char buf[30];
5346 /* TODO: Unclear in XML Schema 1.0 */
5347 /* TODO: What to do with the timezone? */
5348 snprintf(buf, 30, "%04ld", val->value.date.year);
5349 *retValue = BAD_CAST xmlStrdup(BAD_CAST buf);
5350 }
5351 break;
5352 case XML_SCHEMAS_GMONTH: {
5353 /* TODO: Unclear in XML Schema 1.0 */
5354 /* TODO: What to do with the timezone? */
5355 *retValue = xmlMalloc(5);
5356 snprintf((char *) *retValue, 6, "--%02u",
5357 val->value.date.mon);
5358 }
5359 break;
5360 case XML_SCHEMAS_GDAY: {
5361 /* TODO: Unclear in XML Schema 1.0 */
5362 /* TODO: What to do with the timezone? */
5363 *retValue = xmlMalloc(6);
5364 snprintf((char *) *retValue, 6, "---%02u",
5365 val->value.date.day);
5366 }
5367 break;
5368 case XML_SCHEMAS_GMONTHDAY: {
5369 /* TODO: Unclear in XML Schema 1.0 */
5370 /* TODO: What to do with the timezone? */
5371 *retValue = xmlMalloc(8);
5372 snprintf((char *) *retValue, 8, "--%02u-%02u",
5373 val->value.date.mon, val->value.date.day);
5374 }
5375 break;
5376 case XML_SCHEMAS_GYEARMONTH: {
5377 char buf[35];
5378 /* TODO: Unclear in XML Schema 1.0 */
5379 /* TODO: What to do with the timezone? */
5380 if (val->value.date.year < 0)
5381 snprintf(buf, 35, "-%04ld-%02u",
5382 labs(val->value.date.year),
5383 val->value.date.mon);
5384 else
5385 snprintf(buf, 35, "%04ld-%02u",
5386 val->value.date.year, val->value.date.mon);
5387 *retValue = BAD_CAST xmlStrdup(BAD_CAST buf);
5388 }
5389 break;
5390 case XML_SCHEMAS_TIME:
5391 {
5392 char buf[30];
5393
5394 if (val->value.date.tz_flag) {
5395 xmlSchemaValPtr norm;
5396
5397 norm = xmlSchemaDateNormalize(val, 0);
5398 if (norm == NULL)
5399 return (-1);
5400 /*
5401 * TODO: Check if "%.14g" is portable.
5402 */
5403 snprintf(buf, 30,
5404 "%02u:%02u:%02.14gZ",
5405 norm->value.date.hour,
5406 norm->value.date.min,
5407 norm->value.date.sec);
5408 xmlSchemaFreeValue(norm);
5409 } else {
5410 snprintf(buf, 30,
5411 "%02u:%02u:%02.14g",
5412 val->value.date.hour,
5413 val->value.date.min,
5414 val->value.date.sec);
5415 }
5416 *retValue = BAD_CAST xmlStrdup(BAD_CAST buf);
5417 }
5418 break;
5419 case XML_SCHEMAS_DATE:
5420 {
5421 char buf[30];
5422
5423 if (val->value.date.tz_flag) {
5424 xmlSchemaValPtr norm;
5425
5426 norm = xmlSchemaDateNormalize(val, 0);
5427 if (norm == NULL)
5428 return (-1);
5429 /*
5430 * TODO: Append the canonical value of the
5431 * recoverable timezone and not "Z".
5432 */
5433 snprintf(buf, 30,
5434 "%04ld:%02u:%02uZ",
5435 norm->value.date.year, norm->value.date.mon,
5436 norm->value.date.day);
5437 xmlSchemaFreeValue(norm);
5438 } else {
5439 snprintf(buf, 30,
5440 "%04ld:%02u:%02u",
5441 val->value.date.year, val->value.date.mon,
5442 val->value.date.day);
5443 }
5444 *retValue = BAD_CAST xmlStrdup(BAD_CAST buf);
5445 }
5446 break;
5447 case XML_SCHEMAS_DATETIME:
5448 {
5449 char buf[50];
5450
5451 if (val->value.date.tz_flag) {
5452 xmlSchemaValPtr norm;
5453
5454 norm = xmlSchemaDateNormalize(val, 0);
5455 if (norm == NULL)
5456 return (-1);
5457 /*
5458 * TODO: Check if "%.14g" is portable.
5459 */
5460 snprintf(buf, 50,
5461 "%04ld:%02u:%02uT%02u:%02u:%02.14gZ",
5462 norm->value.date.year, norm->value.date.mon,
5463 norm->value.date.day, norm->value.date.hour,
5464 norm->value.date.min, norm->value.date.sec);
5465 xmlSchemaFreeValue(norm);
5466 } else {
5467 snprintf(buf, 50,
5468 "%04ld:%02u:%02uT%02u:%02u:%02.14g",
5469 val->value.date.year, val->value.date.mon,
5470 val->value.date.day, val->value.date.hour,
5471 val->value.date.min, val->value.date.sec);
5472 }
5473 *retValue = BAD_CAST xmlStrdup(BAD_CAST buf);
5474 }
5475 break;
5476 case XML_SCHEMAS_HEXBINARY:
5477 *retValue = BAD_CAST xmlStrdup(BAD_CAST val->value.hex.str);
5478 break;
5479 case XML_SCHEMAS_BASE64BINARY:
5480 /*
5481 * TODO: Is the following spec piece implemented?:
5482 * SPEC: "Note: For some values the canonical form defined
5483 * above does not conform to [RFC 2045], which requires breaking
5484 * with linefeeds at appropriate intervals."
5485 */
5486 *retValue = BAD_CAST xmlStrdup(BAD_CAST val->value.base64.str);
5487 break;
5488 case XML_SCHEMAS_FLOAT: {
5489 char buf[30];
5490 /*
5491 * |m| < 16777216, -149 <= e <= 104.
5492 * TODO: Handle, NaN, INF, -INF. The format is not
5493 * yet conformant. The c type float does not cover
5494 * the whole range.
5495 */
5496 snprintf(buf, 30, "%01.14e", val->value.f);
5497 *retValue = BAD_CAST xmlStrdup(BAD_CAST buf);
5498 }
5499 break;
5500 case XML_SCHEMAS_DOUBLE: {
5501 char buf[40];
5502 /* |m| < 9007199254740992, -1075 <= e <= 970 */
5503 /*
5504 * TODO: Handle, NaN, INF, -INF. The format is not
5505 * yet conformant. The c type float does not cover
5506 * the whole range.
5507 */
5508 snprintf(buf, 40, "%01.14e", val->value.d);
5509 *retValue = BAD_CAST xmlStrdup(BAD_CAST buf);
5510 }
5511 break;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00005512 default:
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005513 *retValue = BAD_CAST xmlStrdup(BAD_CAST "???");
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00005514 return (1);
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00005515 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005516 return (0);
5517}
5518
Daniel Veillardbda59572005-04-01 17:15:17 +00005519/**
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00005520 * xmlSchemaGetCanonValueWhtsp:
5521 * @val: the precomputed value
5522 * @retValue: the returned value
5523 * @ws: the whitespace type of the value
5524 *
5525 * Get a the cononical representation of the value.
5526 * The caller has to free the returned @retValue.
5527 *
5528 * Returns 0 if the value could be built, 1 if the value type is
5529 * not supported yet and -1 in case of API errors.
5530 */
5531int
5532xmlSchemaGetCanonValueWhtsp(xmlSchemaValPtr val,
5533 const xmlChar **retValue,
5534 xmlSchemaWhitespaceValueType ws)
5535{
5536 if ((retValue == NULL) || (val == NULL))
5537 return (-1);
5538 if ((ws == XML_SCHEMA_WHITESPACE_UNKNOWN) ||
5539 (ws > XML_SCHEMA_WHITESPACE_COLLAPSE))
5540 return (-1);
5541
5542 *retValue = NULL;
5543 switch (val->type) {
5544 case XML_SCHEMAS_STRING:
5545 if (val->value.str == NULL)
5546 *retValue = BAD_CAST xmlStrdup(BAD_CAST "");
5547 else if (ws == XML_SCHEMA_WHITESPACE_COLLAPSE)
5548 *retValue = xmlSchemaCollapseString(val->value.str);
5549 else if (ws == XML_SCHEMA_WHITESPACE_REPLACE)
5550 *retValue = xmlSchemaWhiteSpaceReplace(val->value.str);
5551 if ((*retValue) == NULL)
5552 *retValue = BAD_CAST xmlStrdup(val->value.str);
5553 break;
5554 case XML_SCHEMAS_NORMSTRING:
5555 if (val->value.str == NULL)
5556 *retValue = BAD_CAST xmlStrdup(BAD_CAST "");
5557 else {
5558 if (ws == XML_SCHEMA_WHITESPACE_COLLAPSE)
5559 *retValue = xmlSchemaCollapseString(val->value.str);
5560 else
5561 *retValue = xmlSchemaWhiteSpaceReplace(val->value.str);
5562 if ((*retValue) == NULL)
5563 *retValue = BAD_CAST xmlStrdup(val->value.str);
5564 }
5565 break;
5566 default:
5567 return (xmlSchemaGetCanonValue(val, retValue));
5568 }
5569 return (0);
5570}
5571
5572/**
Daniel Veillardbda59572005-04-01 17:15:17 +00005573 * xmlSchemaGetValType:
5574 * @val: a schemas value
5575 *
5576 * Accessor for the type of a value
5577 *
5578 * Returns the xmlSchemaValType of the value
5579 */
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005580xmlSchemaValType
5581xmlSchemaGetValType(xmlSchemaValPtr val)
5582{
Daniel Veillardbda59572005-04-01 17:15:17 +00005583 if (val == NULL)
5584 return(XML_SCHEMAS_UNKNOWN);
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005585 return (val->type);
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00005586}
5587
Daniel Veillard5d4644e2005-04-01 13:11:58 +00005588#define bottom_xmlschemastypes
5589#include "elfgcchack.h"
Daniel Veillard4255d502002-04-16 15:50:10 +00005590#endif /* LIBXML_SCHEMAS_ENABLED */