blob: c6cc62dd2b07e434dea4407bc571a18606522c14 [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? */
Kasimier T. Buchcik285b3672005-05-12 13:10:22 +000069 signed int tzo :12; /* -1440 <= tzo <= 1440;
70 currently only -840 to +840 are needed */
Daniel Veillard070803b2002-05-03 07:29:38 +000071};
72
73/* Duration value */
74typedef struct _xmlSchemaValDuration xmlSchemaValDuration;
75typedef xmlSchemaValDuration *xmlSchemaValDurationPtr;
76struct _xmlSchemaValDuration {
77 long mon; /* mon stores years also */
78 long day;
79 double sec; /* sec stores min and hour also */
80};
81
Daniel Veillard4255d502002-04-16 15:50:10 +000082typedef struct _xmlSchemaValDecimal xmlSchemaValDecimal;
83typedef xmlSchemaValDecimal *xmlSchemaValDecimalPtr;
84struct _xmlSchemaValDecimal {
85 /* would use long long but not portable */
Daniel Veillarde637c4a2003-03-30 21:10:09 +000086 unsigned long lo;
87 unsigned long mi;
88 unsigned long hi;
Daniel Veillard4255d502002-04-16 15:50:10 +000089 unsigned int extra;
Daniel Veillard5a872412002-05-22 06:40:27 +000090 unsigned int sign:1;
William M. Brackc1939562003-08-05 15:52:22 +000091 unsigned int frac:7;
92 unsigned int total:8;
Daniel Veillard4255d502002-04-16 15:50:10 +000093};
94
Daniel Veillarde637c4a2003-03-30 21:10:09 +000095typedef struct _xmlSchemaValQName xmlSchemaValQName;
96typedef xmlSchemaValQName *xmlSchemaValQNamePtr;
97struct _xmlSchemaValQName {
98 xmlChar *name;
99 xmlChar *uri;
100};
101
Daniel Veillard70bcb0e2003-08-08 14:00:28 +0000102typedef struct _xmlSchemaValHex xmlSchemaValHex;
103typedef xmlSchemaValHex *xmlSchemaValHexPtr;
104struct _xmlSchemaValHex {
105 xmlChar *str;
106 unsigned int total;
107};
108
Daniel Veillard1ac24d32003-08-27 14:15:15 +0000109typedef struct _xmlSchemaValBase64 xmlSchemaValBase64;
110typedef xmlSchemaValBase64 *xmlSchemaValBase64Ptr;
111struct _xmlSchemaValBase64 {
112 xmlChar *str;
113 unsigned int total;
114};
115
Daniel Veillard4255d502002-04-16 15:50:10 +0000116struct _xmlSchemaVal {
117 xmlSchemaValType type;
118 union {
Daniel Veillard5a872412002-05-22 06:40:27 +0000119 xmlSchemaValDecimal decimal;
Daniel Veillard070803b2002-05-03 07:29:38 +0000120 xmlSchemaValDate date;
121 xmlSchemaValDuration dur;
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000122 xmlSchemaValQName qname;
Daniel Veillard70bcb0e2003-08-08 14:00:28 +0000123 xmlSchemaValHex hex;
Daniel Veillard1ac24d32003-08-27 14:15:15 +0000124 xmlSchemaValBase64 base64;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000125 float f;
126 double d;
Daniel Veillardc5a70f22003-02-06 23:41:59 +0000127 int b;
Daniel Veillardc4c21552003-03-29 10:53:38 +0000128 xmlChar *str;
Daniel Veillard4255d502002-04-16 15:50:10 +0000129 } value;
130};
131
132static int xmlSchemaTypesInitialized = 0;
133static xmlHashTablePtr xmlSchemaTypesBank = NULL;
134
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000135/*
136 * Basic types
137 */
Daniel Veillard4255d502002-04-16 15:50:10 +0000138static xmlSchemaTypePtr xmlSchemaTypeStringDef = NULL;
139static xmlSchemaTypePtr xmlSchemaTypeAnyTypeDef = NULL;
140static xmlSchemaTypePtr xmlSchemaTypeAnySimpleTypeDef = NULL;
141static xmlSchemaTypePtr xmlSchemaTypeDecimalDef = NULL;
Daniel Veillard070803b2002-05-03 07:29:38 +0000142static xmlSchemaTypePtr xmlSchemaTypeDatetimeDef = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +0000143static xmlSchemaTypePtr xmlSchemaTypeDateDef = NULL;
Daniel Veillard070803b2002-05-03 07:29:38 +0000144static xmlSchemaTypePtr xmlSchemaTypeTimeDef = NULL;
145static xmlSchemaTypePtr xmlSchemaTypeGYearDef = NULL;
146static xmlSchemaTypePtr xmlSchemaTypeGYearMonthDef = NULL;
147static xmlSchemaTypePtr xmlSchemaTypeGDayDef = NULL;
148static xmlSchemaTypePtr xmlSchemaTypeGMonthDayDef = NULL;
149static xmlSchemaTypePtr xmlSchemaTypeGMonthDef = NULL;
150static xmlSchemaTypePtr xmlSchemaTypeDurationDef = NULL;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000151static xmlSchemaTypePtr xmlSchemaTypeFloatDef = NULL;
Daniel Veillardc5a70f22003-02-06 23:41:59 +0000152static xmlSchemaTypePtr xmlSchemaTypeBooleanDef = NULL;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000153static xmlSchemaTypePtr xmlSchemaTypeDoubleDef = NULL;
Daniel Veillard560c2a42003-07-06 21:13:49 +0000154static xmlSchemaTypePtr xmlSchemaTypeHexBinaryDef = NULL;
Daniel Veillard1ac24d32003-08-27 14:15:15 +0000155static xmlSchemaTypePtr xmlSchemaTypeBase64BinaryDef = NULL;
Daniel Veillarde5b110b2003-02-04 14:43:39 +0000156static xmlSchemaTypePtr xmlSchemaTypeAnyURIDef = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +0000157
158/*
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000159 * Derived types
160 */
161static xmlSchemaTypePtr xmlSchemaTypePositiveIntegerDef = NULL;
162static xmlSchemaTypePtr xmlSchemaTypeNonPositiveIntegerDef = NULL;
163static xmlSchemaTypePtr xmlSchemaTypeNegativeIntegerDef = NULL;
164static xmlSchemaTypePtr xmlSchemaTypeNonNegativeIntegerDef = NULL;
165static xmlSchemaTypePtr xmlSchemaTypeIntegerDef = NULL;
166static xmlSchemaTypePtr xmlSchemaTypeLongDef = NULL;
167static xmlSchemaTypePtr xmlSchemaTypeIntDef = NULL;
168static xmlSchemaTypePtr xmlSchemaTypeShortDef = NULL;
169static xmlSchemaTypePtr xmlSchemaTypeByteDef = NULL;
170static xmlSchemaTypePtr xmlSchemaTypeUnsignedLongDef = NULL;
171static xmlSchemaTypePtr xmlSchemaTypeUnsignedIntDef = NULL;
172static xmlSchemaTypePtr xmlSchemaTypeUnsignedShortDef = NULL;
173static xmlSchemaTypePtr xmlSchemaTypeUnsignedByteDef = NULL;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000174static xmlSchemaTypePtr xmlSchemaTypeNormStringDef = NULL;
175static xmlSchemaTypePtr xmlSchemaTypeTokenDef = NULL;
176static xmlSchemaTypePtr xmlSchemaTypeLanguageDef = NULL;
177static xmlSchemaTypePtr xmlSchemaTypeNameDef = NULL;
178static xmlSchemaTypePtr xmlSchemaTypeQNameDef = NULL;
Daniel Veillarde5b110b2003-02-04 14:43:39 +0000179static xmlSchemaTypePtr xmlSchemaTypeNCNameDef = NULL;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000180static xmlSchemaTypePtr xmlSchemaTypeIdDef = NULL;
181static xmlSchemaTypePtr xmlSchemaTypeIdrefDef = NULL;
182static xmlSchemaTypePtr xmlSchemaTypeIdrefsDef = NULL;
Daniel Veillarda1a9d042003-03-18 16:53:17 +0000183static xmlSchemaTypePtr xmlSchemaTypeEntityDef = NULL;
184static xmlSchemaTypePtr xmlSchemaTypeEntitiesDef = NULL;
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000185static xmlSchemaTypePtr xmlSchemaTypeNotationDef = NULL;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000186static xmlSchemaTypePtr xmlSchemaTypeNmtokenDef = NULL;
187static xmlSchemaTypePtr xmlSchemaTypeNmtokensDef = NULL;
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000188
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000189/************************************************************************
190 * *
191 * Datatype error handlers *
192 * *
193 ************************************************************************/
194/**
195 * xmlSchemaTypeErrMemory:
196 * @extra: extra informations
197 *
198 * Handle an out of memory condition
199 */
200static void
201xmlSchemaTypeErrMemory(xmlNodePtr node, const char *extra)
202{
203 __xmlSimpleError(XML_FROM_DATATYPE, XML_ERR_NO_MEMORY, node, NULL, extra);
204}
205
206/************************************************************************
207 * *
208 * Base types support *
209 * *
210 ************************************************************************/
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000211/*
Daniel Veillard4255d502002-04-16 15:50:10 +0000212 * xmlSchemaInitBasicType:
213 * @name: the type name
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000214 * @type: the value type associated
Daniel Veillard4255d502002-04-16 15:50:10 +0000215 *
Daniel Veillard01fa6152004-06-29 17:04:39 +0000216 * Initialize one primitive built-in type
Daniel Veillard4255d502002-04-16 15:50:10 +0000217 */
218static xmlSchemaTypePtr
Daniel Veillard01fa6152004-06-29 17:04:39 +0000219xmlSchemaInitBasicType(const char *name, xmlSchemaValType type,
220 xmlSchemaTypePtr baseType) {
Daniel Veillard4255d502002-04-16 15:50:10 +0000221 xmlSchemaTypePtr ret;
222
223 ret = (xmlSchemaTypePtr) xmlMalloc(sizeof(xmlSchemaType));
224 if (ret == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000225 xmlSchemaTypeErrMemory(NULL, "could not initialize basic types");
Daniel Veillard4255d502002-04-16 15:50:10 +0000226 return(NULL);
227 }
228 memset(ret, 0, sizeof(xmlSchemaType));
Daniel Veillardbe9c6322003-11-22 20:37:51 +0000229 ret->name = (const xmlChar *)name;
Daniel Veillard4255d502002-04-16 15:50:10 +0000230 ret->type = XML_SCHEMA_TYPE_BASIC;
Daniel Veillard01fa6152004-06-29 17:04:39 +0000231 ret->baseType = baseType;
232 /*
233 * Hack to reflect the variety.
234 */
235 if ((type == XML_SCHEMAS_IDREFS) ||
236 (type == XML_SCHEMAS_NMTOKENS) ||
237 (type == XML_SCHEMAS_ENTITIES))
238 ret->flags |= XML_SCHEMAS_TYPE_VARIETY_LIST;
William M. Brack2f2a6632004-08-20 23:09:47 +0000239 else if ((type != XML_SCHEMAS_ANYTYPE) &&
240 (type != XML_SCHEMAS_ANYSIMPLETYPE))
Daniel Veillard01fa6152004-06-29 17:04:39 +0000241 ret->flags |= XML_SCHEMAS_TYPE_VARIETY_ATOMIC;
Daniel Veillard4255d502002-04-16 15:50:10 +0000242 ret->contentType = XML_SCHEMA_CONTENT_BASIC;
Daniel Veillard01fa6152004-06-29 17:04:39 +0000243 switch (type) {
244 case XML_SCHEMAS_STRING:
245 case XML_SCHEMAS_DECIMAL:
246 case XML_SCHEMAS_DATE:
247 case XML_SCHEMAS_DATETIME:
248 case XML_SCHEMAS_TIME:
249 case XML_SCHEMAS_GYEAR:
250 case XML_SCHEMAS_GYEARMONTH:
251 case XML_SCHEMAS_GMONTH:
252 case XML_SCHEMAS_GMONTHDAY:
253 case XML_SCHEMAS_GDAY:
254 case XML_SCHEMAS_DURATION:
255 case XML_SCHEMAS_FLOAT:
256 case XML_SCHEMAS_DOUBLE:
257 case XML_SCHEMAS_BOOLEAN:
258 case XML_SCHEMAS_ANYURI:
259 case XML_SCHEMAS_HEXBINARY:
260 case XML_SCHEMAS_BASE64BINARY:
261 case XML_SCHEMAS_QNAME:
262 case XML_SCHEMAS_NOTATION:
263 ret->flags |= XML_SCHEMAS_TYPE_BUILTIN_PRIMITIVE;
William M. Brack96d2eff2004-06-30 11:48:47 +0000264 default:
265 break;
Daniel Veillard01fa6152004-06-29 17:04:39 +0000266 }
267
Daniel Veillard4255d502002-04-16 15:50:10 +0000268 xmlHashAddEntry2(xmlSchemaTypesBank, ret->name,
269 XML_SCHEMAS_NAMESPACE_NAME, ret);
Daniel Veillard01fa6152004-06-29 17:04:39 +0000270 ret->builtInType = type;
Daniel Veillard4255d502002-04-16 15:50:10 +0000271 return(ret);
272}
273
274/*
275 * xmlSchemaInitTypes:
276 *
277 * Initialize the default XML Schemas type library
278 */
279void
Daniel Veillard6560a422003-03-27 21:25:38 +0000280xmlSchemaInitTypes(void)
281{
Daniel Veillard4255d502002-04-16 15:50:10 +0000282 if (xmlSchemaTypesInitialized != 0)
Daniel Veillard6560a422003-03-27 21:25:38 +0000283 return;
Daniel Veillard4255d502002-04-16 15:50:10 +0000284 xmlSchemaTypesBank = xmlHashCreate(40);
Daniel Veillard6560a422003-03-27 21:25:38 +0000285
Daniel Veillard01fa6152004-06-29 17:04:39 +0000286
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000287 /*
Daniel Veillard01fa6152004-06-29 17:04:39 +0000288 * 3.4.7 Built-in Complex Type Definition
289 */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000290 xmlSchemaTypeAnyTypeDef = xmlSchemaInitBasicType("anyType",
William M. Brack2f2a6632004-08-20 23:09:47 +0000291 XML_SCHEMAS_ANYTYPE,
Daniel Veillard01fa6152004-06-29 17:04:39 +0000292 NULL);
293 xmlSchemaTypeAnyTypeDef->baseType = xmlSchemaTypeAnyTypeDef;
294 xmlSchemaTypeAnyTypeDef->contentType = XML_SCHEMA_CONTENT_MIXED;
295 {
296 xmlSchemaWildcardPtr wild;
297
298 wild = (xmlSchemaWildcardPtr) xmlMalloc(sizeof(xmlSchemaWildcard));
299 if (wild == NULL) {
William M. Brack2f2a6632004-08-20 23:09:47 +0000300 xmlSchemaTypeErrMemory(NULL, "could not create an attribute wildcard on anyType");
Daniel Veillard01fa6152004-06-29 17:04:39 +0000301 return;
302 }
303 memset(wild, 0, sizeof(xmlSchemaWildcard));
304 wild->any = 1;
305 wild->processContents = XML_SCHEMAS_ANY_LAX;
306 wild->minOccurs = 1;
307 wild->maxOccurs = 1;
308 xmlSchemaTypeAnyTypeDef->attributeWildcard = wild;
309 }
310 xmlSchemaTypeAnySimpleTypeDef = xmlSchemaInitBasicType("anySimpleType",
William M. Brack2f2a6632004-08-20 23:09:47 +0000311 XML_SCHEMAS_ANYSIMPLETYPE,
Daniel Veillard01fa6152004-06-29 17:04:39 +0000312 xmlSchemaTypeAnyTypeDef);
313 /*
314 * primitive datatypes
315 */
316 xmlSchemaTypeStringDef = xmlSchemaInitBasicType("string",
317 XML_SCHEMAS_STRING,
318 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000319 xmlSchemaTypeDecimalDef = xmlSchemaInitBasicType("decimal",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000320 XML_SCHEMAS_DECIMAL,
321 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000322 xmlSchemaTypeDateDef = xmlSchemaInitBasicType("date",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000323 XML_SCHEMAS_DATE,
324 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000325 xmlSchemaTypeDatetimeDef = xmlSchemaInitBasicType("dateTime",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000326 XML_SCHEMAS_DATETIME,
327 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000328 xmlSchemaTypeTimeDef = xmlSchemaInitBasicType("time",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000329 XML_SCHEMAS_TIME,
330 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000331 xmlSchemaTypeGYearDef = xmlSchemaInitBasicType("gYear",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000332 XML_SCHEMAS_GYEAR,
333 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000334 xmlSchemaTypeGYearMonthDef = xmlSchemaInitBasicType("gYearMonth",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000335 XML_SCHEMAS_GYEARMONTH,
336 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000337 xmlSchemaTypeGMonthDef = xmlSchemaInitBasicType("gMonth",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000338 XML_SCHEMAS_GMONTH,
339 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000340 xmlSchemaTypeGMonthDayDef = xmlSchemaInitBasicType("gMonthDay",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000341 XML_SCHEMAS_GMONTHDAY,
342 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000343 xmlSchemaTypeGDayDef = xmlSchemaInitBasicType("gDay",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000344 XML_SCHEMAS_GDAY,
345 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000346 xmlSchemaTypeDurationDef = xmlSchemaInitBasicType("duration",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000347 XML_SCHEMAS_DURATION,
348 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000349 xmlSchemaTypeFloatDef = xmlSchemaInitBasicType("float",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000350 XML_SCHEMAS_FLOAT,
351 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000352 xmlSchemaTypeDoubleDef = xmlSchemaInitBasicType("double",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000353 XML_SCHEMAS_DOUBLE,
354 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000355 xmlSchemaTypeBooleanDef = xmlSchemaInitBasicType("boolean",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000356 XML_SCHEMAS_BOOLEAN,
357 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000358 xmlSchemaTypeAnyURIDef = xmlSchemaInitBasicType("anyURI",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000359 XML_SCHEMAS_ANYURI,
360 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard560c2a42003-07-06 21:13:49 +0000361 xmlSchemaTypeHexBinaryDef = xmlSchemaInitBasicType("hexBinary",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000362 XML_SCHEMAS_HEXBINARY,
363 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard1ac24d32003-08-27 14:15:15 +0000364 xmlSchemaTypeBase64BinaryDef
Daniel Veillard01fa6152004-06-29 17:04:39 +0000365 = xmlSchemaInitBasicType("base64Binary", XML_SCHEMAS_BASE64BINARY,
366 xmlSchemaTypeAnySimpleTypeDef);
367 xmlSchemaTypeNotationDef = xmlSchemaInitBasicType("NOTATION",
368 XML_SCHEMAS_NOTATION,
369 xmlSchemaTypeAnySimpleTypeDef);
370 xmlSchemaTypeQNameDef = xmlSchemaInitBasicType("QName",
371 XML_SCHEMAS_QNAME,
372 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard4255d502002-04-16 15:50:10 +0000373
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000374 /*
375 * derived datatypes
376 */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000377 xmlSchemaTypeIntegerDef = xmlSchemaInitBasicType("integer",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000378 XML_SCHEMAS_INTEGER,
379 xmlSchemaTypeDecimalDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000380 xmlSchemaTypeNonPositiveIntegerDef =
381 xmlSchemaInitBasicType("nonPositiveInteger",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000382 XML_SCHEMAS_NPINTEGER,
383 xmlSchemaTypeIntegerDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000384 xmlSchemaTypeNegativeIntegerDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000385 xmlSchemaInitBasicType("negativeInteger", XML_SCHEMAS_NINTEGER,
386 xmlSchemaTypeNonPositiveIntegerDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000387 xmlSchemaTypeLongDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000388 xmlSchemaInitBasicType("long", XML_SCHEMAS_LONG,
389 xmlSchemaTypeIntegerDef);
390 xmlSchemaTypeIntDef = xmlSchemaInitBasicType("int", XML_SCHEMAS_INT,
391 xmlSchemaTypeLongDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000392 xmlSchemaTypeShortDef = xmlSchemaInitBasicType("short",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000393 XML_SCHEMAS_SHORT,
394 xmlSchemaTypeIntDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000395 xmlSchemaTypeByteDef = xmlSchemaInitBasicType("byte",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000396 XML_SCHEMAS_BYTE,
397 xmlSchemaTypeShortDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000398 xmlSchemaTypeNonNegativeIntegerDef =
399 xmlSchemaInitBasicType("nonNegativeInteger",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000400 XML_SCHEMAS_NNINTEGER,
401 xmlSchemaTypeIntegerDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000402 xmlSchemaTypeUnsignedLongDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000403 xmlSchemaInitBasicType("unsignedLong", XML_SCHEMAS_ULONG,
404 xmlSchemaTypeNonNegativeIntegerDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000405 xmlSchemaTypeUnsignedIntDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000406 xmlSchemaInitBasicType("unsignedInt", XML_SCHEMAS_UINT,
407 xmlSchemaTypeUnsignedLongDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000408 xmlSchemaTypeUnsignedShortDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000409 xmlSchemaInitBasicType("unsignedShort", XML_SCHEMAS_USHORT,
410 xmlSchemaTypeUnsignedIntDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000411 xmlSchemaTypeUnsignedByteDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000412 xmlSchemaInitBasicType("unsignedByte", XML_SCHEMAS_UBYTE,
413 xmlSchemaTypeUnsignedShortDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000414 xmlSchemaTypePositiveIntegerDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000415 xmlSchemaInitBasicType("positiveInteger", XML_SCHEMAS_PINTEGER,
416 xmlSchemaTypeNonNegativeIntegerDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000417 xmlSchemaTypeNormStringDef = xmlSchemaInitBasicType("normalizedString",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000418 XML_SCHEMAS_NORMSTRING,
419 xmlSchemaTypeStringDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000420 xmlSchemaTypeTokenDef = xmlSchemaInitBasicType("token",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000421 XML_SCHEMAS_TOKEN,
422 xmlSchemaTypeNormStringDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000423 xmlSchemaTypeLanguageDef = xmlSchemaInitBasicType("language",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000424 XML_SCHEMAS_LANGUAGE,
425 xmlSchemaTypeTokenDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000426 xmlSchemaTypeNameDef = xmlSchemaInitBasicType("Name",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000427 XML_SCHEMAS_NAME,
428 xmlSchemaTypeTokenDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000429 xmlSchemaTypeNmtokenDef = xmlSchemaInitBasicType("NMTOKEN",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000430 XML_SCHEMAS_NMTOKEN,
431 xmlSchemaTypeTokenDef);
432 xmlSchemaTypeNCNameDef = xmlSchemaInitBasicType("NCName",
433 XML_SCHEMAS_NCNAME,
434 xmlSchemaTypeNameDef);
435 xmlSchemaTypeIdDef = xmlSchemaInitBasicType("ID", XML_SCHEMAS_ID,
436 xmlSchemaTypeNCNameDef);
437 xmlSchemaTypeIdrefDef = xmlSchemaInitBasicType("IDREF",
438 XML_SCHEMAS_IDREF,
439 xmlSchemaTypeNCNameDef);
440 xmlSchemaTypeIdrefsDef = xmlSchemaInitBasicType("IDREFS",
441 XML_SCHEMAS_IDREFS,
442 xmlSchemaTypeIdrefDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000443 xmlSchemaTypeNmtokensDef = xmlSchemaInitBasicType("NMTOKENS",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000444 XML_SCHEMAS_NMTOKENS,
445 xmlSchemaTypeNmtokenDef);
446 xmlSchemaTypeEntityDef = xmlSchemaInitBasicType("ENTITY",
447 XML_SCHEMAS_ENTITY,
448 xmlSchemaTypeNCNameDef);
449 xmlSchemaTypeEntitiesDef = xmlSchemaInitBasicType("ENTITIES",
450 XML_SCHEMAS_ENTITIES,
451 xmlSchemaTypeNCNameDef);
Daniel Veillard4255d502002-04-16 15:50:10 +0000452 xmlSchemaTypesInitialized = 1;
453}
454
455/**
456 * xmlSchemaCleanupTypes:
457 *
458 * Cleanup the default XML Schemas type library
459 */
460void
461xmlSchemaCleanupTypes(void) {
462 if (xmlSchemaTypesInitialized == 0)
463 return;
Daniel Veillard01fa6152004-06-29 17:04:39 +0000464 xmlSchemaFreeWildcard(xmlSchemaTypeAnyTypeDef->attributeWildcard);
Daniel Veillard4255d502002-04-16 15:50:10 +0000465 xmlHashFree(xmlSchemaTypesBank, (xmlHashDeallocator) xmlSchemaFreeType);
466 xmlSchemaTypesInitialized = 0;
467}
468
469/**
Daniel Veillard6927b102004-10-27 17:29:04 +0000470 * xmlSchemaIsBuiltInTypeFacet:
Daniel Veillard01fa6152004-06-29 17:04:39 +0000471 * @type: the built-in type
472 * @facetType: the facet type
473 *
474 * Evaluates if a specific facet can be
475 * used in conjunction with a type.
476 *
477 * Returns 1 if the facet can be used with the given built-in type,
478 * 0 otherwise and -1 in case the type is not a built-in type.
479 */
480int
481xmlSchemaIsBuiltInTypeFacet(xmlSchemaTypePtr type, int facetType)
482{
Daniel Veillardce682bc2004-11-05 17:22:25 +0000483 if (type == NULL)
484 return (-1);
Daniel Veillard01fa6152004-06-29 17:04:39 +0000485 if (type->type != XML_SCHEMA_TYPE_BASIC)
486 return (-1);
487 switch (type->builtInType) {
488 case XML_SCHEMAS_BOOLEAN:
489 if ((facetType == XML_SCHEMA_FACET_PATTERN) ||
490 (facetType == XML_SCHEMA_FACET_WHITESPACE))
491 return (1);
492 else
493 return (0);
494 case XML_SCHEMAS_STRING:
495 case XML_SCHEMAS_NOTATION:
496 case XML_SCHEMAS_QNAME:
497 case XML_SCHEMAS_ANYURI:
498 case XML_SCHEMAS_BASE64BINARY:
499 case XML_SCHEMAS_HEXBINARY:
500 if ((facetType == XML_SCHEMA_FACET_LENGTH) ||
501 (facetType == XML_SCHEMA_FACET_MINLENGTH) ||
502 (facetType == XML_SCHEMA_FACET_MAXLENGTH) ||
503 (facetType == XML_SCHEMA_FACET_PATTERN) ||
504 (facetType == XML_SCHEMA_FACET_ENUMERATION) ||
505 (facetType == XML_SCHEMA_FACET_WHITESPACE))
506 return (1);
507 else
508 return (0);
509 case XML_SCHEMAS_DECIMAL:
510 if ((facetType == XML_SCHEMA_FACET_TOTALDIGITS) ||
511 (facetType == XML_SCHEMA_FACET_FRACTIONDIGITS) ||
512 (facetType == XML_SCHEMA_FACET_PATTERN) ||
513 (facetType == XML_SCHEMA_FACET_WHITESPACE) ||
514 (facetType == XML_SCHEMA_FACET_ENUMERATION) ||
515 (facetType == XML_SCHEMA_FACET_MAXINCLUSIVE) ||
516 (facetType == XML_SCHEMA_FACET_MAXEXCLUSIVE) ||
517 (facetType == XML_SCHEMA_FACET_MININCLUSIVE) ||
518 (facetType == XML_SCHEMA_FACET_MINEXCLUSIVE))
519 return (1);
520 else
521 return (0);
522 case XML_SCHEMAS_TIME:
523 case XML_SCHEMAS_GDAY:
524 case XML_SCHEMAS_GMONTH:
525 case XML_SCHEMAS_GMONTHDAY:
526 case XML_SCHEMAS_GYEAR:
527 case XML_SCHEMAS_GYEARMONTH:
528 case XML_SCHEMAS_DATE:
529 case XML_SCHEMAS_DATETIME:
530 case XML_SCHEMAS_DURATION:
531 case XML_SCHEMAS_FLOAT:
532 case XML_SCHEMAS_DOUBLE:
533 if ((facetType == XML_SCHEMA_FACET_PATTERN) ||
534 (facetType == XML_SCHEMA_FACET_ENUMERATION) ||
535 (facetType == XML_SCHEMA_FACET_WHITESPACE) ||
536 (facetType == XML_SCHEMA_FACET_MAXINCLUSIVE) ||
537 (facetType == XML_SCHEMA_FACET_MAXEXCLUSIVE) ||
538 (facetType == XML_SCHEMA_FACET_MININCLUSIVE) ||
539 (facetType == XML_SCHEMA_FACET_MINEXCLUSIVE))
540 return (1);
541 else
542 return (0);
543 default:
Daniel Veillardc7e3cc42004-09-28 12:33:52 +0000544 break;
Daniel Veillard01fa6152004-06-29 17:04:39 +0000545 }
546 return (0);
547}
548
549/**
550 * xmlSchemaGetBuiltInType:
551 * @type: the type of the built in type
552 *
553 * Gives you the type struct for a built-in
554 * type by its type id.
555 *
556 * Returns the type if found, NULL otherwise.
557 */
558xmlSchemaTypePtr
559xmlSchemaGetBuiltInType(xmlSchemaValType type)
560{
561 if (xmlSchemaTypesInitialized == 0)
562 xmlSchemaInitTypes();
563 switch (type) {
564
565 case XML_SCHEMAS_ANYSIMPLETYPE:
566 return (xmlSchemaTypeAnySimpleTypeDef);
567 case XML_SCHEMAS_STRING:
568 return (xmlSchemaTypeStringDef);
569 case XML_SCHEMAS_NORMSTRING:
570 return (xmlSchemaTypeNormStringDef);
571 case XML_SCHEMAS_DECIMAL:
572 return (xmlSchemaTypeDecimalDef);
573 case XML_SCHEMAS_TIME:
574 return (xmlSchemaTypeTimeDef);
575 case XML_SCHEMAS_GDAY:
576 return (xmlSchemaTypeGDayDef);
577 case XML_SCHEMAS_GMONTH:
578 return (xmlSchemaTypeGMonthDef);
579 case XML_SCHEMAS_GMONTHDAY:
580 return (xmlSchemaTypeGMonthDayDef);
581 case XML_SCHEMAS_GYEAR:
582 return (xmlSchemaTypeGYearDef);
583 case XML_SCHEMAS_GYEARMONTH:
584 return (xmlSchemaTypeGYearMonthDef);
585 case XML_SCHEMAS_DATE:
586 return (xmlSchemaTypeDateDef);
587 case XML_SCHEMAS_DATETIME:
588 return (xmlSchemaTypeDatetimeDef);
589 case XML_SCHEMAS_DURATION:
590 return (xmlSchemaTypeDurationDef);
591 case XML_SCHEMAS_FLOAT:
592 return (xmlSchemaTypeFloatDef);
593 case XML_SCHEMAS_DOUBLE:
594 return (xmlSchemaTypeDoubleDef);
595 case XML_SCHEMAS_BOOLEAN:
596 return (xmlSchemaTypeBooleanDef);
597 case XML_SCHEMAS_TOKEN:
598 return (xmlSchemaTypeTokenDef);
599 case XML_SCHEMAS_LANGUAGE:
600 return (xmlSchemaTypeLanguageDef);
601 case XML_SCHEMAS_NMTOKEN:
602 return (xmlSchemaTypeNmtokenDef);
603 case XML_SCHEMAS_NMTOKENS:
604 return (xmlSchemaTypeNmtokensDef);
605 case XML_SCHEMAS_NAME:
606 return (xmlSchemaTypeNameDef);
607 case XML_SCHEMAS_QNAME:
608 return (xmlSchemaTypeQNameDef);
609 case XML_SCHEMAS_NCNAME:
610 return (xmlSchemaTypeNCNameDef);
611 case XML_SCHEMAS_ID:
612 return (xmlSchemaTypeIdDef);
613 case XML_SCHEMAS_IDREF:
614 return (xmlSchemaTypeIdrefDef);
615 case XML_SCHEMAS_IDREFS:
616 return (xmlSchemaTypeIdrefsDef);
617 case XML_SCHEMAS_ENTITY:
618 return (xmlSchemaTypeEntityDef);
619 case XML_SCHEMAS_ENTITIES:
620 return (xmlSchemaTypeEntitiesDef);
621 case XML_SCHEMAS_NOTATION:
622 return (xmlSchemaTypeNotationDef);
623 case XML_SCHEMAS_ANYURI:
624 return (xmlSchemaTypeAnyURIDef);
625 case XML_SCHEMAS_INTEGER:
626 return (xmlSchemaTypeIntegerDef);
627 case XML_SCHEMAS_NPINTEGER:
628 return (xmlSchemaTypeNonPositiveIntegerDef);
629 case XML_SCHEMAS_NINTEGER:
630 return (xmlSchemaTypeNegativeIntegerDef);
631 case XML_SCHEMAS_NNINTEGER:
632 return (xmlSchemaTypeNonNegativeIntegerDef);
633 case XML_SCHEMAS_PINTEGER:
634 return (xmlSchemaTypePositiveIntegerDef);
635 case XML_SCHEMAS_INT:
636 return (xmlSchemaTypeIntDef);
637 case XML_SCHEMAS_UINT:
638 return (xmlSchemaTypeUnsignedIntDef);
639 case XML_SCHEMAS_LONG:
640 return (xmlSchemaTypeLongDef);
641 case XML_SCHEMAS_ULONG:
642 return (xmlSchemaTypeUnsignedLongDef);
643 case XML_SCHEMAS_SHORT:
644 return (xmlSchemaTypeShortDef);
645 case XML_SCHEMAS_USHORT:
646 return (xmlSchemaTypeUnsignedShortDef);
647 case XML_SCHEMAS_BYTE:
648 return (xmlSchemaTypeByteDef);
649 case XML_SCHEMAS_UBYTE:
650 return (xmlSchemaTypeUnsignedByteDef);
651 case XML_SCHEMAS_HEXBINARY:
652 return (xmlSchemaTypeHexBinaryDef);
653 case XML_SCHEMAS_BASE64BINARY:
654 return (xmlSchemaTypeBase64BinaryDef);
655 case XML_SCHEMAS_ANYTYPE:
656 return (xmlSchemaTypeAnyTypeDef);
657 default:
658 return (NULL);
659 }
660}
661
662/**
Daniel Veillard4255d502002-04-16 15:50:10 +0000663 * xmlSchemaNewValue:
664 * @type: the value type
665 *
666 * Allocate a new simple type value
667 *
668 * Returns a pointer to the new value or NULL in case of error
669 */
670static xmlSchemaValPtr
671xmlSchemaNewValue(xmlSchemaValType type) {
672 xmlSchemaValPtr value;
673
674 value = (xmlSchemaValPtr) xmlMalloc(sizeof(xmlSchemaVal));
675 if (value == NULL) {
676 return(NULL);
677 }
678 memset(value, 0, sizeof(xmlSchemaVal));
679 value->type = type;
680 return(value);
681}
682
683/**
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +0000684 * xmlSchemaNewStringValue:
685 * @type: the value type
Daniel Veillardb5839c32005-02-19 18:27:14 +0000686 * @value: the value
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +0000687 *
688 * Allocate a new simple type value. The type can be
Kasimier T. Buchcik2ee855d2005-03-07 11:14:14 +0000689 * of XML_SCHEMAS_STRING.
690 * WARNING: This one is intended to be expanded for other
691 * string based types. We need this for anySimpleType as well.
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +0000692 *
693 * Returns a pointer to the new value or NULL in case of error
694 */
695xmlSchemaValPtr
696xmlSchemaNewStringValue(xmlSchemaValType type,
697 const xmlChar *value)
698{
699 xmlSchemaValPtr val;
700
701 if (type != XML_SCHEMAS_STRING)
702 return(NULL);
703 val = (xmlSchemaValPtr) xmlMalloc(sizeof(xmlSchemaVal));
704 if (val == NULL) {
705 return(NULL);
706 }
707 memset(val, 0, sizeof(xmlSchemaVal));
708 val->type = type;
709 val->value.str = (xmlChar *) value;
710 return(val);
711}
712
Kasimier T. Buchcikb06b4de2005-02-17 19:00:23 +0000713/**
714 * xmlSchemaNewNOTATIONValue:
Daniel Veillardb5839c32005-02-19 18:27:14 +0000715 * @name: the notation name
716 * @ns: the notation namespace name or NULL
Kasimier T. Buchcikb06b4de2005-02-17 19:00:23 +0000717 *
718 * Allocate a new NOTATION value.
719 *
720 * Returns a pointer to the new value or NULL in case of error
721 */
722xmlSchemaValPtr
723xmlSchemaNewNOTATIONValue(const xmlChar *name,
724 const xmlChar *ns)
725{
726 xmlSchemaValPtr val;
727
728 val = xmlSchemaNewValue(XML_SCHEMAS_NOTATION);
729 if (val == NULL)
730 return (NULL);
731
William M. Brack12d37ab2005-02-21 13:54:07 +0000732 val->value.qname.name = (xmlChar *)name;
Kasimier T. Buchcikb06b4de2005-02-17 19:00:23 +0000733 if (ns != NULL)
William M. Brack12d37ab2005-02-21 13:54:07 +0000734 val->value.qname.uri = (xmlChar *)ns;
Kasimier T. Buchcikb06b4de2005-02-17 19:00:23 +0000735 return(val);
736}
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +0000737
738/**
Daniel Veillard4255d502002-04-16 15:50:10 +0000739 * xmlSchemaFreeValue:
740 * @value: the value to free
741 *
742 * Cleanup the default XML Schemas type library
743 */
744void
745xmlSchemaFreeValue(xmlSchemaValPtr value) {
746 if (value == NULL)
747 return;
Daniel Veillardc4c21552003-03-29 10:53:38 +0000748 switch (value->type) {
749 case XML_SCHEMAS_STRING:
750 case XML_SCHEMAS_NORMSTRING:
751 case XML_SCHEMAS_TOKEN:
752 case XML_SCHEMAS_LANGUAGE:
753 case XML_SCHEMAS_NMTOKEN:
754 case XML_SCHEMAS_NMTOKENS:
755 case XML_SCHEMAS_NAME:
Daniel Veillardc4c21552003-03-29 10:53:38 +0000756 case XML_SCHEMAS_NCNAME:
757 case XML_SCHEMAS_ID:
758 case XML_SCHEMAS_IDREF:
759 case XML_SCHEMAS_IDREFS:
760 case XML_SCHEMAS_ENTITY:
Kasimier T. Buchcikb06b4de2005-02-17 19:00:23 +0000761 case XML_SCHEMAS_ENTITIES:
Daniel Veillardc4c21552003-03-29 10:53:38 +0000762 case XML_SCHEMAS_ANYURI:
763 if (value->value.str != NULL)
764 xmlFree(value->value.str);
765 break;
Kasimier T. Buchcikb06b4de2005-02-17 19:00:23 +0000766 case XML_SCHEMAS_NOTATION:
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000767 case XML_SCHEMAS_QNAME:
768 if (value->value.qname.uri != NULL)
769 xmlFree(value->value.qname.uri);
770 if (value->value.qname.name != NULL)
771 xmlFree(value->value.qname.name);
772 break;
Daniel Veillard70bcb0e2003-08-08 14:00:28 +0000773 case XML_SCHEMAS_HEXBINARY:
774 if (value->value.hex.str != NULL)
775 xmlFree(value->value.hex.str);
776 break;
Daniel Veillard1ac24d32003-08-27 14:15:15 +0000777 case XML_SCHEMAS_BASE64BINARY:
778 if (value->value.base64.str != NULL)
779 xmlFree(value->value.base64.str);
780 break;
Daniel Veillardc4c21552003-03-29 10:53:38 +0000781 default:
782 break;
783 }
Daniel Veillard4255d502002-04-16 15:50:10 +0000784 xmlFree(value);
785}
786
787/**
788 * xmlSchemaGetPredefinedType:
789 * @name: the type name
790 * @ns: the URI of the namespace usually "http://www.w3.org/2001/XMLSchema"
791 *
792 * Lookup a type in the default XML Schemas type library
793 *
794 * Returns the type if found, NULL otherwise
795 */
796xmlSchemaTypePtr
797xmlSchemaGetPredefinedType(const xmlChar *name, const xmlChar *ns) {
798 if (xmlSchemaTypesInitialized == 0)
799 xmlSchemaInitTypes();
800 if (name == NULL)
801 return(NULL);
802 return((xmlSchemaTypePtr) xmlHashLookup2(xmlSchemaTypesBank, name, ns));
803}
Daniel Veillard070803b2002-05-03 07:29:38 +0000804
Daniel Veillard01fa6152004-06-29 17:04:39 +0000805/**
806 * xmlSchemaGetBuiltInListSimpleTypeItemType:
807 * @type: the built-in simple type.
808 *
Daniel Veillard6927b102004-10-27 17:29:04 +0000809 * Lookup function
810 *
Daniel Veillardc0826a72004-08-10 14:17:33 +0000811 * Returns the item type of @type as defined by the built-in datatype
812 * hierarchy of XML Schema Part 2: Datatypes, or NULL in case of an error.
Daniel Veillard01fa6152004-06-29 17:04:39 +0000813 */
814xmlSchemaTypePtr
815xmlSchemaGetBuiltInListSimpleTypeItemType(xmlSchemaTypePtr type)
816{
Daniel Veillard42595322004-11-08 10:52:06 +0000817 if ((type == NULL) || (type->type != XML_SCHEMA_TYPE_BASIC))
Daniel Veillard01fa6152004-06-29 17:04:39 +0000818 return (NULL);
819 switch (type->builtInType) {
820 case XML_SCHEMAS_NMTOKENS:
821 return (xmlSchemaTypeNmtokenDef );
822 case XML_SCHEMAS_IDREFS:
823 return (xmlSchemaTypeIdrefDef);
824 case XML_SCHEMAS_ENTITIES:
825 return (xmlSchemaTypeEntityDef);
826 default:
827 return (NULL);
828 }
829}
830
Daniel Veillard070803b2002-05-03 07:29:38 +0000831/****************************************************************
832 * *
833 * Convenience macros and functions *
834 * *
835 ****************************************************************/
836
837#define IS_TZO_CHAR(c) \
838 ((c == 0) || (c == 'Z') || (c == '+') || (c == '-'))
839
840#define VALID_YEAR(yr) (yr != 0)
841#define VALID_MONTH(mon) ((mon >= 1) && (mon <= 12))
842/* VALID_DAY should only be used when month is unknown */
843#define VALID_DAY(day) ((day >= 1) && (day <= 31))
844#define VALID_HOUR(hr) ((hr >= 0) && (hr <= 23))
845#define VALID_MIN(min) ((min >= 0) && (min <= 59))
846#define VALID_SEC(sec) ((sec >= 0) && (sec < 60))
847#define VALID_TZO(tzo) ((tzo > -1440) && (tzo < 1440))
848#define IS_LEAP(y) \
849 (((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0))
850
Daniel Veillardebe25d42004-03-25 09:35:49 +0000851static const unsigned int daysInMonth[12] =
Daniel Veillard070803b2002-05-03 07:29:38 +0000852 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
Daniel Veillardebe25d42004-03-25 09:35:49 +0000853static const unsigned int daysInMonthLeap[12] =
Daniel Veillard070803b2002-05-03 07:29:38 +0000854 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
855
Daniel Veillard5a872412002-05-22 06:40:27 +0000856#define MAX_DAYINMONTH(yr,mon) \
857 (IS_LEAP(yr) ? daysInMonthLeap[mon - 1] : daysInMonth[mon - 1])
858
Daniel Veillard070803b2002-05-03 07:29:38 +0000859#define VALID_MDAY(dt) \
860 (IS_LEAP(dt->year) ? \
861 (dt->day <= daysInMonthLeap[dt->mon - 1]) : \
862 (dt->day <= daysInMonth[dt->mon - 1]))
863
864#define VALID_DATE(dt) \
865 (VALID_YEAR(dt->year) && VALID_MONTH(dt->mon) && VALID_MDAY(dt))
866
867#define VALID_TIME(dt) \
868 (VALID_HOUR(dt->hour) && VALID_MIN(dt->min) && \
869 VALID_SEC(dt->sec) && VALID_TZO(dt->tzo))
870
871#define VALID_DATETIME(dt) \
872 (VALID_DATE(dt) && VALID_TIME(dt))
873
874#define SECS_PER_MIN (60)
875#define SECS_PER_HOUR (60 * SECS_PER_MIN)
876#define SECS_PER_DAY (24 * SECS_PER_HOUR)
877
Daniel Veillard5a872412002-05-22 06:40:27 +0000878static const long dayInYearByMonth[12] =
879 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
880static const long dayInLeapYearByMonth[12] =
881 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 };
882
883#define DAY_IN_YEAR(day, month, year) \
884 ((IS_LEAP(year) ? \
885 dayInLeapYearByMonth[month - 1] : \
886 dayInYearByMonth[month - 1]) + day)
887
888#ifdef DEBUG
889#define DEBUG_DATE(dt) \
890 xmlGenericError(xmlGenericErrorContext, \
891 "type=%o %04ld-%02u-%02uT%02u:%02u:%03f", \
892 dt->type,dt->value.date.year,dt->value.date.mon, \
893 dt->value.date.day,dt->value.date.hour,dt->value.date.min, \
894 dt->value.date.sec); \
895 if (dt->value.date.tz_flag) \
896 if (dt->value.date.tzo != 0) \
897 xmlGenericError(xmlGenericErrorContext, \
898 "%+05d\n",dt->value.date.tzo); \
899 else \
900 xmlGenericError(xmlGenericErrorContext, "Z\n"); \
901 else \
902 xmlGenericError(xmlGenericErrorContext,"\n")
903#else
904#define DEBUG_DATE(dt)
905#endif
906
Daniel Veillard070803b2002-05-03 07:29:38 +0000907/**
908 * _xmlSchemaParseGYear:
909 * @dt: pointer to a date structure
910 * @str: pointer to the string to analyze
911 *
912 * Parses a xs:gYear without time zone and fills in the appropriate
913 * field of the @dt structure. @str is updated to point just after the
914 * xs:gYear. It is supposed that @dt->year is big enough to contain
915 * the year.
916 *
917 * Returns 0 or the error code
918 */
919static int
920_xmlSchemaParseGYear (xmlSchemaValDatePtr dt, const xmlChar **str) {
921 const xmlChar *cur = *str, *firstChar;
922 int isneg = 0, digcnt = 0;
923
924 if (((*cur < '0') || (*cur > '9')) &&
925 (*cur != '-') && (*cur != '+'))
926 return -1;
927
928 if (*cur == '-') {
929 isneg = 1;
930 cur++;
931 }
932
933 firstChar = cur;
934
935 while ((*cur >= '0') && (*cur <= '9')) {
936 dt->year = dt->year * 10 + (*cur - '0');
937 cur++;
938 digcnt++;
939 }
940
941 /* year must be at least 4 digits (CCYY); over 4
942 * digits cannot have a leading zero. */
943 if ((digcnt < 4) || ((digcnt > 4) && (*firstChar == '0')))
944 return 1;
945
946 if (isneg)
947 dt->year = - dt->year;
948
949 if (!VALID_YEAR(dt->year))
950 return 2;
951
952 *str = cur;
953 return 0;
954}
955
956/**
957 * PARSE_2_DIGITS:
958 * @num: the integer to fill in
959 * @cur: an #xmlChar *
960 * @invalid: an integer
961 *
962 * Parses a 2-digits integer and updates @num with the value. @cur is
963 * updated to point just after the integer.
964 * In case of error, @invalid is set to %TRUE, values of @num and
965 * @cur are undefined.
966 */
967#define PARSE_2_DIGITS(num, cur, invalid) \
968 if ((cur[0] < '0') || (cur[0] > '9') || \
969 (cur[1] < '0') || (cur[1] > '9')) \
970 invalid = 1; \
971 else \
972 num = (cur[0] - '0') * 10 + (cur[1] - '0'); \
973 cur += 2;
974
975/**
976 * PARSE_FLOAT:
977 * @num: the double to fill in
978 * @cur: an #xmlChar *
979 * @invalid: an integer
980 *
981 * Parses a float and updates @num with the value. @cur is
982 * updated to point just after the float. The float must have a
983 * 2-digits integer part and may or may not have a decimal part.
984 * In case of error, @invalid is set to %TRUE, values of @num and
985 * @cur are undefined.
986 */
987#define PARSE_FLOAT(num, cur, invalid) \
988 PARSE_2_DIGITS(num, cur, invalid); \
989 if (!invalid && (*cur == '.')) { \
990 double mult = 1; \
991 cur++; \
992 if ((*cur < '0') || (*cur > '9')) \
993 invalid = 1; \
994 while ((*cur >= '0') && (*cur <= '9')) { \
995 mult /= 10; \
996 num += (*cur - '0') * mult; \
997 cur++; \
998 } \
999 }
1000
1001/**
1002 * _xmlSchemaParseGMonth:
1003 * @dt: pointer to a date structure
1004 * @str: pointer to the string to analyze
1005 *
1006 * Parses a xs:gMonth without time zone and fills in the appropriate
1007 * field of the @dt structure. @str is updated to point just after the
1008 * xs:gMonth.
1009 *
1010 * Returns 0 or the error code
1011 */
1012static int
1013_xmlSchemaParseGMonth (xmlSchemaValDatePtr dt, const xmlChar **str) {
1014 const xmlChar *cur = *str;
1015 int ret = 0;
Kasimier T. Buchcik64dc4d22005-04-19 15:58:31 +00001016 unsigned int value = 0;
Daniel Veillard070803b2002-05-03 07:29:38 +00001017
Kasimier T. Buchcik64dc4d22005-04-19 15:58:31 +00001018 PARSE_2_DIGITS(value, cur, ret);
Daniel Veillard070803b2002-05-03 07:29:38 +00001019 if (ret != 0)
1020 return ret;
1021
Kasimier T. Buchcik64dc4d22005-04-19 15:58:31 +00001022 if (!VALID_MONTH(value))
Daniel Veillard070803b2002-05-03 07:29:38 +00001023 return 2;
1024
Kasimier T. Buchcik64dc4d22005-04-19 15:58:31 +00001025 dt->mon = value;
1026
Daniel Veillard070803b2002-05-03 07:29:38 +00001027 *str = cur;
1028 return 0;
1029}
1030
1031/**
1032 * _xmlSchemaParseGDay:
1033 * @dt: pointer to a date structure
1034 * @str: pointer to the string to analyze
1035 *
1036 * Parses a xs:gDay without time zone and fills in the appropriate
1037 * field of the @dt structure. @str is updated to point just after the
1038 * xs:gDay.
1039 *
1040 * Returns 0 or the error code
1041 */
1042static int
1043_xmlSchemaParseGDay (xmlSchemaValDatePtr dt, const xmlChar **str) {
1044 const xmlChar *cur = *str;
1045 int ret = 0;
Kasimier T. Buchcik64dc4d22005-04-19 15:58:31 +00001046 unsigned int value = 0;
Daniel Veillard070803b2002-05-03 07:29:38 +00001047
Kasimier T. Buchcik64dc4d22005-04-19 15:58:31 +00001048 PARSE_2_DIGITS(value, cur, ret);
Daniel Veillard070803b2002-05-03 07:29:38 +00001049 if (ret != 0)
1050 return ret;
1051
Kasimier T. Buchcik64dc4d22005-04-19 15:58:31 +00001052 if (!VALID_DAY(value))
Daniel Veillard070803b2002-05-03 07:29:38 +00001053 return 2;
1054
Kasimier T. Buchcik64dc4d22005-04-19 15:58:31 +00001055 dt->day = value;
Daniel Veillard070803b2002-05-03 07:29:38 +00001056 *str = cur;
1057 return 0;
1058}
1059
1060/**
1061 * _xmlSchemaParseTime:
1062 * @dt: pointer to a date structure
1063 * @str: pointer to the string to analyze
1064 *
1065 * Parses a xs:time without time zone and fills in the appropriate
1066 * fields of the @dt structure. @str is updated to point just after the
1067 * xs:time.
1068 * In case of error, values of @dt fields are undefined.
1069 *
1070 * Returns 0 or the error code
1071 */
1072static int
1073_xmlSchemaParseTime (xmlSchemaValDatePtr dt, const xmlChar **str) {
Kasimier T. Buchcik285b3672005-05-12 13:10:22 +00001074 const xmlChar *cur = *str;
Daniel Veillard070803b2002-05-03 07:29:38 +00001075 int ret = 0;
Kasimier T. Buchcik285b3672005-05-12 13:10:22 +00001076 int value = 0;
Daniel Veillard070803b2002-05-03 07:29:38 +00001077
Kasimier T. Buchcik64dc4d22005-04-19 15:58:31 +00001078 PARSE_2_DIGITS(value, cur, ret);
Daniel Veillard070803b2002-05-03 07:29:38 +00001079 if (ret != 0)
Kasimier T. Buchcik64dc4d22005-04-19 15:58:31 +00001080 return ret;
Daniel Veillard070803b2002-05-03 07:29:38 +00001081 if (*cur != ':')
1082 return 1;
Kasimier T. Buchcik64dc4d22005-04-19 15:58:31 +00001083 if (!VALID_HOUR(value))
1084 return 2;
Daniel Veillard070803b2002-05-03 07:29:38 +00001085 cur++;
1086
1087 /* the ':' insures this string is xs:time */
Kasimier T. Buchcik64dc4d22005-04-19 15:58:31 +00001088 dt->hour = value;
Daniel Veillard070803b2002-05-03 07:29:38 +00001089
Kasimier T. Buchcik64dc4d22005-04-19 15:58:31 +00001090 PARSE_2_DIGITS(value, cur, ret);
Daniel Veillard070803b2002-05-03 07:29:38 +00001091 if (ret != 0)
1092 return ret;
Kasimier T. Buchcik64dc4d22005-04-19 15:58:31 +00001093 if (!VALID_MIN(value))
1094 return 2;
1095 dt->min = value;
Daniel Veillard070803b2002-05-03 07:29:38 +00001096
1097 if (*cur != ':')
1098 return 1;
1099 cur++;
1100
1101 PARSE_FLOAT(dt->sec, cur, ret);
1102 if (ret != 0)
1103 return ret;
1104
Kasimier T. Buchcik64dc4d22005-04-19 15:58:31 +00001105 if ((!VALID_SEC(dt->sec)) || (!VALID_TZO(dt->tzo)))
Daniel Veillard070803b2002-05-03 07:29:38 +00001106 return 2;
1107
1108 *str = cur;
1109 return 0;
1110}
1111
1112/**
1113 * _xmlSchemaParseTimeZone:
1114 * @dt: pointer to a date structure
1115 * @str: pointer to the string to analyze
1116 *
1117 * Parses a time zone without time zone and fills in the appropriate
1118 * field of the @dt structure. @str is updated to point just after the
1119 * time zone.
1120 *
1121 * Returns 0 or the error code
1122 */
1123static int
1124_xmlSchemaParseTimeZone (xmlSchemaValDatePtr dt, const xmlChar **str) {
1125 const xmlChar *cur = *str;
1126 int ret = 0;
1127
1128 if (str == NULL)
1129 return -1;
1130
1131 switch (*cur) {
1132 case 0:
1133 dt->tz_flag = 0;
1134 dt->tzo = 0;
1135 break;
1136
1137 case 'Z':
1138 dt->tz_flag = 1;
1139 dt->tzo = 0;
1140 cur++;
1141 break;
1142
1143 case '+':
1144 case '-': {
1145 int isneg = 0, tmp = 0;
1146 isneg = (*cur == '-');
1147
1148 cur++;
1149
1150 PARSE_2_DIGITS(tmp, cur, ret);
1151 if (ret != 0)
1152 return ret;
1153 if (!VALID_HOUR(tmp))
1154 return 2;
1155
1156 if (*cur != ':')
1157 return 1;
1158 cur++;
1159
1160 dt->tzo = tmp * 60;
1161
1162 PARSE_2_DIGITS(tmp, cur, ret);
1163 if (ret != 0)
1164 return ret;
1165 if (!VALID_MIN(tmp))
1166 return 2;
1167
1168 dt->tzo += tmp;
1169 if (isneg)
1170 dt->tzo = - dt->tzo;
1171
1172 if (!VALID_TZO(dt->tzo))
1173 return 2;
1174
Daniel Veillard5a872412002-05-22 06:40:27 +00001175 dt->tz_flag = 1;
Daniel Veillard070803b2002-05-03 07:29:38 +00001176 break;
1177 }
1178 default:
1179 return 1;
1180 }
1181
1182 *str = cur;
1183 return 0;
1184}
1185
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001186/**
1187 * _xmlSchemaBase64Decode:
1188 * @ch: a character
1189 *
1190 * Converts a base64 encoded character to its base 64 value.
1191 *
1192 * Returns 0-63 (value), 64 (pad), or -1 (not recognized)
1193 */
1194static int
1195_xmlSchemaBase64Decode (const xmlChar ch) {
1196 if (('A' <= ch) && (ch <= 'Z')) return ch - 'A';
1197 if (('a' <= ch) && (ch <= 'z')) return ch - 'a' + 26;
1198 if (('0' <= ch) && (ch <= '9')) return ch - '0' + 52;
1199 if ('+' == ch) return 62;
1200 if ('/' == ch) return 63;
1201 if ('=' == ch) return 64;
1202 return -1;
1203}
1204
Daniel Veillard070803b2002-05-03 07:29:38 +00001205/****************************************************************
1206 * *
1207 * XML Schema Dates/Times Datatypes Handling *
1208 * *
1209 ****************************************************************/
1210
1211/**
1212 * PARSE_DIGITS:
1213 * @num: the integer to fill in
1214 * @cur: an #xmlChar *
1215 * @num_type: an integer flag
1216 *
1217 * Parses a digits integer and updates @num with the value. @cur is
1218 * updated to point just after the integer.
1219 * In case of error, @num_type is set to -1, values of @num and
1220 * @cur are undefined.
1221 */
1222#define PARSE_DIGITS(num, cur, num_type) \
1223 if ((*cur < '0') || (*cur > '9')) \
1224 num_type = -1; \
1225 else \
1226 while ((*cur >= '0') && (*cur <= '9')) { \
1227 num = num * 10 + (*cur - '0'); \
1228 cur++; \
1229 }
1230
1231/**
1232 * PARSE_NUM:
1233 * @num: the double to fill in
1234 * @cur: an #xmlChar *
1235 * @num_type: an integer flag
1236 *
1237 * Parses a float or integer and updates @num with the value. @cur is
1238 * updated to point just after the number. If the number is a float,
1239 * then it must have an integer part and a decimal part; @num_type will
1240 * be set to 1. If there is no decimal part, @num_type is set to zero.
1241 * In case of error, @num_type is set to -1, values of @num and
1242 * @cur are undefined.
1243 */
1244#define PARSE_NUM(num, cur, num_type) \
1245 num = 0; \
1246 PARSE_DIGITS(num, cur, num_type); \
1247 if (!num_type && (*cur == '.')) { \
1248 double mult = 1; \
1249 cur++; \
1250 if ((*cur < '0') || (*cur > '9')) \
1251 num_type = -1; \
1252 else \
1253 num_type = 1; \
1254 while ((*cur >= '0') && (*cur <= '9')) { \
1255 mult /= 10; \
1256 num += (*cur - '0') * mult; \
1257 cur++; \
1258 } \
1259 }
1260
1261/**
Daniel Veillard5a872412002-05-22 06:40:27 +00001262 * xmlSchemaValidateDates:
Daniel Veillard455cc072003-03-31 10:13:23 +00001263 * @type: the expected type or XML_SCHEMAS_UNKNOWN
Daniel Veillard070803b2002-05-03 07:29:38 +00001264 * @dateTime: string to analyze
1265 * @val: the return computed value
1266 *
1267 * Check that @dateTime conforms to the lexical space of one of the date types.
1268 * if true a value is computed and returned in @val.
1269 *
1270 * Returns 0 if this validates, a positive error code number otherwise
1271 * and -1 in case of internal or API error.
1272 */
1273static int
Daniel Veillard455cc072003-03-31 10:13:23 +00001274xmlSchemaValidateDates (xmlSchemaValType type,
Daniel Veillard118aed72002-09-24 14:13:13 +00001275 const xmlChar *dateTime, xmlSchemaValPtr *val) {
Daniel Veillard070803b2002-05-03 07:29:38 +00001276 xmlSchemaValPtr dt;
1277 int ret;
1278 const xmlChar *cur = dateTime;
1279
1280#define RETURN_TYPE_IF_VALID(t) \
1281 if (IS_TZO_CHAR(*cur)) { \
1282 ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur); \
1283 if (ret == 0) { \
1284 if (*cur != 0) \
1285 goto error; \
1286 dt->type = t; \
Daniel Veillard455cc072003-03-31 10:13:23 +00001287 goto done; \
Daniel Veillard070803b2002-05-03 07:29:38 +00001288 } \
1289 }
1290
1291 if (dateTime == NULL)
1292 return -1;
1293
1294 if ((*cur != '-') && (*cur < '0') && (*cur > '9'))
1295 return 1;
1296
1297 dt = xmlSchemaNewValue(XML_SCHEMAS_UNKNOWN);
1298 if (dt == NULL)
1299 return -1;
1300
1301 if ((cur[0] == '-') && (cur[1] == '-')) {
1302 /*
1303 * It's an incomplete date (xs:gMonthDay, xs:gMonth or
1304 * xs:gDay)
1305 */
1306 cur += 2;
1307
1308 /* is it an xs:gDay? */
1309 if (*cur == '-') {
Daniel Veillard455cc072003-03-31 10:13:23 +00001310 if (type == XML_SCHEMAS_GMONTH)
1311 goto error;
Daniel Veillard070803b2002-05-03 07:29:38 +00001312 ++cur;
1313 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
1314 if (ret != 0)
1315 goto error;
1316
1317 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GDAY);
1318
1319 goto error;
1320 }
1321
1322 /*
1323 * it should be an xs:gMonthDay or xs:gMonth
1324 */
1325 ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
1326 if (ret != 0)
1327 goto error;
1328
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001329 /*
1330 * a '-' char could indicate this type is xs:gMonthDay or
1331 * a negative time zone offset. Check for xs:gMonthDay first.
1332 * Also the first three char's of a negative tzo (-MM:SS) can
1333 * appear to be a valid day; so even if the day portion
1334 * of the xs:gMonthDay verifies, we must insure it was not
1335 * a tzo.
1336 */
1337 if (*cur == '-') {
1338 const xmlChar *rewnd = cur;
1339 cur++;
Daniel Veillard070803b2002-05-03 07:29:38 +00001340
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001341 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
1342 if ((ret == 0) && ((*cur == 0) || (*cur != ':'))) {
1343
1344 /*
1345 * we can use the VALID_MDAY macro to validate the month
1346 * and day because the leap year test will flag year zero
1347 * as a leap year (even though zero is an invalid year).
1348 */
1349 if (VALID_MDAY((&(dt->value.date)))) {
1350
1351 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTHDAY);
1352
1353 goto error;
1354 }
1355 }
1356
1357 /*
1358 * not xs:gMonthDay so rewind and check if just xs:gMonth
1359 * with an optional time zone.
1360 */
1361 cur = rewnd;
1362 }
1363
1364 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTH);
Daniel Veillard070803b2002-05-03 07:29:38 +00001365
1366 goto error;
1367 }
1368
1369 /*
1370 * It's a right-truncated date or an xs:time.
1371 * Try to parse an xs:time then fallback on right-truncated dates.
1372 */
1373 if ((*cur >= '0') && (*cur <= '9')) {
1374 ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
1375 if (ret == 0) {
1376 /* it's an xs:time */
1377 RETURN_TYPE_IF_VALID(XML_SCHEMAS_TIME);
1378 }
1379 }
1380
1381 /* fallback on date parsing */
1382 cur = dateTime;
1383
1384 ret = _xmlSchemaParseGYear(&(dt->value.date), &cur);
1385 if (ret != 0)
1386 goto error;
1387
1388 /* is it an xs:gYear? */
1389 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEAR);
1390
1391 if (*cur != '-')
1392 goto error;
1393 cur++;
1394
1395 ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
1396 if (ret != 0)
1397 goto error;
1398
1399 /* is it an xs:gYearMonth? */
1400 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEARMONTH);
1401
1402 if (*cur != '-')
1403 goto error;
1404 cur++;
1405
1406 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
1407 if ((ret != 0) || !VALID_DATE((&(dt->value.date))))
1408 goto error;
1409
1410 /* is it an xs:date? */
1411 RETURN_TYPE_IF_VALID(XML_SCHEMAS_DATE);
1412
1413 if (*cur != 'T')
1414 goto error;
1415 cur++;
1416
1417 /* it should be an xs:dateTime */
1418 ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
1419 if (ret != 0)
1420 goto error;
1421
1422 ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur);
1423 if ((ret != 0) || (*cur != 0) || !VALID_DATETIME((&(dt->value.date))))
1424 goto error;
1425
Daniel Veillard455cc072003-03-31 10:13:23 +00001426
Daniel Veillard070803b2002-05-03 07:29:38 +00001427 dt->type = XML_SCHEMAS_DATETIME;
1428
Daniel Veillard455cc072003-03-31 10:13:23 +00001429done:
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001430#if 1
1431 if ((type != XML_SCHEMAS_UNKNOWN) && (type != dt->type))
1432 goto error;
1433#else
1434 /*
1435 * insure the parsed type is equal to or less significant (right
1436 * truncated) than the desired type.
1437 */
1438 if ((type != XML_SCHEMAS_UNKNOWN) && (type != dt->type)) {
1439
1440 /* time only matches time */
1441 if ((type == XML_SCHEMAS_TIME) && (dt->type == XML_SCHEMAS_TIME))
1442 goto error;
1443
1444 if ((type == XML_SCHEMAS_DATETIME) &&
1445 ((dt->type != XML_SCHEMAS_DATE) ||
1446 (dt->type != XML_SCHEMAS_GYEARMONTH) ||
1447 (dt->type != XML_SCHEMAS_GYEAR)))
1448 goto error;
1449
1450 if ((type == XML_SCHEMAS_DATE) &&
1451 ((dt->type != XML_SCHEMAS_GYEAR) ||
1452 (dt->type != XML_SCHEMAS_GYEARMONTH)))
1453 goto error;
1454
1455 if ((type == XML_SCHEMAS_GYEARMONTH) && (dt->type != XML_SCHEMAS_GYEAR))
1456 goto error;
1457
1458 if ((type == XML_SCHEMAS_GMONTHDAY) && (dt->type != XML_SCHEMAS_GMONTH))
1459 goto error;
1460 }
Daniel Veillard455cc072003-03-31 10:13:23 +00001461#endif
1462
Daniel Veillard070803b2002-05-03 07:29:38 +00001463 if (val != NULL)
1464 *val = dt;
Daniel Veillard80b19092003-03-28 13:29:53 +00001465 else
1466 xmlSchemaFreeValue(dt);
Daniel Veillard070803b2002-05-03 07:29:38 +00001467
1468 return 0;
1469
1470error:
1471 if (dt != NULL)
1472 xmlSchemaFreeValue(dt);
1473 return 1;
1474}
1475
1476/**
Daniel Veillard5a872412002-05-22 06:40:27 +00001477 * xmlSchemaValidateDuration:
Daniel Veillard070803b2002-05-03 07:29:38 +00001478 * @type: the predefined type
1479 * @duration: string to analyze
1480 * @val: the return computed value
1481 *
1482 * Check that @duration conforms to the lexical space of the duration type.
1483 * if true a value is computed and returned in @val.
1484 *
1485 * Returns 0 if this validates, a positive error code number otherwise
1486 * and -1 in case of internal or API error.
1487 */
1488static int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00001489xmlSchemaValidateDuration (xmlSchemaTypePtr type ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +00001490 const xmlChar *duration, xmlSchemaValPtr *val) {
Daniel Veillard070803b2002-05-03 07:29:38 +00001491 const xmlChar *cur = duration;
1492 xmlSchemaValPtr dur;
1493 int isneg = 0;
1494 unsigned int seq = 0;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001495 double num;
1496 int num_type = 0; /* -1 = invalid, 0 = int, 1 = floating */
1497 const xmlChar desig[] = {'Y', 'M', 'D', 'H', 'M', 'S'};
1498 const double multi[] = { 0.0, 0.0, 86400.0, 3600.0, 60.0, 1.0, 0.0};
Daniel Veillard070803b2002-05-03 07:29:38 +00001499
1500 if (duration == NULL)
1501 return -1;
1502
1503 if (*cur == '-') {
1504 isneg = 1;
1505 cur++;
1506 }
1507
1508 /* duration must start with 'P' (after sign) */
1509 if (*cur++ != 'P')
1510 return 1;
1511
Daniel Veillard80b19092003-03-28 13:29:53 +00001512 if (*cur == 0)
1513 return 1;
1514
Daniel Veillard070803b2002-05-03 07:29:38 +00001515 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
1516 if (dur == NULL)
1517 return -1;
1518
1519 while (*cur != 0) {
Daniel Veillard070803b2002-05-03 07:29:38 +00001520
1521 /* input string should be empty or invalid date/time item */
1522 if (seq >= sizeof(desig))
1523 goto error;
1524
1525 /* T designator must be present for time items */
1526 if (*cur == 'T') {
1527 if (seq <= 3) {
1528 seq = 3;
1529 cur++;
1530 } else
1531 return 1;
1532 } else if (seq == 3)
1533 goto error;
1534
1535 /* parse the number portion of the item */
1536 PARSE_NUM(num, cur, num_type);
1537
1538 if ((num_type == -1) || (*cur == 0))
1539 goto error;
1540
1541 /* update duration based on item type */
1542 while (seq < sizeof(desig)) {
1543 if (*cur == desig[seq]) {
1544
1545 /* verify numeric type; only seconds can be float */
1546 if ((num_type != 0) && (seq < (sizeof(desig)-1)))
1547 goto error;
1548
1549 switch (seq) {
1550 case 0:
1551 dur->value.dur.mon = (long)num * 12;
1552 break;
1553 case 1:
1554 dur->value.dur.mon += (long)num;
1555 break;
1556 default:
1557 /* convert to seconds using multiplier */
1558 dur->value.dur.sec += num * multi[seq];
1559 seq++;
1560 break;
1561 }
1562
1563 break; /* exit loop */
1564 }
1565 /* no date designators found? */
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00001566 if ((++seq == 3) || (seq == 6))
Daniel Veillard070803b2002-05-03 07:29:38 +00001567 goto error;
1568 }
1569 cur++;
1570 }
1571
1572 if (isneg) {
1573 dur->value.dur.mon = -dur->value.dur.mon;
1574 dur->value.dur.day = -dur->value.dur.day;
1575 dur->value.dur.sec = -dur->value.dur.sec;
1576 }
1577
1578 if (val != NULL)
1579 *val = dur;
Daniel Veillard80b19092003-03-28 13:29:53 +00001580 else
1581 xmlSchemaFreeValue(dur);
Daniel Veillard070803b2002-05-03 07:29:38 +00001582
1583 return 0;
1584
1585error:
1586 if (dur != NULL)
1587 xmlSchemaFreeValue(dur);
1588 return 1;
1589}
1590
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001591/**
1592 * xmlSchemaStrip:
1593 * @value: a value
1594 *
1595 * Removes the leading and ending spaces of a string
1596 *
1597 * Returns the new string or NULL if no change was required.
1598 */
1599static xmlChar *
1600xmlSchemaStrip(const xmlChar *value) {
1601 const xmlChar *start = value, *end, *f;
1602
1603 if (value == NULL) return(NULL);
William M. Brack76e95df2003-10-18 16:20:14 +00001604 while ((*start != 0) && (IS_BLANK_CH(*start))) start++;
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001605 end = start;
1606 while (*end != 0) end++;
1607 f = end;
1608 end--;
William M. Brack76e95df2003-10-18 16:20:14 +00001609 while ((end > start) && (IS_BLANK_CH(*end))) end--;
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001610 end++;
1611 if ((start == value) && (f == end)) return(NULL);
1612 return(xmlStrndup(start, end - start));
1613}
Daniel Veillard96a4b252003-02-06 08:22:32 +00001614
1615/**
Kasimier T. Buchcik91feaf82004-11-12 14:04:58 +00001616 * xmlSchemaWhiteSpaceReplace:
1617 * @value: a value
1618 *
1619 * Replaces 0xd, 0x9 and 0xa with a space.
1620 *
1621 * Returns the new string or NULL if no change was required.
1622 */
1623xmlChar *
1624xmlSchemaWhiteSpaceReplace(const xmlChar *value) {
1625 const xmlChar *cur = value;
1626 xmlChar *ret = NULL, *mcur;
1627
1628 if (value == NULL)
1629 return(NULL);
1630
1631 while ((*cur != 0) &&
1632 (((*cur) != 0xd) && ((*cur) != 0x9) && ((*cur) != 0xa))) {
1633 cur++;
1634 }
1635 if (*cur == 0)
1636 return (NULL);
1637 ret = xmlStrdup(value);
1638 /* TODO FIXME: I guess gcc will bark at this. */
1639 mcur = (xmlChar *) (ret + (cur - value));
1640 do {
1641 if ( ((*mcur) == 0xd) || ((*mcur) == 0x9) || ((*mcur) == 0xa) )
1642 *mcur = ' ';
1643 mcur++;
1644 } while (*mcur != 0);
1645 return(ret);
1646}
1647
1648/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001649 * xmlSchemaCollapseString:
1650 * @value: a value
1651 *
1652 * Removes and normalize white spaces in the string
1653 *
1654 * Returns the new string or NULL if no change was required.
1655 */
Daniel Veillard01fa6152004-06-29 17:04:39 +00001656xmlChar *
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001657xmlSchemaCollapseString(const xmlChar *value) {
1658 const xmlChar *start = value, *end, *f;
1659 xmlChar *g;
1660 int col = 0;
1661
1662 if (value == NULL) return(NULL);
William M. Brack76e95df2003-10-18 16:20:14 +00001663 while ((*start != 0) && (IS_BLANK_CH(*start))) start++;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001664 end = start;
1665 while (*end != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00001666 if ((*end == ' ') && (IS_BLANK_CH(end[1]))) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001667 col = end - start;
1668 break;
1669 } else if ((*end == 0xa) || (*end == 0x9) || (*end == 0xd)) {
1670 col = end - start;
1671 break;
1672 }
1673 end++;
1674 }
1675 if (col == 0) {
1676 f = end;
1677 end--;
William M. Brack76e95df2003-10-18 16:20:14 +00001678 while ((end > start) && (IS_BLANK_CH(*end))) end--;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001679 end++;
1680 if ((start == value) && (f == end)) return(NULL);
1681 return(xmlStrndup(start, end - start));
1682 }
1683 start = xmlStrdup(start);
1684 if (start == NULL) return(NULL);
1685 g = (xmlChar *) (start + col);
1686 end = g;
1687 while (*end != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00001688 if (IS_BLANK_CH(*end)) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001689 end++;
William M. Brack76e95df2003-10-18 16:20:14 +00001690 while (IS_BLANK_CH(*end)) end++;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001691 if (*end != 0)
1692 *g++ = ' ';
1693 } else
1694 *g++ = *end++;
1695 }
1696 *g = 0;
1697 return((xmlChar *) start);
1698}
1699
1700/**
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001701 * xmlSchemaValAtomicListNode:
1702 * @type: the predefined atomic type for a token in the list
1703 * @value: the list value to check
1704 * @ret: the return computed value
1705 * @node: the node containing the value
1706 *
1707 * Check that a value conforms to the lexical space of the predefined
1708 * list type. if true a value is computed and returned in @ret.
1709 *
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001710 * Returns the number of items if this validates, a negative error code
1711 * number otherwise
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001712 */
1713static int
1714xmlSchemaValAtomicListNode(xmlSchemaTypePtr type, const xmlChar *value,
1715 xmlSchemaValPtr *ret, xmlNodePtr node) {
1716 xmlChar *val, *cur, *endval;
1717 int nb_values = 0;
Daniel Veillard580ced82003-03-21 21:22:48 +00001718 int tmp = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001719
1720 if (value == NULL) {
1721 return(-1);
1722 }
1723 val = xmlStrdup(value);
1724 if (val == NULL) {
1725 return(-1);
1726 }
Daniel Veillard6fc5db02005-01-16 00:05:58 +00001727 if (ret != NULL) {
1728 *ret = NULL;
1729 }
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001730 cur = val;
1731 /*
1732 * Split the list
1733 */
William M. Brack76e95df2003-10-18 16:20:14 +00001734 while (IS_BLANK_CH(*cur)) *cur++ = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001735 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00001736 if (IS_BLANK_CH(*cur)) {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001737 *cur = 0;
1738 cur++;
William M. Brack76e95df2003-10-18 16:20:14 +00001739 while (IS_BLANK_CH(*cur)) *cur++ = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001740 } else {
1741 nb_values++;
1742 cur++;
William M. Brack76e95df2003-10-18 16:20:14 +00001743 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001744 }
1745 }
1746 if (nb_values == 0) {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001747 xmlFree(val);
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001748 return(nb_values);
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001749 }
1750 endval = cur;
1751 cur = val;
1752 while ((*cur == 0) && (cur != endval)) cur++;
1753 while (cur != endval) {
1754 tmp = xmlSchemaValPredefTypeNode(type, cur, NULL, node);
1755 if (tmp != 0)
1756 break;
1757 while (*cur != 0) cur++;
1758 while ((*cur == 0) && (cur != endval)) cur++;
1759 }
Daniel Veillard6fc5db02005-01-16 00:05:58 +00001760 /* TODO what return value ? c.f. bug #158628
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001761 if (ret != NULL) {
1762 TODO
Daniel Veillard6fc5db02005-01-16 00:05:58 +00001763 } */
1764 xmlFree(val);
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001765 if (tmp == 0)
1766 return(nb_values);
1767 return(-1);
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001768}
1769
1770/**
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001771 * xmlSchemaParseUInt:
1772 * @str: pointer to the string R/W
1773 * @llo: pointer to the low result
1774 * @lmi: pointer to the mid result
1775 * @lhi: pointer to the high result
1776 *
1777 * Parse an unsigned long into 3 fields.
1778 *
William M. Brackec3b4b72005-03-15 15:50:17 +00001779 * Returns the number of significant digits in the number or
1780 * -1 if overflow of the capacity
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001781 */
1782static int
1783xmlSchemaParseUInt(const xmlChar **str, unsigned long *llo,
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00001784 unsigned long *lmi, unsigned long *lhi) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001785 unsigned long lo = 0, mi = 0, hi = 0;
1786 const xmlChar *tmp, *cur = *str;
1787 int ret = 0, i = 0;
1788
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00001789 while (*cur == '0') { /* ignore leading zeroes */
1790 cur++;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001791 }
1792 tmp = cur;
1793 while ((*tmp != 0) && (*tmp >= '0') && (*tmp <= '9')) {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00001794 i++;tmp++;ret++;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001795 }
1796 if (i > 24) {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00001797 *str = tmp;
1798 return(-1);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001799 }
1800 while (i > 16) {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00001801 hi = hi * 10 + (*cur++ - '0');
1802 i--;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001803 }
1804 while (i > 8) {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00001805 mi = mi * 10 + (*cur++ - '0');
1806 i--;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001807 }
1808 while (i > 0) {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00001809 lo = lo * 10 + (*cur++ - '0');
1810 i--;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001811 }
1812
1813 *str = cur;
1814 *llo = lo;
1815 *lmi = mi;
1816 *lhi = hi;
1817 return(ret);
1818}
1819
1820/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001821 * xmlSchemaValAtomicType:
1822 * @type: the predefined type
1823 * @value: the value to check
1824 * @val: the return computed value
1825 * @node: the node containing the value
1826 * flags: flags to control the vlidation
1827 *
1828 * Check that a value conforms to the lexical space of the atomic type.
1829 * if true a value is computed and returned in @val.
Daniel Veillard01fa6152004-06-29 17:04:39 +00001830 * This checks the value space for list types as well (IDREFS, NMTOKENS).
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001831 *
1832 * Returns 0 if this validates, a positive error code number otherwise
1833 * and -1 in case of internal or API error.
1834 */
1835static int
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001836xmlSchemaValAtomicType(xmlSchemaTypePtr type, const xmlChar * value,
1837 xmlSchemaValPtr * val, xmlNodePtr node, int flags)
1838{
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001839 xmlSchemaValPtr v;
1840 xmlChar *norm = NULL;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001841 int ret = 0;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001842
1843 if (xmlSchemaTypesInitialized == 0)
Daniel Veillard01fa6152004-06-29 17:04:39 +00001844 xmlSchemaInitTypes();
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001845 if (type == NULL)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001846 return (-1);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001847
Daniel Veillardeebd6332004-08-26 10:30:44 +00001848 /*
1849 * validating a non existant text node is similar to validating
1850 * an empty one.
1851 */
1852 if (value == NULL)
1853 value = BAD_CAST "";
1854
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001855 if (val != NULL)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001856 *val = NULL;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001857 if ((flags == 0) && (value != NULL)) {
Kasimier T. Buchcik91feaf82004-11-12 14:04:58 +00001858
Daniel Veillard01fa6152004-06-29 17:04:39 +00001859 if ((type->builtInType != XML_SCHEMAS_STRING) &&
Kasimier T. Buchcik91feaf82004-11-12 14:04:58 +00001860 (type->builtInType != XML_SCHEMAS_ANYTYPE) &&
1861 (type->builtInType != XML_SCHEMAS_ANYSIMPLETYPE)) {
1862 if (type->builtInType == XML_SCHEMAS_NORMSTRING)
1863 norm = xmlSchemaWhiteSpaceReplace(value);
1864 else
1865 norm = xmlSchemaCollapseString(value);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001866 if (norm != NULL)
1867 value = norm;
1868 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001869 }
1870
Daniel Veillard01fa6152004-06-29 17:04:39 +00001871 switch (type->builtInType) {
William M. Brack2f2a6632004-08-20 23:09:47 +00001872 case XML_SCHEMAS_UNKNOWN:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001873 goto error;
William M. Brack2f2a6632004-08-20 23:09:47 +00001874 case XML_SCHEMAS_ANYTYPE:
1875 case XML_SCHEMAS_ANYSIMPLETYPE:
1876 goto return0;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001877 case XML_SCHEMAS_STRING:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001878 goto return0;
Daniel Veillard1516d5b2004-01-22 07:27:45 +00001879 case XML_SCHEMAS_NORMSTRING:{
1880 const xmlChar *cur = value;
1881
1882 while (*cur != 0) {
1883 if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) {
1884 goto return1;
1885 } else {
1886 cur++;
1887 }
1888 }
1889 if (val != NULL) {
1890 v = xmlSchemaNewValue(XML_SCHEMAS_NORMSTRING);
1891 if (v != NULL) {
1892 v->value.str = xmlStrdup(value);
1893 *val = v;
1894 } else {
1895 goto error;
1896 }
1897 }
1898 goto return0;
1899 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001900 case XML_SCHEMAS_DECIMAL:{
William M. Brack273670f2005-03-11 15:55:14 +00001901 const xmlChar *cur = value;
1902 unsigned int len, neg = 0;
1903 xmlChar cval[25];
1904 xmlChar *cptr = cval;
1905 int dec = -1;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001906
1907 if (cur == NULL)
1908 goto return1;
William M. Brack273670f2005-03-11 15:55:14 +00001909 /* First we handle an optional sign */
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001910 if (*cur == '+')
1911 cur++;
1912 else if (*cur == '-') {
1913 neg = 1;
1914 cur++;
1915 }
William M. Brack273670f2005-03-11 15:55:14 +00001916 /*
1917 * Next we "pre-parse" the number, in preparation for calling
1918 * the common routine xmlSchemaParseUInt. We get rid of any
1919 * leading zeroes (because we have reserved only 25 chars),
1920 * and note the position of any decimal point.
1921 */
1922 len = 0;
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00001923 /*
1924 * Skip leading zeroes.
1925 */
1926 while (*cur == '0')
William M. Brack273670f2005-03-11 15:55:14 +00001927 cur++;
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00001928 if (*cur != 0) {
1929 while (len < 24) {
1930 if ((*cur >= '0') && (*cur <= '9')) {
1931 *cptr++ = *cur++;
1932 len++;
1933 } else if (*cur == '.') {
1934 if (dec != -1)
1935 goto return1; /* multiple decimal points */
1936 cur++;
1937 if ((*cur == 0) && (cur -1 == value))
1938 goto return1;
1939
1940 dec = len;
1941 while ((len < 24) && (*cur >= '0') &&
1942 (*cur <= '9')) {
1943 *cptr++ = *cur++;
1944 len++;
1945 }
1946 break;
1947 } else
1948 break;
1949 }
William M. Brack273670f2005-03-11 15:55:14 +00001950 }
1951 if (*cur != 0)
1952 goto return1; /* error if any extraneous chars */
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001953 if (val != NULL) {
1954 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
1955 if (v != NULL) {
William M. Brack273670f2005-03-11 15:55:14 +00001956 /*
1957 * If a mixed decimal, get rid of trailing zeroes
1958 */
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00001959 if (dec != -1) {
William M. Brack273670f2005-03-11 15:55:14 +00001960 while ((cptr > cval) && (*(cptr-1) == '0')) {
1961 cptr--;
1962 len--;
1963 }
1964 }
1965 *cptr = 0; /* Terminate our (preparsed) string */
1966 cptr = cval;
1967 /*
1968 * Now evaluate the significant digits of the number
1969 */
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00001970 if (*cptr != 0)
1971 xmlSchemaParseUInt((const xmlChar **)&cptr,
William M. Brack273670f2005-03-11 15:55:14 +00001972 &v->value.decimal.lo,
1973 &v->value.decimal.mi,
1974 &v->value.decimal.hi);
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00001975 /*
1976 * Set the total digits to 1 if a zero value.
1977 */
1978 if (len == 0)
1979 len++;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001980 v->value.decimal.sign = neg;
William M. Brack273670f2005-03-11 15:55:14 +00001981 if (dec == -1) {
1982 v->value.decimal.frac = 0;
1983 v->value.decimal.total = len;
1984 } else {
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00001985 v->value.decimal.frac = len - dec;
1986 v->value.decimal.total = len;
William M. Brack273670f2005-03-11 15:55:14 +00001987 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001988 *val = v;
1989 }
1990 }
1991 goto return0;
1992 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001993 case XML_SCHEMAS_TIME:
1994 case XML_SCHEMAS_GDAY:
1995 case XML_SCHEMAS_GMONTH:
1996 case XML_SCHEMAS_GMONTHDAY:
1997 case XML_SCHEMAS_GYEAR:
1998 case XML_SCHEMAS_GYEARMONTH:
1999 case XML_SCHEMAS_DATE:
2000 case XML_SCHEMAS_DATETIME:
Daniel Veillard01fa6152004-06-29 17:04:39 +00002001 ret = xmlSchemaValidateDates(type->builtInType, value, val);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002002 break;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002003 case XML_SCHEMAS_DURATION:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002004 ret = xmlSchemaValidateDuration(type, value, val);
2005 break;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002006 case XML_SCHEMAS_FLOAT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002007 case XML_SCHEMAS_DOUBLE:{
2008 const xmlChar *cur = value;
2009 int neg = 0;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002010
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002011 if (cur == NULL)
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00002012 goto return1;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002013 if ((cur[0] == 'N') && (cur[1] == 'a') && (cur[2] == 'N')) {
2014 cur += 3;
2015 if (*cur != 0)
2016 goto return1;
2017 if (val != NULL) {
2018 if (type == xmlSchemaTypeFloatDef) {
2019 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
2020 if (v != NULL) {
2021 v->value.f = (float) xmlXPathNAN;
2022 } else {
2023 xmlSchemaFreeValue(v);
2024 goto error;
2025 }
2026 } else {
2027 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
2028 if (v != NULL) {
2029 v->value.d = xmlXPathNAN;
2030 } else {
2031 xmlSchemaFreeValue(v);
2032 goto error;
2033 }
2034 }
2035 *val = v;
2036 }
2037 goto return0;
2038 }
2039 if (*cur == '-') {
2040 neg = 1;
2041 cur++;
2042 }
2043 if ((cur[0] == 'I') && (cur[1] == 'N') && (cur[2] == 'F')) {
2044 cur += 3;
2045 if (*cur != 0)
2046 goto return1;
2047 if (val != NULL) {
2048 if (type == xmlSchemaTypeFloatDef) {
2049 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
2050 if (v != NULL) {
2051 if (neg)
2052 v->value.f = (float) xmlXPathNINF;
2053 else
2054 v->value.f = (float) xmlXPathPINF;
2055 } else {
2056 xmlSchemaFreeValue(v);
2057 goto error;
2058 }
2059 } else {
2060 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
2061 if (v != NULL) {
2062 if (neg)
2063 v->value.d = xmlXPathNINF;
2064 else
2065 v->value.d = xmlXPathPINF;
2066 } else {
2067 xmlSchemaFreeValue(v);
2068 goto error;
2069 }
2070 }
2071 *val = v;
2072 }
2073 goto return0;
2074 }
2075 if ((neg == 0) && (*cur == '+'))
2076 cur++;
2077 if ((cur[0] == 0) || (cur[0] == '+') || (cur[0] == '-'))
2078 goto return1;
2079 while ((*cur >= '0') && (*cur <= '9')) {
2080 cur++;
2081 }
2082 if (*cur == '.') {
2083 cur++;
2084 while ((*cur >= '0') && (*cur <= '9'))
2085 cur++;
2086 }
2087 if ((*cur == 'e') || (*cur == 'E')) {
2088 cur++;
2089 if ((*cur == '-') || (*cur == '+'))
2090 cur++;
2091 while ((*cur >= '0') && (*cur <= '9'))
2092 cur++;
2093 }
2094 if (*cur != 0)
2095 goto return1;
2096 if (val != NULL) {
2097 if (type == xmlSchemaTypeFloatDef) {
2098 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
2099 if (v != NULL) {
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00002100 /*
2101 * TODO: sscanf seems not to give the correct
2102 * value for extremely high/low values.
2103 * E.g. "1E-149" results in zero.
2104 */
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002105 if (sscanf((const char *) value, "%f",
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002106 &(v->value.f)) == 1) {
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00002107 *val = v;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002108 } else {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002109 xmlSchemaFreeValue(v);
2110 goto return1;
2111 }
2112 } else {
2113 goto error;
2114 }
2115 } else {
2116 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
2117 if (v != NULL) {
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00002118 /*
2119 * TODO: sscanf seems not to give the correct
2120 * value for extremely high/low values.
2121 */
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002122 if (sscanf((const char *) value, "%lf",
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002123 &(v->value.d)) == 1) {
2124 *val = v;
2125 } else {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002126 xmlSchemaFreeValue(v);
2127 goto return1;
2128 }
2129 } else {
2130 goto error;
2131 }
2132 }
2133 }
2134 goto return0;
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00002135 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002136 case XML_SCHEMAS_BOOLEAN:{
2137 const xmlChar *cur = value;
2138
2139 if ((cur[0] == '0') && (cur[1] == 0))
2140 ret = 0;
2141 else if ((cur[0] == '1') && (cur[1] == 0))
2142 ret = 1;
2143 else if ((cur[0] == 't') && (cur[1] == 'r')
2144 && (cur[2] == 'u') && (cur[3] == 'e')
2145 && (cur[4] == 0))
2146 ret = 1;
2147 else if ((cur[0] == 'f') && (cur[1] == 'a')
2148 && (cur[2] == 'l') && (cur[3] == 's')
2149 && (cur[4] == 'e') && (cur[5] == 0))
2150 ret = 0;
2151 else
2152 goto return1;
2153 if (val != NULL) {
2154 v = xmlSchemaNewValue(XML_SCHEMAS_BOOLEAN);
2155 if (v != NULL) {
2156 v->value.b = ret;
2157 *val = v;
2158 } else {
2159 goto error;
2160 }
2161 }
2162 goto return0;
2163 }
2164 case XML_SCHEMAS_TOKEN:{
2165 const xmlChar *cur = value;
2166
William M. Brack76e95df2003-10-18 16:20:14 +00002167 if (IS_BLANK_CH(*cur))
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002168 goto return1;
2169
2170 while (*cur != 0) {
2171 if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) {
2172 goto return1;
2173 } else if (*cur == ' ') {
2174 cur++;
2175 if (*cur == 0)
2176 goto return1;
2177 if (*cur == ' ')
2178 goto return1;
2179 } else {
2180 cur++;
2181 }
2182 }
2183 if (val != NULL) {
2184 v = xmlSchemaNewValue(XML_SCHEMAS_TOKEN);
2185 if (v != NULL) {
2186 v->value.str = xmlStrdup(value);
2187 *val = v;
2188 } else {
2189 goto error;
2190 }
2191 }
2192 goto return0;
2193 }
2194 case XML_SCHEMAS_LANGUAGE:
2195 if (xmlCheckLanguageID(value) == 1) {
2196 if (val != NULL) {
2197 v = xmlSchemaNewValue(XML_SCHEMAS_LANGUAGE);
2198 if (v != NULL) {
2199 v->value.str = xmlStrdup(value);
2200 *val = v;
2201 } else {
2202 goto error;
2203 }
2204 }
2205 goto return0;
2206 }
2207 goto return1;
2208 case XML_SCHEMAS_NMTOKEN:
2209 if (xmlValidateNMToken(value, 1) == 0) {
2210 if (val != NULL) {
2211 v = xmlSchemaNewValue(XML_SCHEMAS_NMTOKEN);
2212 if (v != NULL) {
2213 v->value.str = xmlStrdup(value);
2214 *val = v;
2215 } else {
2216 goto error;
2217 }
2218 }
2219 goto return0;
2220 }
2221 goto return1;
2222 case XML_SCHEMAS_NMTOKENS:
2223 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeNmtokenDef,
2224 value, val, node);
2225 if (ret > 0)
2226 ret = 0;
2227 else
2228 ret = 1;
2229 goto done;
2230 case XML_SCHEMAS_NAME:
2231 ret = xmlValidateName(value, 1);
Daniel Veillarddf292f72005-01-16 19:00:15 +00002232 if ((ret == 0) && (val != NULL) && (value != NULL)) {
2233 v = xmlSchemaNewValue(XML_SCHEMAS_NAME);
2234 if (v != NULL) {
2235 const xmlChar *start = value, *end;
2236 while (IS_BLANK_CH(*start)) start++;
2237 end = start;
2238 while ((*end != 0) && (!IS_BLANK_CH(*end))) end++;
2239 v->value.str = xmlStrndup(start, end - start);
2240 *val = v;
2241 } else {
2242 goto error;
2243 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002244 }
2245 goto done;
2246 case XML_SCHEMAS_QNAME:{
2247 xmlChar *uri = NULL;
2248 xmlChar *local = NULL;
2249
2250 ret = xmlValidateQName(value, 1);
2251 if ((ret == 0) && (node != NULL)) {
2252 xmlChar *prefix;
2253
2254 local = xmlSplitQName2(value, &prefix);
2255 if (prefix != NULL) {
2256 xmlNsPtr ns;
2257
2258 ns = xmlSearchNs(node->doc, node, prefix);
2259 if (ns == NULL)
2260 ret = 1;
2261 else if (val != NULL)
2262 uri = xmlStrdup(ns->href);
2263 }
2264 if ((local != NULL) && ((val == NULL) || (ret != 0)))
2265 xmlFree(local);
2266 if (prefix != NULL)
2267 xmlFree(prefix);
2268 }
2269 if ((ret == 0) && (val != NULL)) {
2270 v = xmlSchemaNewValue(XML_SCHEMAS_QNAME);
2271 if (v != NULL) {
2272 if (local != NULL)
2273 v->value.qname.name = local;
2274 else
2275 v->value.qname.name = xmlStrdup(value);
2276 if (uri != NULL)
2277 v->value.qname.uri = uri;
2278
2279 *val = v;
2280 } else {
2281 if (local != NULL)
2282 xmlFree(local);
2283 if (uri != NULL)
2284 xmlFree(uri);
2285 goto error;
2286 }
2287 }
2288 goto done;
2289 }
2290 case XML_SCHEMAS_NCNAME:
2291 ret = xmlValidateNCName(value, 1);
2292 if ((ret == 0) && (val != NULL)) {
2293 v = xmlSchemaNewValue(XML_SCHEMAS_NCNAME);
2294 if (v != NULL) {
2295 v->value.str = xmlStrdup(value);
2296 *val = v;
2297 } else {
2298 goto error;
2299 }
2300 }
2301 goto done;
2302 case XML_SCHEMAS_ID:
2303 ret = xmlValidateNCName(value, 1);
2304 if ((ret == 0) && (val != NULL)) {
2305 v = xmlSchemaNewValue(XML_SCHEMAS_ID);
2306 if (v != NULL) {
2307 v->value.str = xmlStrdup(value);
2308 *val = v;
2309 } else {
2310 goto error;
2311 }
2312 }
2313 if ((ret == 0) && (node != NULL) &&
2314 (node->type == XML_ATTRIBUTE_NODE)) {
2315 xmlAttrPtr attr = (xmlAttrPtr) node;
2316
2317 /*
2318 * NOTE: the IDness might have already be declared in the DTD
2319 */
2320 if (attr->atype != XML_ATTRIBUTE_ID) {
2321 xmlIDPtr res;
2322 xmlChar *strip;
2323
2324 strip = xmlSchemaStrip(value);
2325 if (strip != NULL) {
2326 res = xmlAddID(NULL, node->doc, strip, attr);
2327 xmlFree(strip);
2328 } else
2329 res = xmlAddID(NULL, node->doc, value, attr);
2330 if (res == NULL) {
2331 ret = 2;
2332 } else {
2333 attr->atype = XML_ATTRIBUTE_ID;
2334 }
2335 }
2336 }
2337 goto done;
2338 case XML_SCHEMAS_IDREF:
2339 ret = xmlValidateNCName(value, 1);
2340 if ((ret == 0) && (val != NULL)) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00002341 v = xmlSchemaNewValue(XML_SCHEMAS_IDREF);
2342 if (v == NULL)
2343 goto error;
2344 v->value.str = xmlStrdup(value);
2345 *val = v;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002346 }
2347 if ((ret == 0) && (node != NULL) &&
2348 (node->type == XML_ATTRIBUTE_NODE)) {
2349 xmlAttrPtr attr = (xmlAttrPtr) node;
2350 xmlChar *strip;
2351
2352 strip = xmlSchemaStrip(value);
2353 if (strip != NULL) {
2354 xmlAddRef(NULL, node->doc, strip, attr);
2355 xmlFree(strip);
2356 } else
2357 xmlAddRef(NULL, node->doc, value, attr);
2358 attr->atype = XML_ATTRIBUTE_IDREF;
2359 }
2360 goto done;
2361 case XML_SCHEMAS_IDREFS:
2362 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeIdrefDef,
2363 value, val, node);
2364 if (ret < 0)
2365 ret = 2;
2366 else
2367 ret = 0;
2368 if ((ret == 0) && (node != NULL) &&
2369 (node->type == XML_ATTRIBUTE_NODE)) {
2370 xmlAttrPtr attr = (xmlAttrPtr) node;
2371
2372 attr->atype = XML_ATTRIBUTE_IDREFS;
2373 }
2374 goto done;
2375 case XML_SCHEMAS_ENTITY:{
2376 xmlChar *strip;
2377
2378 ret = xmlValidateNCName(value, 1);
2379 if ((node == NULL) || (node->doc == NULL))
2380 ret = 3;
2381 if (ret == 0) {
2382 xmlEntityPtr ent;
2383
2384 strip = xmlSchemaStrip(value);
2385 if (strip != NULL) {
2386 ent = xmlGetDocEntity(node->doc, strip);
2387 xmlFree(strip);
2388 } else {
2389 ent = xmlGetDocEntity(node->doc, value);
2390 }
2391 if ((ent == NULL) ||
2392 (ent->etype !=
2393 XML_EXTERNAL_GENERAL_UNPARSED_ENTITY))
2394 ret = 4;
2395 }
2396 if ((ret == 0) && (val != NULL)) {
2397 TODO;
2398 }
2399 if ((ret == 0) && (node != NULL) &&
2400 (node->type == XML_ATTRIBUTE_NODE)) {
2401 xmlAttrPtr attr = (xmlAttrPtr) node;
2402
2403 attr->atype = XML_ATTRIBUTE_ENTITY;
2404 }
2405 goto done;
2406 }
2407 case XML_SCHEMAS_ENTITIES:
2408 if ((node == NULL) || (node->doc == NULL))
2409 goto return3;
2410 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeEntityDef,
2411 value, val, node);
2412 if (ret <= 0)
2413 ret = 1;
2414 else
2415 ret = 0;
2416 if ((ret == 0) && (node != NULL) &&
2417 (node->type == XML_ATTRIBUTE_NODE)) {
2418 xmlAttrPtr attr = (xmlAttrPtr) node;
2419
2420 attr->atype = XML_ATTRIBUTE_ENTITIES;
2421 }
2422 goto done;
2423 case XML_SCHEMAS_NOTATION:{
2424 xmlChar *uri = NULL;
2425 xmlChar *local = NULL;
2426
2427 ret = xmlValidateQName(value, 1);
2428 if ((ret == 0) && (node != NULL)) {
2429 xmlChar *prefix;
2430
2431 local = xmlSplitQName2(value, &prefix);
2432 if (prefix != NULL) {
2433 xmlNsPtr ns;
2434
2435 ns = xmlSearchNs(node->doc, node, prefix);
2436 if (ns == NULL)
2437 ret = 1;
2438 else if (val != NULL)
2439 uri = xmlStrdup(ns->href);
2440 }
2441 if ((local != NULL) && ((val == NULL) || (ret != 0)))
2442 xmlFree(local);
2443 if (prefix != NULL)
2444 xmlFree(prefix);
2445 }
2446 if ((node == NULL) || (node->doc == NULL))
2447 ret = 3;
2448 if (ret == 0) {
2449 ret = xmlValidateNotationUse(NULL, node->doc, value);
2450 if (ret == 1)
2451 ret = 0;
2452 else
2453 ret = 1;
2454 }
2455 if ((ret == 0) && (val != NULL)) {
2456 v = xmlSchemaNewValue(XML_SCHEMAS_NOTATION);
2457 if (v != NULL) {
2458 if (local != NULL)
2459 v->value.qname.name = local;
2460 else
2461 v->value.qname.name = xmlStrdup(value);
2462 if (uri != NULL)
2463 v->value.qname.uri = uri;
2464
2465 *val = v;
2466 } else {
2467 if (local != NULL)
2468 xmlFree(local);
2469 if (uri != NULL)
2470 xmlFree(uri);
2471 goto error;
2472 }
2473 }
2474 goto done;
2475 }
2476 case XML_SCHEMAS_ANYURI:{
Daniel Veillard11c466a2004-03-14 12:20:15 +00002477 if (*value != 0) {
2478 xmlURIPtr uri = xmlParseURI((const char *) value);
2479 if (uri == NULL)
2480 goto return1;
2481 xmlFreeURI(uri);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002482 }
Daniel Veillard11c466a2004-03-14 12:20:15 +00002483
2484 if (val != NULL) {
2485 v = xmlSchemaNewValue(XML_SCHEMAS_ANYURI);
2486 if (v == NULL)
2487 goto error;
2488 v->value.str = xmlStrdup(value);
2489 *val = v;
2490 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002491 goto return0;
2492 }
2493 case XML_SCHEMAS_HEXBINARY:{
2494 const xmlChar *cur = value;
2495 xmlChar *base;
2496 int total, i = 0;
2497
Daniel Veillardf34a20e2004-08-31 08:42:17 +00002498 if (cur == NULL)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002499 goto return1;
2500
2501 while (((*cur >= '0') && (*cur <= '9')) ||
2502 ((*cur >= 'A') && (*cur <= 'F')) ||
2503 ((*cur >= 'a') && (*cur <= 'f'))) {
2504 i++;
2505 cur++;
2506 }
2507
2508 if (*cur != 0)
2509 goto return1;
2510 if ((i % 2) != 0)
2511 goto return1;
2512
2513 if (val != NULL) {
2514
2515 v = xmlSchemaNewValue(XML_SCHEMAS_HEXBINARY);
2516 if (v == NULL)
2517 goto error;
2518
2519 cur = xmlStrdup(value);
2520 if (cur == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002521 xmlSchemaTypeErrMemory(node, "allocating hexbin data");
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002522 xmlFree(v);
2523 goto return1;
2524 }
2525
2526 total = i / 2; /* number of octets */
2527
2528 base = (xmlChar *) cur;
2529 while (i-- > 0) {
2530 if (*base >= 'a')
2531 *base = *base - ('a' - 'A');
2532 base++;
2533 }
2534
2535 v->value.hex.str = (xmlChar *) cur;
2536 v->value.hex.total = total;
2537 *val = v;
2538 }
2539 goto return0;
2540 }
2541 case XML_SCHEMAS_BASE64BINARY:{
2542 /* ISSUE:
2543 *
2544 * Ignore all stray characters? (yes, currently)
2545 * Worry about long lines? (no, currently)
2546 *
2547 * rfc2045.txt:
2548 *
2549 * "The encoded output stream must be represented in lines of
2550 * no more than 76 characters each. All line breaks or other
2551 * characters not found in Table 1 must be ignored by decoding
2552 * software. In base64 data, characters other than those in
2553 * Table 1, line breaks, and other white space probably
2554 * indicate a transmission error, about which a warning
2555 * message or even a message rejection might be appropriate
2556 * under some circumstances." */
2557 const xmlChar *cur = value;
2558 xmlChar *base;
2559 int total, i = 0, pad = 0;
2560
2561 if (cur == NULL)
2562 goto return1;
2563
2564 for (; *cur; ++cur) {
2565 int decc;
2566
2567 decc = _xmlSchemaBase64Decode(*cur);
2568 if (decc < 0) ;
2569 else if (decc < 64)
2570 i++;
2571 else
2572 break;
2573 }
2574 for (; *cur; ++cur) {
2575 int decc;
2576
2577 decc = _xmlSchemaBase64Decode(*cur);
2578 if (decc < 0) ;
2579 else if (decc < 64)
2580 goto return1;
2581 if (decc == 64)
2582 pad++;
2583 }
2584
2585 /* rfc2045.txt: "Special processing is performed if fewer than
2586 * 24 bits are available at the end of the data being encoded.
2587 * A full encoding quantum is always completed at the end of a
2588 * body. When fewer than 24 input bits are available in an
2589 * input group, zero bits are added (on the right) to form an
2590 * integral number of 6-bit groups. Padding at the end of the
2591 * data is performed using the "=" character. Since all
2592 * base64 input is an integral number of octets, only the
2593 * following cases can arise: (1) the final quantum of
2594 * encoding input is an integral multiple of 24 bits; here,
2595 * the final unit of encoded output will be an integral
2596 * multiple ofindent: Standard input:701: Warning:old style
2597 * assignment ambiguity in "=*". Assuming "= *" 4 characters
2598 * with no "=" padding, (2) the final
2599 * quantum of encoding input is exactly 8 bits; here, the
2600 * final unit of encoded output will be two characters
2601 * followed by two "=" padding characters, or (3) the final
2602 * quantum of encoding input is exactly 16 bits; here, the
2603 * final unit of encoded output will be three characters
2604 * followed by one "=" padding character." */
2605
2606 total = 3 * (i / 4);
2607 if (pad == 0) {
2608 if (i % 4 != 0)
2609 goto return1;
2610 } else if (pad == 1) {
2611 int decc;
2612
2613 if (i % 4 != 3)
2614 goto return1;
2615 for (decc = _xmlSchemaBase64Decode(*cur);
2616 (decc < 0) || (decc > 63);
2617 decc = _xmlSchemaBase64Decode(*cur))
2618 --cur;
2619 /* 16bits in 24bits means 2 pad bits: nnnnnn nnmmmm mmmm00*/
2620 /* 00111100 -> 0x3c */
2621 if (decc & ~0x3c)
2622 goto return1;
2623 total += 2;
2624 } else if (pad == 2) {
2625 int decc;
2626
2627 if (i % 4 != 2)
2628 goto return1;
2629 for (decc = _xmlSchemaBase64Decode(*cur);
2630 (decc < 0) || (decc > 63);
2631 decc = _xmlSchemaBase64Decode(*cur))
2632 --cur;
2633 /* 8bits in 12bits means 4 pad bits: nnnnnn nn0000 */
2634 /* 00110000 -> 0x30 */
2635 if (decc & ~0x30)
2636 goto return1;
2637 total += 1;
2638 } else
2639 goto return1;
2640
2641 if (val != NULL) {
2642 v = xmlSchemaNewValue(XML_SCHEMAS_BASE64BINARY);
2643 if (v == NULL)
2644 goto error;
2645 base =
2646 (xmlChar *) xmlMallocAtomic((i + pad + 1) *
2647 sizeof(xmlChar));
2648 if (base == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002649 xmlSchemaTypeErrMemory(node, "allocating base64 data");
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002650 xmlFree(v);
2651 goto return1;
2652 }
2653 v->value.base64.str = base;
2654 for (cur = value; *cur; ++cur)
2655 if (_xmlSchemaBase64Decode(*cur) >= 0) {
2656 *base = *cur;
2657 ++base;
2658 }
2659 *base = 0;
2660 v->value.base64.total = total;
2661 *val = v;
2662 }
2663 goto return0;
2664 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002665 case XML_SCHEMAS_INTEGER:
2666 case XML_SCHEMAS_PINTEGER:
2667 case XML_SCHEMAS_NPINTEGER:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002668 case XML_SCHEMAS_NINTEGER:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002669 case XML_SCHEMAS_NNINTEGER:{
2670 const xmlChar *cur = value;
2671 unsigned long lo, mi, hi;
William M. Brackec3b4b72005-03-15 15:50:17 +00002672 int sign = 0;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002673
2674 if (cur == NULL)
2675 goto return1;
2676 if (*cur == '-') {
2677 sign = 1;
2678 cur++;
2679 } else if (*cur == '+')
2680 cur++;
William M. Brackec3b4b72005-03-15 15:50:17 +00002681 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2682 if (ret == -1)
2683 goto return1;
2684 if (*cur != 0)
2685 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002686 if (type->builtInType == XML_SCHEMAS_NPINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002687 if ((sign == 0) &&
2688 ((hi != 0) || (mi != 0) || (lo != 0)))
2689 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002690 } else if (type->builtInType == XML_SCHEMAS_PINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002691 if (sign == 1)
2692 goto return1;
2693 if ((hi == 0) && (mi == 0) && (lo == 0))
2694 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002695 } else if (type->builtInType == XML_SCHEMAS_NINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002696 if (sign == 0)
2697 goto return1;
2698 if ((hi == 0) && (mi == 0) && (lo == 0))
2699 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002700 } else if (type->builtInType == XML_SCHEMAS_NNINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002701 if ((sign == 1) &&
2702 ((hi != 0) || (mi != 0) || (lo != 0)))
2703 goto return1;
2704 }
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00002705 if (val != NULL) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00002706 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002707 if (v != NULL) {
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00002708 if (ret == 0)
2709 ret++;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002710 v->value.decimal.lo = lo;
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00002711 v->value.decimal.mi = mi;
2712 v->value.decimal.hi = hi;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002713 v->value.decimal.sign = sign;
2714 v->value.decimal.frac = 0;
William M. Brackec3b4b72005-03-15 15:50:17 +00002715 v->value.decimal.total = ret;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002716 *val = v;
2717 }
2718 }
2719 goto return0;
2720 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002721 case XML_SCHEMAS_LONG:
2722 case XML_SCHEMAS_BYTE:
2723 case XML_SCHEMAS_SHORT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002724 case XML_SCHEMAS_INT:{
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00002725 const xmlChar *cur = value;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002726 unsigned long lo, mi, hi;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002727 int sign = 0;
2728
2729 if (cur == NULL)
2730 goto return1;
2731 if (*cur == '-') {
2732 sign = 1;
2733 cur++;
2734 } else if (*cur == '+')
2735 cur++;
William M. Brackec3b4b72005-03-15 15:50:17 +00002736 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2737 if (ret < 0)
2738 goto return1;
2739 if (*cur != 0)
2740 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002741 if (type->builtInType == XML_SCHEMAS_LONG) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002742 if (hi >= 922) {
2743 if (hi > 922)
2744 goto return1;
2745 if (mi >= 33720368) {
2746 if (mi > 33720368)
2747 goto return1;
2748 if ((sign == 0) && (lo > 54775807))
2749 goto return1;
2750 if ((sign == 1) && (lo > 54775808))
2751 goto return1;
2752 }
2753 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002754 } else if (type->builtInType == XML_SCHEMAS_INT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002755 if (hi != 0)
2756 goto return1;
2757 if (mi >= 21) {
2758 if (mi > 21)
2759 goto return1;
2760 if ((sign == 0) && (lo > 47483647))
2761 goto return1;
2762 if ((sign == 1) && (lo > 47483648))
2763 goto return1;
2764 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002765 } else if (type->builtInType == XML_SCHEMAS_SHORT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002766 if ((mi != 0) || (hi != 0))
2767 goto return1;
2768 if ((sign == 1) && (lo > 32768))
2769 goto return1;
2770 if ((sign == 0) && (lo > 32767))
2771 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002772 } else if (type->builtInType == XML_SCHEMAS_BYTE) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002773 if ((mi != 0) || (hi != 0))
2774 goto return1;
2775 if ((sign == 1) && (lo > 128))
2776 goto return1;
2777 if ((sign == 0) && (lo > 127))
2778 goto return1;
2779 }
2780 if (val != NULL) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00002781 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002782 if (v != NULL) {
2783 v->value.decimal.lo = lo;
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00002784 v->value.decimal.mi = mi;
2785 v->value.decimal.hi = hi;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002786 v->value.decimal.sign = sign;
2787 v->value.decimal.frac = 0;
William M. Brackec3b4b72005-03-15 15:50:17 +00002788 v->value.decimal.total = ret;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002789 *val = v;
2790 }
2791 }
2792 goto return0;
2793 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002794 case XML_SCHEMAS_UINT:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002795 case XML_SCHEMAS_ULONG:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002796 case XML_SCHEMAS_USHORT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002797 case XML_SCHEMAS_UBYTE:{
2798 const xmlChar *cur = value;
2799 unsigned long lo, mi, hi;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002800
2801 if (cur == NULL)
2802 goto return1;
William M. Brackec3b4b72005-03-15 15:50:17 +00002803 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2804 if (ret < 0)
2805 goto return1;
2806 if (*cur != 0)
2807 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002808 if (type->builtInType == XML_SCHEMAS_ULONG) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002809 if (hi >= 1844) {
2810 if (hi > 1844)
2811 goto return1;
2812 if (mi >= 67440737) {
2813 if (mi > 67440737)
2814 goto return1;
2815 if (lo > 9551615)
2816 goto return1;
2817 }
2818 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002819 } else if (type->builtInType == XML_SCHEMAS_UINT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002820 if (hi != 0)
2821 goto return1;
2822 if (mi >= 42) {
2823 if (mi > 42)
2824 goto return1;
2825 if (lo > 94967295)
2826 goto return1;
2827 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002828 } else if (type->builtInType == XML_SCHEMAS_USHORT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002829 if ((mi != 0) || (hi != 0))
2830 goto return1;
2831 if (lo > 65535)
2832 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002833 } else if (type->builtInType == XML_SCHEMAS_UBYTE) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002834 if ((mi != 0) || (hi != 0))
2835 goto return1;
2836 if (lo > 255)
2837 goto return1;
2838 }
2839 if (val != NULL) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00002840 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002841 if (v != NULL) {
2842 v->value.decimal.lo = lo;
2843 v->value.decimal.mi = mi;
2844 v->value.decimal.hi = hi;
2845 v->value.decimal.sign = 0;
2846 v->value.decimal.frac = 0;
William M. Brackec3b4b72005-03-15 15:50:17 +00002847 v->value.decimal.total = ret;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002848 *val = v;
2849 }
2850 }
2851 goto return0;
2852 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002853 }
2854
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002855 done:
2856 if (norm != NULL)
2857 xmlFree(norm);
2858 return (ret);
2859 return3:
2860 if (norm != NULL)
2861 xmlFree(norm);
2862 return (3);
2863 return1:
2864 if (norm != NULL)
2865 xmlFree(norm);
2866 return (1);
2867 return0:
2868 if (norm != NULL)
2869 xmlFree(norm);
2870 return (0);
2871 error:
2872 if (norm != NULL)
2873 xmlFree(norm);
2874 return (-1);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002875}
2876
2877/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002878 * xmlSchemaValPredefTypeNode:
Daniel Veillard4255d502002-04-16 15:50:10 +00002879 * @type: the predefined type
2880 * @value: the value to check
2881 * @val: the return computed value
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002882 * @node: the node containing the value
Daniel Veillard4255d502002-04-16 15:50:10 +00002883 *
2884 * Check that a value conforms to the lexical space of the predefined type.
2885 * if true a value is computed and returned in @val.
2886 *
2887 * Returns 0 if this validates, a positive error code number otherwise
2888 * and -1 in case of internal or API error.
2889 */
2890int
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002891xmlSchemaValPredefTypeNode(xmlSchemaTypePtr type, const xmlChar *value,
2892 xmlSchemaValPtr *val, xmlNodePtr node) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002893 return(xmlSchemaValAtomicType(type, value, val, node, 0));
Daniel Veillard4255d502002-04-16 15:50:10 +00002894}
2895
2896/**
Daniel Veillardc0826a72004-08-10 14:17:33 +00002897 * xmlSchemaValPredefTypeNodeNoNorm:
2898 * @type: the predefined type
2899 * @value: the value to check
2900 * @val: the return computed value
2901 * @node: the node containing the value
2902 *
2903 * Check that a value conforms to the lexical space of the predefined type.
2904 * if true a value is computed and returned in @val.
2905 * This one does apply any normalization to the value.
2906 *
2907 * Returns 0 if this validates, a positive error code number otherwise
2908 * and -1 in case of internal or API error.
2909 */
2910int
2911xmlSchemaValPredefTypeNodeNoNorm(xmlSchemaTypePtr type, const xmlChar *value,
2912 xmlSchemaValPtr *val, xmlNodePtr node) {
2913 return(xmlSchemaValAtomicType(type, value, val, node, 1));
2914}
2915
2916/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002917 * xmlSchemaValidatePredefinedType:
2918 * @type: the predefined type
2919 * @value: the value to check
2920 * @val: the return computed value
2921 *
2922 * Check that a value conforms to the lexical space of the predefined type.
2923 * if true a value is computed and returned in @val.
2924 *
2925 * Returns 0 if this validates, a positive error code number otherwise
2926 * and -1 in case of internal or API error.
2927 */
2928int
2929xmlSchemaValidatePredefinedType(xmlSchemaTypePtr type, const xmlChar *value,
2930 xmlSchemaValPtr *val) {
2931 return(xmlSchemaValPredefTypeNode(type, value, val, NULL));
2932}
2933
2934/**
Daniel Veillard4255d502002-04-16 15:50:10 +00002935 * xmlSchemaCompareDecimals:
2936 * @x: a first decimal value
2937 * @y: a second decimal value
2938 *
2939 * Compare 2 decimals
2940 *
2941 * Returns -1 if x < y, 0 if x == y, 1 if x > y and -2 in case of error
2942 */
2943static int
2944xmlSchemaCompareDecimals(xmlSchemaValPtr x, xmlSchemaValPtr y)
2945{
2946 xmlSchemaValPtr swp;
William M. Brack273670f2005-03-11 15:55:14 +00002947 int order = 1, integx, integy, dlen;
2948 unsigned long hi, mi, lo;
Daniel Veillard4255d502002-04-16 15:50:10 +00002949
William M. Brack273670f2005-03-11 15:55:14 +00002950 /*
2951 * First test: If x is -ve and not zero
2952 */
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002953 if ((x->value.decimal.sign) &&
2954 ((x->value.decimal.lo != 0) ||
2955 (x->value.decimal.mi != 0) ||
2956 (x->value.decimal.hi != 0))) {
William M. Brack273670f2005-03-11 15:55:14 +00002957 /*
2958 * Then if y is -ve and not zero reverse the compare
2959 */
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002960 if ((y->value.decimal.sign) &&
2961 ((y->value.decimal.lo != 0) ||
2962 (y->value.decimal.mi != 0) ||
2963 (y->value.decimal.hi != 0)))
Daniel Veillard80b19092003-03-28 13:29:53 +00002964 order = -1;
William M. Brack273670f2005-03-11 15:55:14 +00002965 /*
2966 * Otherwise (y >= 0) we have the answer
2967 */
Daniel Veillard80b19092003-03-28 13:29:53 +00002968 else
2969 return (-1);
William M. Brack273670f2005-03-11 15:55:14 +00002970 /*
2971 * If x is not -ve and y is -ve we have the answer
2972 */
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002973 } else if ((y->value.decimal.sign) &&
2974 ((y->value.decimal.lo != 0) ||
2975 (y->value.decimal.mi != 0) ||
2976 (y->value.decimal.hi != 0))) {
Daniel Veillard4255d502002-04-16 15:50:10 +00002977 return (1);
Daniel Veillard80b19092003-03-28 13:29:53 +00002978 }
William M. Brack273670f2005-03-11 15:55:14 +00002979 /*
2980 * If it's not simply determined by a difference in sign,
2981 * then we need to compare the actual values of the two nums.
2982 * To do this, we start by looking at the integral parts.
2983 * If the number of integral digits differ, then we have our
2984 * answer.
2985 */
2986 integx = x->value.decimal.total - x->value.decimal.frac;
2987 integy = y->value.decimal.total - y->value.decimal.frac;
2988 if (integx > integy)
2989 return order;
2990 else if (integy > integx)
2991 return -order;
2992 /*
2993 * If the number of integral digits is the same for both numbers,
2994 * then things get a little more complicated. We need to "normalize"
2995 * the numbers in order to properly compare them. To do this, we
2996 * look at the total length of each number (length => number of
2997 * significant digits), and divide the "shorter" by 10 (decreasing
2998 * the length) until they are of equal length.
2999 */
3000 dlen = x->value.decimal.total - y->value.decimal.total;
3001 if (dlen < 0) { /* y has more digits than x */
3002 swp = x;
3003 hi = y->value.decimal.hi;
3004 mi = y->value.decimal.mi;
3005 lo = y->value.decimal.lo;
3006 dlen = -dlen;
3007 order = -order;
3008 } else { /* x has more digits than y */
3009 swp = y;
3010 hi = x->value.decimal.hi;
3011 mi = x->value.decimal.mi;
3012 lo = x->value.decimal.lo;
Daniel Veillard4255d502002-04-16 15:50:10 +00003013 }
William M. Brack273670f2005-03-11 15:55:14 +00003014 while (dlen > 8) { /* in effect, right shift by 10**8 */
3015 lo = mi;
3016 mi = hi;
3017 hi = 0;
3018 dlen -= 8;
Daniel Veillard4255d502002-04-16 15:50:10 +00003019 }
William M. Brack273670f2005-03-11 15:55:14 +00003020 while (dlen > 0) {
3021 unsigned long rem1, rem2;
3022 rem1 = (hi % 10) * 100000000L;
3023 hi = hi / 10;
3024 rem2 = (mi % 10) * 100000000L;
3025 mi = (mi + rem1) / 10;
3026 lo = (lo + rem2) / 10;
3027 dlen--;
3028 }
3029 if (hi > swp->value.decimal.hi) {
3030 return order;
3031 } else if (hi == swp->value.decimal.hi) {
3032 if (mi > swp->value.decimal.mi) {
3033 return order;
3034 } else if (mi == swp->value.decimal.mi) {
3035 if (lo > swp->value.decimal.lo) {
3036 return order;
3037 } else if (lo == swp->value.decimal.lo) {
3038 if (x->value.decimal.total == y->value.decimal.total) {
3039 return 0;
3040 } else {
3041 return order;
3042 }
3043 }
3044 }
3045 }
3046 return -order;
Daniel Veillard4255d502002-04-16 15:50:10 +00003047}
3048
3049/**
Daniel Veillard070803b2002-05-03 07:29:38 +00003050 * xmlSchemaCompareDurations:
3051 * @x: a first duration value
3052 * @y: a second duration value
3053 *
3054 * Compare 2 durations
3055 *
3056 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3057 * case of error
3058 */
3059static int
3060xmlSchemaCompareDurations(xmlSchemaValPtr x, xmlSchemaValPtr y)
3061{
3062 long carry, mon, day;
3063 double sec;
Daniel Veillard80b19092003-03-28 13:29:53 +00003064 int invert = 1;
3065 long xmon, xday, myear, minday, maxday;
Daniel Veillard070803b2002-05-03 07:29:38 +00003066 static const long dayRange [2][12] = {
3067 { 0, 28, 59, 89, 120, 150, 181, 212, 242, 273, 303, 334, },
3068 { 0, 31, 62, 92, 123, 153, 184, 215, 245, 276, 306, 337} };
3069
3070 if ((x == NULL) || (y == NULL))
Daniel Veillard5a872412002-05-22 06:40:27 +00003071 return -2;
Daniel Veillard070803b2002-05-03 07:29:38 +00003072
3073 /* months */
3074 mon = x->value.dur.mon - y->value.dur.mon;
3075
3076 /* seconds */
3077 sec = x->value.dur.sec - y->value.dur.sec;
3078 carry = (long)sec / SECS_PER_DAY;
3079 sec -= (double)(carry * SECS_PER_DAY);
3080
3081 /* days */
3082 day = x->value.dur.day - y->value.dur.day + carry;
3083
3084 /* easy test */
3085 if (mon == 0) {
3086 if (day == 0)
3087 if (sec == 0.0)
3088 return 0;
3089 else if (sec < 0.0)
3090 return -1;
3091 else
3092 return 1;
3093 else if (day < 0)
3094 return -1;
3095 else
3096 return 1;
3097 }
3098
3099 if (mon > 0) {
3100 if ((day >= 0) && (sec >= 0.0))
3101 return 1;
3102 else {
3103 xmon = mon;
3104 xday = -day;
3105 }
3106 } else if ((day <= 0) && (sec <= 0.0)) {
3107 return -1;
3108 } else {
Daniel Veillard80b19092003-03-28 13:29:53 +00003109 invert = -1;
Daniel Veillard070803b2002-05-03 07:29:38 +00003110 xmon = -mon;
3111 xday = day;
3112 }
3113
3114 myear = xmon / 12;
Daniel Veillard80b19092003-03-28 13:29:53 +00003115 if (myear == 0) {
3116 minday = 0;
3117 maxday = 0;
3118 } else {
3119 maxday = 366 * ((myear + 3) / 4) +
3120 365 * ((myear - 1) % 4);
3121 minday = maxday - 1;
3122 }
3123
Daniel Veillard070803b2002-05-03 07:29:38 +00003124 xmon = xmon % 12;
3125 minday += dayRange[0][xmon];
3126 maxday += dayRange[1][xmon];
3127
Daniel Veillard80b19092003-03-28 13:29:53 +00003128 if ((maxday == minday) && (maxday == xday))
3129 return(0); /* can this really happen ? */
Daniel Veillard070803b2002-05-03 07:29:38 +00003130 if (maxday < xday)
Daniel Veillard80b19092003-03-28 13:29:53 +00003131 return(-invert);
3132 if (minday > xday)
3133 return(invert);
Daniel Veillard070803b2002-05-03 07:29:38 +00003134
3135 /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00003136 return 2;
3137}
3138
3139/*
3140 * macros for adding date/times and durations
3141 */
3142#define FQUOTIENT(a,b) (floor(((double)a/(double)b)))
3143#define MODULO(a,b) (a - FQUOTIENT(a,b) * b)
3144#define FQUOTIENT_RANGE(a,low,high) (FQUOTIENT((a-low),(high-low)))
3145#define MODULO_RANGE(a,low,high) ((MODULO((a-low),(high-low)))+low)
3146
3147/**
Daniel Veillard669adfc2004-05-29 20:12:46 +00003148 * xmlSchemaDupVal:
3149 * @v: the #xmlSchemaValPtr value to duplicate
3150 *
3151 * Makes a copy of @v. The calling program is responsible for freeing
3152 * the returned value.
3153 *
3154 * returns a pointer to a duplicated #xmlSchemaValPtr or NULL if error.
3155 */
3156static xmlSchemaValPtr
3157xmlSchemaDupVal (xmlSchemaValPtr v)
3158{
3159 xmlSchemaValPtr ret = xmlSchemaNewValue(v->type);
3160 if (ret == NULL)
3161 return NULL;
3162
3163 memcpy(ret, v, sizeof(xmlSchemaVal));
3164 return ret;
3165}
3166
3167/**
Kasimier T. Buchcik285ebab2005-03-04 18:04:59 +00003168 * xmlSchemaCopyValue:
3169 * @val: the precomputed value to be copied
3170 *
3171 * Copies the precomputed value. This duplicates any string within.
3172 *
3173 * Returns the copy or NULL if a copy for a data-type is not implemented.
3174 */
3175xmlSchemaValPtr
3176xmlSchemaCopyValue(xmlSchemaValPtr val)
3177{
3178 xmlSchemaValPtr ret;
3179
3180 if (val == NULL)
3181 return (NULL);
3182 /*
3183 * Copy the string values.
3184 */
3185 switch (val->type) {
3186 case XML_SCHEMAS_IDREFS:
3187 case XML_SCHEMAS_ENTITIES:
3188 case XML_SCHEMAS_NMTOKENS:
3189 case XML_SCHEMAS_ANYTYPE:
3190 case XML_SCHEMAS_ANYSIMPLETYPE:
3191 return (NULL);
3192 case XML_SCHEMAS_STRING:
3193 case XML_SCHEMAS_NORMSTRING:
3194 case XML_SCHEMAS_TOKEN:
3195 case XML_SCHEMAS_LANGUAGE:
3196 case XML_SCHEMAS_NAME:
3197 case XML_SCHEMAS_NCNAME:
3198 case XML_SCHEMAS_ID:
3199 case XML_SCHEMAS_IDREF:
3200 case XML_SCHEMAS_ENTITY:
3201 case XML_SCHEMAS_NMTOKEN:
Kasimier T. Buchcik2ee855d2005-03-07 11:14:14 +00003202 case XML_SCHEMAS_ANYURI:
Kasimier T. Buchcik285ebab2005-03-04 18:04:59 +00003203 ret = xmlSchemaDupVal(val);
3204 if (val->value.str != NULL)
3205 ret->value.str = xmlStrdup(BAD_CAST val->value.str);
3206 return (ret);
Kasimier T. Buchcik2ee855d2005-03-07 11:14:14 +00003207 case XML_SCHEMAS_QNAME:
Kasimier T. Buchcik285ebab2005-03-04 18:04:59 +00003208 case XML_SCHEMAS_NOTATION:
3209 ret = xmlSchemaDupVal(val);
3210 if (val->value.qname.name != NULL)
3211 ret->value.qname.name =
3212 xmlStrdup(BAD_CAST val->value.qname.name);
3213 if (val->value.qname.uri != NULL)
3214 ret->value.qname.uri =
3215 xmlStrdup(BAD_CAST val->value.qname.uri);
3216 return (ret);
3217 case XML_SCHEMAS_HEXBINARY:
3218 ret = xmlSchemaDupVal(val);
3219 if (val->value.hex.str != NULL)
3220 ret->value.hex.str = xmlStrdup(BAD_CAST val->value.hex.str);
3221 return (ret);
3222 case XML_SCHEMAS_BASE64BINARY:
3223 ret = xmlSchemaDupVal(val);
3224 if (val->value.base64.str != NULL)
3225 ret->value.base64.str =
3226 xmlStrdup(BAD_CAST val->value.base64.str);
3227 return (ret);
3228 default:
3229 return (xmlSchemaDupVal(val));
3230 }
3231 return (NULL);
3232}
3233
3234/**
Daniel Veillard5a872412002-05-22 06:40:27 +00003235 * _xmlSchemaDateAdd:
3236 * @dt: an #xmlSchemaValPtr
3237 * @dur: an #xmlSchemaValPtr of type #XS_DURATION
3238 *
3239 * Compute a new date/time from @dt and @dur. This function assumes @dt
3240 * is either #XML_SCHEMAS_DATETIME, #XML_SCHEMAS_DATE, #XML_SCHEMAS_GYEARMONTH,
Daniel Veillard669adfc2004-05-29 20:12:46 +00003241 * or #XML_SCHEMAS_GYEAR. The returned #xmlSchemaVal is the same type as
3242 * @dt. The calling program is responsible for freeing the returned value.
Daniel Veillard5a872412002-05-22 06:40:27 +00003243 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00003244 * Returns a pointer to a new #xmlSchemaVal or NULL if error.
Daniel Veillard5a872412002-05-22 06:40:27 +00003245 */
3246static xmlSchemaValPtr
3247_xmlSchemaDateAdd (xmlSchemaValPtr dt, xmlSchemaValPtr dur)
3248{
Daniel Veillard669adfc2004-05-29 20:12:46 +00003249 xmlSchemaValPtr ret, tmp;
Daniel Veillard5a872412002-05-22 06:40:27 +00003250 long carry, tempdays, temp;
3251 xmlSchemaValDatePtr r, d;
3252 xmlSchemaValDurationPtr u;
3253
3254 if ((dt == NULL) || (dur == NULL))
3255 return NULL;
3256
3257 ret = xmlSchemaNewValue(dt->type);
3258 if (ret == NULL)
3259 return NULL;
3260
Daniel Veillard669adfc2004-05-29 20:12:46 +00003261 /* make a copy so we don't alter the original value */
3262 tmp = xmlSchemaDupVal(dt);
3263 if (tmp == NULL) {
3264 xmlSchemaFreeValue(ret);
3265 return NULL;
3266 }
3267
Daniel Veillard5a872412002-05-22 06:40:27 +00003268 r = &(ret->value.date);
Daniel Veillard669adfc2004-05-29 20:12:46 +00003269 d = &(tmp->value.date);
Daniel Veillard5a872412002-05-22 06:40:27 +00003270 u = &(dur->value.dur);
3271
3272 /* normalization */
3273 if (d->mon == 0)
3274 d->mon = 1;
3275
3276 /* normalize for time zone offset */
3277 u->sec -= (d->tzo * 60);
3278 d->tzo = 0;
3279
3280 /* normalization */
3281 if (d->day == 0)
3282 d->day = 1;
3283
3284 /* month */
3285 carry = d->mon + u->mon;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003286 r->mon = (unsigned int) MODULO_RANGE(carry, 1, 13);
3287 carry = (long) FQUOTIENT_RANGE(carry, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00003288
3289 /* year (may be modified later) */
3290 r->year = d->year + carry;
3291 if (r->year == 0) {
3292 if (d->year > 0)
3293 r->year--;
3294 else
3295 r->year++;
3296 }
3297
3298 /* time zone */
3299 r->tzo = d->tzo;
3300 r->tz_flag = d->tz_flag;
3301
3302 /* seconds */
3303 r->sec = d->sec + u->sec;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003304 carry = (long) FQUOTIENT((long)r->sec, 60);
Daniel Veillard5a872412002-05-22 06:40:27 +00003305 if (r->sec != 0.0) {
3306 r->sec = MODULO(r->sec, 60.0);
3307 }
3308
3309 /* minute */
3310 carry += d->min;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003311 r->min = (unsigned int) MODULO(carry, 60);
3312 carry = (long) FQUOTIENT(carry, 60);
Daniel Veillard5a872412002-05-22 06:40:27 +00003313
3314 /* hours */
3315 carry += d->hour;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003316 r->hour = (unsigned int) MODULO(carry, 24);
3317 carry = (long)FQUOTIENT(carry, 24);
Daniel Veillard5a872412002-05-22 06:40:27 +00003318
3319 /*
3320 * days
3321 * Note we use tempdays because the temporary values may need more
3322 * than 5 bits
3323 */
3324 if ((VALID_YEAR(r->year)) && (VALID_MONTH(r->mon)) &&
3325 (d->day > MAX_DAYINMONTH(r->year, r->mon)))
3326 tempdays = MAX_DAYINMONTH(r->year, r->mon);
3327 else if (d->day < 1)
3328 tempdays = 1;
3329 else
3330 tempdays = d->day;
3331
3332 tempdays += u->day + carry;
3333
3334 while (1) {
3335 if (tempdays < 1) {
Daniel Veillardebe25d42004-03-25 09:35:49 +00003336 long tmon = (long) MODULO_RANGE(r->mon-1, 1, 13);
3337 long tyr = r->year + (long)FQUOTIENT_RANGE(r->mon-1, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00003338 if (tyr == 0)
3339 tyr--;
3340 tempdays += MAX_DAYINMONTH(tyr, tmon);
3341 carry = -1;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003342 } else if (tempdays > (long) MAX_DAYINMONTH(r->year, r->mon)) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003343 tempdays = tempdays - MAX_DAYINMONTH(r->year, r->mon);
3344 carry = 1;
3345 } else
3346 break;
3347
3348 temp = r->mon + carry;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003349 r->mon = (unsigned int) MODULO_RANGE(temp, 1, 13);
3350 r->year = r->year + (unsigned int) FQUOTIENT_RANGE(temp, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00003351 if (r->year == 0) {
3352 if (temp < 1)
3353 r->year--;
3354 else
3355 r->year++;
3356 }
3357 }
3358
3359 r->day = tempdays;
3360
3361 /*
3362 * adjust the date/time type to the date values
3363 */
3364 if (ret->type != XML_SCHEMAS_DATETIME) {
3365 if ((r->hour) || (r->min) || (r->sec))
3366 ret->type = XML_SCHEMAS_DATETIME;
3367 else if (ret->type != XML_SCHEMAS_DATE) {
3368 if ((r->mon != 1) && (r->day != 1))
3369 ret->type = XML_SCHEMAS_DATE;
3370 else if ((ret->type != XML_SCHEMAS_GYEARMONTH) && (r->mon != 1))
3371 ret->type = XML_SCHEMAS_GYEARMONTH;
3372 }
3373 }
3374
Daniel Veillard669adfc2004-05-29 20:12:46 +00003375 xmlSchemaFreeValue(tmp);
Daniel Veillard5a872412002-05-22 06:40:27 +00003376
Daniel Veillard5a872412002-05-22 06:40:27 +00003377 return ret;
3378}
3379
3380/**
3381 * xmlSchemaDateNormalize:
Daniel Veillard669adfc2004-05-29 20:12:46 +00003382 * @dt: an #xmlSchemaValPtr of a date/time type value.
3383 * @offset: number of seconds to adjust @dt by.
Daniel Veillard5a872412002-05-22 06:40:27 +00003384 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00003385 * Normalize @dt to GMT time. The @offset parameter is subtracted from
3386 * the return value is a time-zone offset is present on @dt.
Daniel Veillard5a872412002-05-22 06:40:27 +00003387 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00003388 * Returns a normalized copy of @dt or NULL if error.
Daniel Veillard5a872412002-05-22 06:40:27 +00003389 */
3390static xmlSchemaValPtr
3391xmlSchemaDateNormalize (xmlSchemaValPtr dt, double offset)
3392{
3393 xmlSchemaValPtr dur, ret;
3394
3395 if (dt == NULL)
3396 return NULL;
3397
3398 if (((dt->type != XML_SCHEMAS_TIME) &&
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00003399 (dt->type != XML_SCHEMAS_DATETIME) &&
3400 (dt->type != XML_SCHEMAS_DATE)) || (dt->value.date.tzo == 0))
Daniel Veillard5a872412002-05-22 06:40:27 +00003401 return xmlSchemaDupVal(dt);
3402
3403 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
3404 if (dur == NULL)
3405 return NULL;
3406
3407 dur->value.date.sec -= offset;
3408
3409 ret = _xmlSchemaDateAdd(dt, dur);
3410 if (ret == NULL)
3411 return NULL;
3412
3413 xmlSchemaFreeValue(dur);
3414
3415 /* ret->value.date.tzo = 0; */
3416 return ret;
3417}
3418
3419/**
3420 * _xmlSchemaDateCastYMToDays:
3421 * @dt: an #xmlSchemaValPtr
3422 *
3423 * Convert mon and year of @dt to total number of days. Take the
3424 * number of years since (or before) 1 AD and add the number of leap
3425 * years. This is a function because negative
3426 * years must be handled a little differently and there is no zero year.
3427 *
3428 * Returns number of days.
3429 */
3430static long
3431_xmlSchemaDateCastYMToDays (const xmlSchemaValPtr dt)
3432{
3433 long ret;
Daniel Veillard49e89632004-09-23 16:24:36 +00003434 int mon;
Daniel Veillard5a872412002-05-22 06:40:27 +00003435
Daniel Veillard49e89632004-09-23 16:24:36 +00003436 mon = dt->value.date.mon;
3437 if (mon <= 0) mon = 1; /* normalization */
3438
3439 if (dt->value.date.year <= 0)
Daniel Veillard5a872412002-05-22 06:40:27 +00003440 ret = (dt->value.date.year * 365) +
3441 (((dt->value.date.year+1)/4)-((dt->value.date.year+1)/100)+
3442 ((dt->value.date.year+1)/400)) +
Daniel Veillard49e89632004-09-23 16:24:36 +00003443 DAY_IN_YEAR(0, mon, dt->value.date.year);
Daniel Veillard5a872412002-05-22 06:40:27 +00003444 else
3445 ret = ((dt->value.date.year-1) * 365) +
3446 (((dt->value.date.year-1)/4)-((dt->value.date.year-1)/100)+
3447 ((dt->value.date.year-1)/400)) +
Daniel Veillard49e89632004-09-23 16:24:36 +00003448 DAY_IN_YEAR(0, mon, dt->value.date.year);
Daniel Veillard5a872412002-05-22 06:40:27 +00003449
3450 return ret;
3451}
3452
3453/**
3454 * TIME_TO_NUMBER:
3455 * @dt: an #xmlSchemaValPtr
3456 *
3457 * Calculates the number of seconds in the time portion of @dt.
3458 *
3459 * Returns seconds.
3460 */
3461#define TIME_TO_NUMBER(dt) \
3462 ((double)((dt->value.date.hour * SECS_PER_HOUR) + \
Daniel Veillardb3721c22003-03-31 11:22:25 +00003463 (dt->value.date.min * SECS_PER_MIN) + \
3464 (dt->value.date.tzo * SECS_PER_MIN)) + \
3465 dt->value.date.sec)
Daniel Veillard5a872412002-05-22 06:40:27 +00003466
3467/**
3468 * xmlSchemaCompareDates:
3469 * @x: a first date/time value
3470 * @y: a second date/time value
3471 *
3472 * Compare 2 date/times
3473 *
3474 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3475 * case of error
3476 */
3477static int
3478xmlSchemaCompareDates (xmlSchemaValPtr x, xmlSchemaValPtr y)
3479{
3480 unsigned char xmask, ymask, xor_mask, and_mask;
3481 xmlSchemaValPtr p1, p2, q1, q2;
3482 long p1d, p2d, q1d, q2d;
3483
3484 if ((x == NULL) || (y == NULL))
3485 return -2;
3486
3487 if (x->value.date.tz_flag) {
3488
3489 if (!y->value.date.tz_flag) {
3490 p1 = xmlSchemaDateNormalize(x, 0);
3491 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3492 /* normalize y + 14:00 */
3493 q1 = xmlSchemaDateNormalize(y, (14 * SECS_PER_HOUR));
3494
3495 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003496 if (p1d < q1d) {
3497 xmlSchemaFreeValue(p1);
3498 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003499 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003500 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003501 double sec;
3502
3503 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00003504 if (sec < 0.0) {
3505 xmlSchemaFreeValue(p1);
3506 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003507 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003508 } else {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003509 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003510 /* normalize y - 14:00 */
3511 q2 = xmlSchemaDateNormalize(y, -(14 * SECS_PER_HOUR));
3512 q2d = _xmlSchemaDateCastYMToDays(q2) + q2->value.date.day;
3513 if (p1d > q2d)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003514 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003515 else if (p1d == q2d) {
3516 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q2);
3517 if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003518 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003519 else
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003520 ret = 2; /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00003521 }
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003522 xmlSchemaFreeValue(p1);
3523 xmlSchemaFreeValue(q1);
3524 xmlSchemaFreeValue(q2);
3525 if (ret != 0)
3526 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003527 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00003528 } else {
3529 xmlSchemaFreeValue(p1);
3530 xmlSchemaFreeValue(q1);
3531 }
Daniel Veillard5a872412002-05-22 06:40:27 +00003532 }
3533 } else if (y->value.date.tz_flag) {
3534 q1 = xmlSchemaDateNormalize(y, 0);
3535 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
3536
3537 /* normalize x - 14:00 */
3538 p1 = xmlSchemaDateNormalize(x, -(14 * SECS_PER_HOUR));
3539 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3540
Daniel Veillardfdc91562002-07-01 21:52:03 +00003541 if (p1d < q1d) {
3542 xmlSchemaFreeValue(p1);
3543 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003544 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003545 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003546 double sec;
3547
3548 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00003549 if (sec < 0.0) {
3550 xmlSchemaFreeValue(p1);
3551 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003552 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003553 } else {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003554 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003555 /* normalize x + 14:00 */
3556 p2 = xmlSchemaDateNormalize(x, (14 * SECS_PER_HOUR));
3557 p2d = _xmlSchemaDateCastYMToDays(p2) + p2->value.date.day;
3558
Daniel Veillard6560a422003-03-27 21:25:38 +00003559 if (p2d > q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003560 ret = 1;
Daniel Veillard6560a422003-03-27 21:25:38 +00003561 } else if (p2d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003562 sec = TIME_TO_NUMBER(p2) - TIME_TO_NUMBER(q1);
3563 if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003564 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003565 else
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003566 ret = 2; /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00003567 }
Daniel Veillard6560a422003-03-27 21:25:38 +00003568 xmlSchemaFreeValue(p1);
3569 xmlSchemaFreeValue(q1);
3570 xmlSchemaFreeValue(p2);
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003571 if (ret != 0)
3572 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003573 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00003574 } else {
3575 xmlSchemaFreeValue(p1);
3576 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003577 }
3578 }
3579
3580 /*
3581 * if the same type then calculate the difference
3582 */
3583 if (x->type == y->type) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003584 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003585 q1 = xmlSchemaDateNormalize(y, 0);
3586 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
3587
3588 p1 = xmlSchemaDateNormalize(x, 0);
3589 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3590
Daniel Veillardfdc91562002-07-01 21:52:03 +00003591 if (p1d < q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003592 ret = -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003593 } else if (p1d > q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003594 ret = 1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003595 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00003596 double sec;
3597
3598 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
3599 if (sec < 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003600 ret = -1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003601 else if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003602 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003603
3604 }
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003605 xmlSchemaFreeValue(p1);
3606 xmlSchemaFreeValue(q1);
3607 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003608 }
3609
3610 switch (x->type) {
3611 case XML_SCHEMAS_DATETIME:
3612 xmask = 0xf;
3613 break;
3614 case XML_SCHEMAS_DATE:
3615 xmask = 0x7;
3616 break;
3617 case XML_SCHEMAS_GYEAR:
3618 xmask = 0x1;
3619 break;
3620 case XML_SCHEMAS_GMONTH:
3621 xmask = 0x2;
3622 break;
3623 case XML_SCHEMAS_GDAY:
3624 xmask = 0x3;
3625 break;
3626 case XML_SCHEMAS_GYEARMONTH:
3627 xmask = 0x3;
3628 break;
3629 case XML_SCHEMAS_GMONTHDAY:
3630 xmask = 0x6;
3631 break;
3632 case XML_SCHEMAS_TIME:
3633 xmask = 0x8;
3634 break;
3635 default:
3636 xmask = 0;
3637 break;
3638 }
3639
3640 switch (y->type) {
3641 case XML_SCHEMAS_DATETIME:
3642 ymask = 0xf;
3643 break;
3644 case XML_SCHEMAS_DATE:
3645 ymask = 0x7;
3646 break;
3647 case XML_SCHEMAS_GYEAR:
3648 ymask = 0x1;
3649 break;
3650 case XML_SCHEMAS_GMONTH:
3651 ymask = 0x2;
3652 break;
3653 case XML_SCHEMAS_GDAY:
3654 ymask = 0x3;
3655 break;
3656 case XML_SCHEMAS_GYEARMONTH:
3657 ymask = 0x3;
3658 break;
3659 case XML_SCHEMAS_GMONTHDAY:
3660 ymask = 0x6;
3661 break;
3662 case XML_SCHEMAS_TIME:
3663 ymask = 0x8;
3664 break;
3665 default:
3666 ymask = 0;
3667 break;
3668 }
3669
3670 xor_mask = xmask ^ ymask; /* mark type differences */
3671 and_mask = xmask & ymask; /* mark field specification */
3672
3673 /* year */
3674 if (xor_mask & 1)
3675 return 2; /* indeterminate */
3676 else if (and_mask & 1) {
3677 if (x->value.date.year < y->value.date.year)
3678 return -1;
3679 else if (x->value.date.year > y->value.date.year)
3680 return 1;
3681 }
3682
3683 /* month */
3684 if (xor_mask & 2)
3685 return 2; /* indeterminate */
3686 else if (and_mask & 2) {
3687 if (x->value.date.mon < y->value.date.mon)
3688 return -1;
3689 else if (x->value.date.mon > y->value.date.mon)
3690 return 1;
3691 }
3692
3693 /* day */
3694 if (xor_mask & 4)
3695 return 2; /* indeterminate */
3696 else if (and_mask & 4) {
3697 if (x->value.date.day < y->value.date.day)
3698 return -1;
3699 else if (x->value.date.day > y->value.date.day)
3700 return 1;
3701 }
3702
3703 /* time */
3704 if (xor_mask & 8)
3705 return 2; /* indeterminate */
3706 else if (and_mask & 8) {
3707 if (x->value.date.hour < y->value.date.hour)
3708 return -1;
3709 else if (x->value.date.hour > y->value.date.hour)
3710 return 1;
3711 else if (x->value.date.min < y->value.date.min)
3712 return -1;
3713 else if (x->value.date.min > y->value.date.min)
3714 return 1;
3715 else if (x->value.date.sec < y->value.date.sec)
3716 return -1;
3717 else if (x->value.date.sec > y->value.date.sec)
3718 return 1;
3719 }
3720
Daniel Veillard070803b2002-05-03 07:29:38 +00003721 return 0;
3722}
3723
3724/**
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003725 * xmlSchemaComparePreserveReplaceStrings:
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003726 * @x: a first string value
3727 * @y: a second string value
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003728 * @invert: inverts the result if x < y or x > y.
3729 *
3730 * Compare 2 string for their normalized values.
3731 * @x is a string with whitespace of "preserve", @y is
3732 * a string with a whitespace of "replace". I.e. @x could
3733 * be an "xsd:string" and @y an "xsd:normalizedString".
3734 *
3735 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
3736 * case of error
3737 */
3738static int
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003739xmlSchemaComparePreserveReplaceStrings(const xmlChar *x,
3740 const xmlChar *y,
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003741 int invert)
3742{
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003743 int tmp;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003744
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003745 while ((*x != 0) && (*y != 0)) {
3746 if (IS_WSP_REPLACE_CH(*y)) {
3747 if (! IS_WSP_SPACE_CH(*x)) {
3748 if ((*x - 0x20) < 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003749 if (invert)
3750 return(1);
3751 else
3752 return(-1);
3753 } else {
3754 if (invert)
3755 return(-1);
3756 else
3757 return(1);
3758 }
3759 }
3760 } else {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003761 tmp = *x - *y;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003762 if (tmp < 0) {
3763 if (invert)
3764 return(1);
3765 else
3766 return(-1);
3767 }
3768 if (tmp > 0) {
3769 if (invert)
3770 return(-1);
3771 else
3772 return(1);
3773 }
3774 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003775 x++;
3776 y++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003777 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003778 if (*x != 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003779 if (invert)
3780 return(-1);
3781 else
3782 return(1);
3783 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003784 if (*y != 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003785 if (invert)
3786 return(1);
3787 else
3788 return(-1);
3789 }
3790 return(0);
3791}
3792
3793/**
3794 * xmlSchemaComparePreserveCollapseStrings:
3795 * @x: a first string value
3796 * @y: a second string value
3797 *
3798 * Compare 2 string for their normalized values.
3799 * @x is a string with whitespace of "preserve", @y is
3800 * a string with a whitespace of "collapse". I.e. @x could
3801 * be an "xsd:string" and @y an "xsd:normalizedString".
3802 *
3803 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
3804 * case of error
3805 */
3806static int
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003807xmlSchemaComparePreserveCollapseStrings(const xmlChar *x,
3808 const xmlChar *y,
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003809 int invert)
3810{
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003811 int tmp;
3812
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003813 /*
3814 * Skip leading blank chars of the collapsed string.
3815 */
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003816 while IS_WSP_BLANK_CH(*y)
3817 y++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003818
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003819 while ((*x != 0) && (*y != 0)) {
3820 if IS_WSP_BLANK_CH(*y) {
3821 if (! IS_WSP_SPACE_CH(*x)) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003822 /*
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003823 * The yv character would have been replaced to 0x20.
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003824 */
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003825 if ((*x - 0x20) < 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003826 if (invert)
3827 return(1);
3828 else
3829 return(-1);
3830 } else {
3831 if (invert)
3832 return(-1);
3833 else
3834 return(1);
3835 }
3836 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003837 x++;
3838 y++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003839 /*
3840 * Skip contiguous blank chars of the collapsed string.
3841 */
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003842 while IS_WSP_BLANK_CH(*y)
3843 y++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003844 } else {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003845 tmp = *x++ - *y++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003846 if (tmp < 0) {
3847 if (invert)
3848 return(1);
3849 else
3850 return(-1);
3851 }
3852 if (tmp > 0) {
3853 if (invert)
3854 return(-1);
3855 else
3856 return(1);
3857 }
3858 }
3859 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003860 if (*x != 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003861 if (invert)
3862 return(-1);
3863 else
3864 return(1);
3865 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003866 if (*y != 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003867 /*
3868 * Skip trailing blank chars of the collapsed string.
3869 */
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003870 while IS_WSP_BLANK_CH(*y)
3871 y++;
3872 if (*y != 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003873 if (invert)
3874 return(1);
3875 else
3876 return(-1);
3877 }
3878 }
3879 return(0);
3880}
3881
3882/**
3883 * xmlSchemaComparePreserveCollapseStrings:
3884 * @x: a first string value
3885 * @y: a second string value
3886 *
3887 * Compare 2 string for their normalized values.
3888 * @x is a string with whitespace of "preserve", @y is
3889 * a string with a whitespace of "collapse". I.e. @x could
3890 * be an "xsd:string" and @y an "xsd:normalizedString".
3891 *
3892 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
3893 * case of error
3894 */
3895static int
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003896xmlSchemaCompareReplaceCollapseStrings(const xmlChar *x,
3897 const xmlChar *y,
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003898 int invert)
3899{
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003900 int tmp;
3901
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003902 /*
3903 * Skip leading blank chars of the collapsed string.
3904 */
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003905 while IS_WSP_BLANK_CH(*y)
3906 y++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003907
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003908 while ((*x != 0) && (*y != 0)) {
3909 if IS_WSP_BLANK_CH(*y) {
3910 if (! IS_WSP_BLANK_CH(*x)) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003911 /*
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003912 * The yv character would have been replaced to 0x20.
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003913 */
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003914 if ((*x - 0x20) < 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003915 if (invert)
3916 return(1);
3917 else
3918 return(-1);
3919 } else {
3920 if (invert)
3921 return(-1);
3922 else
3923 return(1);
3924 }
3925 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003926 x++;
3927 y++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003928 /*
3929 * Skip contiguous blank chars of the collapsed string.
3930 */
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003931 while IS_WSP_BLANK_CH(*y)
3932 y++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003933 } else {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003934 if IS_WSP_BLANK_CH(*x) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003935 /*
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003936 * The xv character would have been replaced to 0x20.
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003937 */
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003938 if ((0x20 - *y) < 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003939 if (invert)
3940 return(1);
3941 else
3942 return(-1);
3943 } else {
3944 if (invert)
3945 return(-1);
3946 else
3947 return(1);
3948 }
3949 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003950 tmp = *x++ - *y++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003951 if (tmp < 0)
3952 return(-1);
3953 if (tmp > 0)
3954 return(1);
3955 }
3956 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003957 if (*x != 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003958 if (invert)
3959 return(-1);
3960 else
3961 return(1);
3962 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003963 if (*y != 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003964 /*
3965 * Skip trailing blank chars of the collapsed string.
3966 */
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003967 while IS_WSP_BLANK_CH(*y)
3968 y++;
3969 if (*y != 0) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003970 if (invert)
3971 return(1);
3972 else
3973 return(-1);
3974 }
3975 }
3976 return(0);
3977}
3978
3979
3980/**
3981 * xmlSchemaCompareReplacedStrings:
3982 * @x: a first string value
3983 * @y: a second string value
3984 *
3985 * Compare 2 string for their normalized values.
3986 *
3987 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
3988 * case of error
3989 */
3990static int
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003991xmlSchemaCompareReplacedStrings(const xmlChar *x,
3992 const xmlChar *y)
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003993{
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00003994 int tmp;
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00003995
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00003996 while ((*x != 0) && (*y != 0)) {
3997 if IS_WSP_BLANK_CH(*y) {
3998 if (! IS_WSP_BLANK_CH(*x)) {
3999 if ((*x - 0x20) < 0)
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004000 return(-1);
4001 else
4002 return(1);
4003 }
4004 } else {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004005 if IS_WSP_BLANK_CH(*x) {
4006 if ((0x20 - *y) < 0)
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004007 return(-1);
4008 else
4009 return(1);
4010 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004011 tmp = *x - *y;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004012 if (tmp < 0)
4013 return(-1);
4014 if (tmp > 0)
4015 return(1);
4016 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004017 x++;
4018 y++;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004019 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004020 if (*x != 0)
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004021 return(1);
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004022 if (*y != 0)
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004023 return(-1);
4024 return(0);
4025}
4026
4027/**
Daniel Veillardc4c21552003-03-29 10:53:38 +00004028 * xmlSchemaCompareNormStrings:
4029 * @x: a first string value
4030 * @y: a second string value
4031 *
4032 * Compare 2 string for their normalized values.
4033 *
4034 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
4035 * case of error
4036 */
4037static int
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004038xmlSchemaCompareNormStrings(const xmlChar *x,
4039 const xmlChar *y) {
Daniel Veillardc4c21552003-03-29 10:53:38 +00004040 int tmp;
Daniel Veillardc4c21552003-03-29 10:53:38 +00004041
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004042 while (IS_BLANK_CH(*x)) x++;
4043 while (IS_BLANK_CH(*y)) y++;
4044 while ((*x != 0) && (*y != 0)) {
4045 if (IS_BLANK_CH(*x)) {
4046 if (!IS_BLANK_CH(*y)) {
4047 tmp = *x - *y;
Daniel Veillardc4c21552003-03-29 10:53:38 +00004048 return(tmp);
4049 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004050 while (IS_BLANK_CH(*x)) x++;
4051 while (IS_BLANK_CH(*y)) y++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00004052 } else {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004053 tmp = *x++ - *y++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00004054 if (tmp < 0)
4055 return(-1);
4056 if (tmp > 0)
4057 return(1);
4058 }
4059 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004060 if (*x != 0) {
4061 while (IS_BLANK_CH(*x)) x++;
4062 if (*x != 0)
Daniel Veillardc4c21552003-03-29 10:53:38 +00004063 return(1);
4064 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004065 if (*y != 0) {
4066 while (IS_BLANK_CH(*y)) y++;
4067 if (*y != 0)
Daniel Veillardc4c21552003-03-29 10:53:38 +00004068 return(-1);
4069 }
4070 return(0);
4071}
4072
4073/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00004074 * xmlSchemaCompareFloats:
4075 * @x: a first float or double value
4076 * @y: a second float or double value
4077 *
4078 * Compare 2 values
4079 *
4080 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
4081 * case of error
4082 */
4083static int
4084xmlSchemaCompareFloats(xmlSchemaValPtr x, xmlSchemaValPtr y) {
4085 double d1, d2;
4086
4087 if ((x == NULL) || (y == NULL))
4088 return(-2);
4089
4090 /*
4091 * Cast everything to doubles.
4092 */
4093 if (x->type == XML_SCHEMAS_DOUBLE)
4094 d1 = x->value.d;
4095 else if (x->type == XML_SCHEMAS_FLOAT)
4096 d1 = x->value.f;
4097 else
4098 return(-2);
4099
4100 if (y->type == XML_SCHEMAS_DOUBLE)
4101 d2 = y->value.d;
4102 else if (y->type == XML_SCHEMAS_FLOAT)
4103 d2 = y->value.f;
4104 else
4105 return(-2);
4106
4107 /*
4108 * Check for special cases.
4109 */
4110 if (xmlXPathIsNaN(d1)) {
4111 if (xmlXPathIsNaN(d2))
4112 return(0);
4113 return(1);
4114 }
4115 if (xmlXPathIsNaN(d2))
4116 return(-1);
4117 if (d1 == xmlXPathPINF) {
4118 if (d2 == xmlXPathPINF)
4119 return(0);
4120 return(1);
4121 }
4122 if (d2 == xmlXPathPINF)
4123 return(-1);
4124 if (d1 == xmlXPathNINF) {
4125 if (d2 == xmlXPathNINF)
4126 return(0);
4127 return(-1);
4128 }
4129 if (d2 == xmlXPathNINF)
4130 return(1);
4131
4132 /*
4133 * basic tests, the last one we should have equality, but
4134 * portability is more important than speed and handling
4135 * NaN or Inf in a portable way is always a challenge, so ...
4136 */
4137 if (d1 < d2)
4138 return(-1);
4139 if (d1 > d2)
4140 return(1);
4141 if (d1 == d2)
4142 return(0);
4143 return(2);
4144}
4145
4146/**
Daniel Veillard4255d502002-04-16 15:50:10 +00004147 * xmlSchemaCompareValues:
4148 * @x: a first value
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004149 * @xvalue: the first value as a string (optional)
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004150 * @xwtsp: the whitespace type
Daniel Veillard4255d502002-04-16 15:50:10 +00004151 * @y: a second value
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004152 * @xvalue: the second value as a string (optional)
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004153 * @ywtsp: the whitespace type
Daniel Veillard4255d502002-04-16 15:50:10 +00004154 *
4155 * Compare 2 values
4156 *
Daniel Veillard5a872412002-05-22 06:40:27 +00004157 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
4158 * case of error
Daniel Veillard4255d502002-04-16 15:50:10 +00004159 */
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004160static int
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004161xmlSchemaCompareValuesInternal(xmlSchemaValType xtype,
4162 xmlSchemaValPtr x,
4163 const xmlChar *xvalue,
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004164 xmlSchemaWhitespaceValueType xws,
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004165 xmlSchemaValType ytype,
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004166 xmlSchemaValPtr y,
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004167 const xmlChar *yvalue,
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004168 xmlSchemaWhitespaceValueType yws)
4169{
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004170 switch (xtype) {
Daniel Veillard80b19092003-03-28 13:29:53 +00004171 case XML_SCHEMAS_UNKNOWN:
William M. Brack2f2a6632004-08-20 23:09:47 +00004172 case XML_SCHEMAS_ANYTYPE:
Daniel Veillard80b19092003-03-28 13:29:53 +00004173 return(-2);
4174 case XML_SCHEMAS_INTEGER:
4175 case XML_SCHEMAS_NPINTEGER:
4176 case XML_SCHEMAS_NINTEGER:
4177 case XML_SCHEMAS_NNINTEGER:
4178 case XML_SCHEMAS_PINTEGER:
4179 case XML_SCHEMAS_INT:
4180 case XML_SCHEMAS_UINT:
4181 case XML_SCHEMAS_LONG:
4182 case XML_SCHEMAS_ULONG:
4183 case XML_SCHEMAS_SHORT:
4184 case XML_SCHEMAS_USHORT:
4185 case XML_SCHEMAS_BYTE:
4186 case XML_SCHEMAS_UBYTE:
Daniel Veillard4255d502002-04-16 15:50:10 +00004187 case XML_SCHEMAS_DECIMAL:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004188 if ((x == NULL) || (y == NULL))
4189 return(-2);
4190 if (ytype == xtype)
Daniel Veillard80b19092003-03-28 13:29:53 +00004191 return(xmlSchemaCompareDecimals(x, y));
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004192 if ((ytype == XML_SCHEMAS_DECIMAL) ||
4193 (ytype == XML_SCHEMAS_INTEGER) ||
4194 (ytype == XML_SCHEMAS_NPINTEGER) ||
4195 (ytype == XML_SCHEMAS_NINTEGER) ||
4196 (ytype == XML_SCHEMAS_NNINTEGER) ||
4197 (ytype == XML_SCHEMAS_PINTEGER) ||
4198 (ytype == XML_SCHEMAS_INT) ||
4199 (ytype == XML_SCHEMAS_UINT) ||
4200 (ytype == XML_SCHEMAS_LONG) ||
4201 (ytype == XML_SCHEMAS_ULONG) ||
4202 (ytype == XML_SCHEMAS_SHORT) ||
4203 (ytype == XML_SCHEMAS_USHORT) ||
4204 (ytype == XML_SCHEMAS_BYTE) ||
4205 (ytype == XML_SCHEMAS_UBYTE))
Daniel Veillard4255d502002-04-16 15:50:10 +00004206 return(xmlSchemaCompareDecimals(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00004207 return(-2);
Daniel Veillard070803b2002-05-03 07:29:38 +00004208 case XML_SCHEMAS_DURATION:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004209 if ((x == NULL) || (y == NULL))
4210 return(-2);
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004211 if (ytype == XML_SCHEMAS_DURATION)
Daniel Veillard070803b2002-05-03 07:29:38 +00004212 return(xmlSchemaCompareDurations(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00004213 return(-2);
4214 case XML_SCHEMAS_TIME:
4215 case XML_SCHEMAS_GDAY:
4216 case XML_SCHEMAS_GMONTH:
4217 case XML_SCHEMAS_GMONTHDAY:
4218 case XML_SCHEMAS_GYEAR:
4219 case XML_SCHEMAS_GYEARMONTH:
4220 case XML_SCHEMAS_DATE:
4221 case XML_SCHEMAS_DATETIME:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004222 if ((x == NULL) || (y == NULL))
4223 return(-2);
4224 if ((ytype == XML_SCHEMAS_DATETIME) ||
4225 (ytype == XML_SCHEMAS_TIME) ||
4226 (ytype == XML_SCHEMAS_GDAY) ||
4227 (ytype == XML_SCHEMAS_GMONTH) ||
4228 (ytype == XML_SCHEMAS_GMONTHDAY) ||
4229 (ytype == XML_SCHEMAS_GYEAR) ||
4230 (ytype == XML_SCHEMAS_DATE) ||
4231 (ytype == XML_SCHEMAS_GYEARMONTH))
Daniel Veillard5a872412002-05-22 06:40:27 +00004232 return (xmlSchemaCompareDates(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00004233 return (-2);
Kasimier T. Buchcik2ee855d2005-03-07 11:14:14 +00004234 /*
4235 * Note that we will support comparison of string types against
4236 * anySimpleType as well.
4237 */
4238 case XML_SCHEMAS_ANYSIMPLETYPE:
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004239 case XML_SCHEMAS_STRING:
4240 case XML_SCHEMAS_NORMSTRING:
Daniel Veillard80b19092003-03-28 13:29:53 +00004241 case XML_SCHEMAS_TOKEN:
4242 case XML_SCHEMAS_LANGUAGE:
4243 case XML_SCHEMAS_NMTOKEN:
Daniel Veillard80b19092003-03-28 13:29:53 +00004244 case XML_SCHEMAS_NAME:
Daniel Veillard80b19092003-03-28 13:29:53 +00004245 case XML_SCHEMAS_NCNAME:
4246 case XML_SCHEMAS_ID:
4247 case XML_SCHEMAS_IDREF:
Daniel Veillard80b19092003-03-28 13:29:53 +00004248 case XML_SCHEMAS_ENTITY:
Daniel Veillard80b19092003-03-28 13:29:53 +00004249 case XML_SCHEMAS_ANYURI:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004250 {
4251 const xmlChar *xv, *yv;
4252
4253 if (x == NULL)
4254 xv = xvalue;
4255 else
4256 xv = x->value.str;
4257 if (y == NULL)
4258 yv = yvalue;
4259 else
4260 yv = y->value.str;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004261 /*
4262 * TODO: Compare those against QName.
4263 */
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004264 if (ytype == XML_SCHEMAS_QNAME) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004265 TODO
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004266 if (y == NULL)
4267 return(-2);
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004268 return (-2);
4269 }
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004270 if ((ytype == XML_SCHEMAS_ANYSIMPLETYPE) ||
4271 (ytype == XML_SCHEMAS_STRING) ||
4272 (ytype == XML_SCHEMAS_NORMSTRING) ||
4273 (ytype == XML_SCHEMAS_TOKEN) ||
4274 (ytype == XML_SCHEMAS_LANGUAGE) ||
4275 (ytype == XML_SCHEMAS_NMTOKEN) ||
4276 (ytype == XML_SCHEMAS_NAME) ||
4277 (ytype == XML_SCHEMAS_NCNAME) ||
4278 (ytype == XML_SCHEMAS_ID) ||
4279 (ytype == XML_SCHEMAS_IDREF) ||
4280 (ytype == XML_SCHEMAS_ENTITY) ||
4281 (ytype == XML_SCHEMAS_NOTATION) ||
4282 (ytype == XML_SCHEMAS_ANYURI)) {
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004283
4284 if (xws == XML_SCHEMA_WHITESPACE_PRESERVE) {
4285
4286 if (yws == XML_SCHEMA_WHITESPACE_PRESERVE) {
4287 /* TODO: What about x < y or x > y. */
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004288 if (xmlStrEqual(xv, yv))
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004289 return (0);
4290 else
4291 return (2);
4292 } else if (yws == XML_SCHEMA_WHITESPACE_REPLACE)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004293 return (xmlSchemaComparePreserveReplaceStrings(xv, yv, 0));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004294 else if (yws == XML_SCHEMA_WHITESPACE_COLLAPSE)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004295 return (xmlSchemaComparePreserveCollapseStrings(xv, yv, 0));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004296
4297 } else if (xws == XML_SCHEMA_WHITESPACE_REPLACE) {
4298
4299 if (yws == XML_SCHEMA_WHITESPACE_PRESERVE)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004300 return (xmlSchemaComparePreserveReplaceStrings(yv, xv, 1));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004301 if (yws == XML_SCHEMA_WHITESPACE_REPLACE)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004302 return (xmlSchemaCompareReplacedStrings(xv, yv));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004303 if (yws == XML_SCHEMA_WHITESPACE_COLLAPSE)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004304 return (xmlSchemaCompareReplaceCollapseStrings(xv, yv, 0));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004305
4306 } else if (xws == XML_SCHEMA_WHITESPACE_COLLAPSE) {
4307
4308 if (yws == XML_SCHEMA_WHITESPACE_PRESERVE)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004309 return (xmlSchemaComparePreserveCollapseStrings(yv, xv, 1));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004310 if (yws == XML_SCHEMA_WHITESPACE_REPLACE)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004311 return (xmlSchemaCompareReplaceCollapseStrings(yv, xv, 1));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004312 if (yws == XML_SCHEMA_WHITESPACE_COLLAPSE)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004313 return (xmlSchemaCompareNormStrings(xv, yv));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004314 } else
4315 return (-2);
4316
4317 }
Daniel Veillardc4c21552003-03-29 10:53:38 +00004318 return (-2);
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004319 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004320 case XML_SCHEMAS_QNAME:
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00004321 case XML_SCHEMAS_NOTATION:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004322 if ((x == NULL) || (y == NULL))
4323 return(-2);
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00004324 if ((ytype == XML_SCHEMAS_QNAME) ||
4325 (ytype == XML_SCHEMAS_NOTATION)) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004326 if ((xmlStrEqual(x->value.qname.name, y->value.qname.name)) &&
4327 (xmlStrEqual(x->value.qname.uri, y->value.qname.uri)))
4328 return(0);
4329 return(2);
4330 }
4331 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00004332 case XML_SCHEMAS_FLOAT:
4333 case XML_SCHEMAS_DOUBLE:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004334 if ((x == NULL) || (y == NULL))
4335 return(-2);
4336 if ((ytype == XML_SCHEMAS_FLOAT) ||
4337 (ytype == XML_SCHEMAS_DOUBLE))
Daniel Veillardb6c7f412003-03-29 16:41:55 +00004338 return (xmlSchemaCompareFloats(x, y));
4339 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00004340 case XML_SCHEMAS_BOOLEAN:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004341 if ((x == NULL) || (y == NULL))
4342 return(-2);
4343 if (ytype == XML_SCHEMAS_BOOLEAN) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00004344 if (x->value.b == y->value.b)
4345 return(0);
4346 if (x->value.b == 0)
4347 return(-1);
4348 return(1);
4349 }
4350 return (-2);
Daniel Veillard560c2a42003-07-06 21:13:49 +00004351 case XML_SCHEMAS_HEXBINARY:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004352 if ((x == NULL) || (y == NULL))
4353 return(-2);
4354 if (ytype == XML_SCHEMAS_HEXBINARY) {
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004355 if (x->value.hex.total == y->value.hex.total) {
4356 int ret = xmlStrcmp(x->value.hex.str, y->value.hex.str);
4357 if (ret > 0)
4358 return(1);
4359 else if (ret == 0)
4360 return(0);
4361 }
4362 else if (x->value.hex.total > y->value.hex.total)
4363 return(1);
4364
4365 return(-1);
4366 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00004367 return (-2);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00004368 case XML_SCHEMAS_BASE64BINARY:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004369 if ((x == NULL) || (y == NULL))
4370 return(-2);
4371 if (ytype == XML_SCHEMAS_BASE64BINARY) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00004372 if (x->value.base64.total == y->value.base64.total) {
4373 int ret = xmlStrcmp(x->value.base64.str,
4374 y->value.base64.str);
4375 if (ret > 0)
4376 return(1);
4377 else if (ret == 0)
4378 return(0);
4379 }
4380 else if (x->value.base64.total > y->value.base64.total)
4381 return(1);
4382 else
4383 return(-1);
4384 }
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004385 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00004386 case XML_SCHEMAS_IDREFS:
4387 case XML_SCHEMAS_ENTITIES:
4388 case XML_SCHEMAS_NMTOKENS:
4389 TODO
4390 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00004391 }
Daniel Veillard5a872412002-05-22 06:40:27 +00004392 return -2;
Daniel Veillard4255d502002-04-16 15:50:10 +00004393}
4394
4395/**
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004396 * xmlSchemaCompareValues:
4397 * @x: a first value
4398 * @y: a second value
4399 *
4400 * Compare 2 values
4401 *
4402 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
4403 * case of error
4404 */
4405int
4406xmlSchemaCompareValues(xmlSchemaValPtr x, xmlSchemaValPtr y) {
4407 xmlSchemaWhitespaceValueType xws, yws;
4408
Daniel Veillard5e094142005-02-18 19:36:12 +00004409 if ((x == NULL) || (y == NULL))
4410 return(-2);
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004411 if (x->type == XML_SCHEMAS_STRING)
4412 xws = XML_SCHEMA_WHITESPACE_PRESERVE;
4413 else if (x->type == XML_SCHEMAS_NORMSTRING)
4414 xws = XML_SCHEMA_WHITESPACE_REPLACE;
4415 else
4416 xws = XML_SCHEMA_WHITESPACE_COLLAPSE;
4417
4418 if (y->type == XML_SCHEMAS_STRING)
4419 yws = XML_SCHEMA_WHITESPACE_PRESERVE;
4420 else if (x->type == XML_SCHEMAS_NORMSTRING)
4421 yws = XML_SCHEMA_WHITESPACE_REPLACE;
4422 else
4423 yws = XML_SCHEMA_WHITESPACE_COLLAPSE;
4424
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004425 return(xmlSchemaCompareValuesInternal(x->type, x, NULL, xws, y->type,
4426 y, NULL, yws));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004427}
4428
4429/**
4430 * xmlSchemaCompareValuesWhtsp:
4431 * @x: a first value
4432 * @xws: the whitespace value of x
4433 * @y: a second value
4434 * @yws: the whitespace value of y
4435 *
4436 * Compare 2 values
4437 *
4438 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
4439 * case of error
4440 */
4441int
4442xmlSchemaCompareValuesWhtsp(xmlSchemaValPtr x,
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004443 xmlSchemaWhitespaceValueType xws,
4444 xmlSchemaValPtr y,
4445 xmlSchemaWhitespaceValueType yws)
4446{
Kasimier T. Buchcik9dbb0ce2005-03-16 16:39:23 +00004447 if ((x == NULL) || (y == NULL))
4448 return(-2);
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004449 return(xmlSchemaCompareValuesInternal(x->type, x, NULL, xws, y->type,
4450 y, NULL, yws));
4451}
4452
4453/**
4454 * xmlSchemaCompareValuesWhtspExt:
4455 * @x: a first value
4456 * @xws: the whitespace value of x
4457 * @y: a second value
4458 * @yws: the whitespace value of y
4459 *
4460 * Compare 2 values
4461 *
4462 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
4463 * case of error
4464 */
4465static int
4466xmlSchemaCompareValuesWhtspExt(xmlSchemaValType xtype,
4467 xmlSchemaValPtr x,
4468 const xmlChar *xvalue,
4469 xmlSchemaWhitespaceValueType xws,
4470 xmlSchemaValType ytype,
4471 xmlSchemaValPtr y,
4472 const xmlChar *yvalue,
4473 xmlSchemaWhitespaceValueType yws)
4474{
4475 return(xmlSchemaCompareValuesInternal(xtype, x, xvalue, xws, ytype, y,
4476 yvalue, yws));
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004477}
4478
4479/**
Daniel Veillardc4c21552003-03-29 10:53:38 +00004480 * xmlSchemaNormLen:
4481 * @value: a string
4482 *
4483 * Computes the UTF8 length of the normalized value of the string
4484 *
4485 * Returns the length or -1 in case of error.
4486 */
4487static int
4488xmlSchemaNormLen(const xmlChar *value) {
4489 const xmlChar *utf;
4490 int ret = 0;
4491
4492 if (value == NULL)
4493 return(-1);
4494 utf = value;
William M. Brack76e95df2003-10-18 16:20:14 +00004495 while (IS_BLANK_CH(*utf)) utf++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00004496 while (*utf != 0) {
4497 if (utf[0] & 0x80) {
4498 if ((utf[1] & 0xc0) != 0x80)
4499 return(-1);
4500 if ((utf[0] & 0xe0) == 0xe0) {
4501 if ((utf[2] & 0xc0) != 0x80)
4502 return(-1);
4503 if ((utf[0] & 0xf0) == 0xf0) {
4504 if ((utf[0] & 0xf8) != 0xf0 || (utf[3] & 0xc0) != 0x80)
4505 return(-1);
4506 utf += 4;
4507 } else {
4508 utf += 3;
4509 }
4510 } else {
4511 utf += 2;
4512 }
William M. Brack76e95df2003-10-18 16:20:14 +00004513 } else if (IS_BLANK_CH(*utf)) {
4514 while (IS_BLANK_CH(*utf)) utf++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00004515 if (*utf == 0)
4516 break;
4517 } else {
4518 utf++;
4519 }
4520 ret++;
4521 }
4522 return(ret);
4523}
4524
Daniel Veillard6927b102004-10-27 17:29:04 +00004525/**
4526 * xmlSchemaGetFacetValueAsULong:
4527 * @facet: an schemas type facet
4528 *
4529 * Extract the value of a facet
4530 *
4531 * Returns the value as a long
4532 */
Daniel Veillardc0826a72004-08-10 14:17:33 +00004533unsigned long
4534xmlSchemaGetFacetValueAsULong(xmlSchemaFacetPtr facet)
4535{
4536 /*
4537 * TODO: Check if this is a decimal.
4538 */
William M. Brack094dd862004-11-14 14:28:34 +00004539 if (facet == NULL)
4540 return 0;
Daniel Veillardc0826a72004-08-10 14:17:33 +00004541 return ((unsigned long) facet->val->value.decimal.lo);
4542}
4543
Daniel Veillardc4c21552003-03-29 10:53:38 +00004544/**
Daniel Veillard01fa6152004-06-29 17:04:39 +00004545 * xmlSchemaValidateListSimpleTypeFacet:
4546 * @facet: the facet to check
4547 * @value: the lexical repr of the value to validate
4548 * @actualLen: the number of list items
4549 * @expectedLen: the resulting expected number of list items
4550 *
4551 * Checks the value of a list simple type against a facet.
4552 *
4553 * Returns 0 if the value is valid, a positive error code
4554 * number otherwise and -1 in case of an internal error.
4555 */
4556int
4557xmlSchemaValidateListSimpleTypeFacet(xmlSchemaFacetPtr facet,
4558 const xmlChar *value,
4559 unsigned long actualLen,
4560 unsigned long *expectedLen)
4561{
Daniel Veillardce682bc2004-11-05 17:22:25 +00004562 if (facet == NULL)
4563 return(-1);
Daniel Veillard01fa6152004-06-29 17:04:39 +00004564 /*
4565 * TODO: Check if this will work with large numbers.
4566 * (compare value.decimal.mi and value.decimal.hi as well?).
4567 */
4568 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
4569 if (actualLen != facet->val->value.decimal.lo) {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004570 if (expectedLen != NULL)
Daniel Veillardc0826a72004-08-10 14:17:33 +00004571 *expectedLen = facet->val->value.decimal.lo;
Daniel Veillard01fa6152004-06-29 17:04:39 +00004572 return (XML_SCHEMAV_CVC_LENGTH_VALID);
4573 }
4574 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
4575 if (actualLen < facet->val->value.decimal.lo) {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004576 if (expectedLen != NULL)
Daniel Veillardc0826a72004-08-10 14:17:33 +00004577 *expectedLen = facet->val->value.decimal.lo;
Daniel Veillard01fa6152004-06-29 17:04:39 +00004578 return (XML_SCHEMAV_CVC_MINLENGTH_VALID);
4579 }
4580 } else if (facet->type == XML_SCHEMA_FACET_MAXLENGTH) {
4581 if (actualLen > facet->val->value.decimal.lo) {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004582 if (expectedLen != NULL)
Daniel Veillardc0826a72004-08-10 14:17:33 +00004583 *expectedLen = facet->val->value.decimal.lo;
Daniel Veillard01fa6152004-06-29 17:04:39 +00004584 return (XML_SCHEMAV_CVC_MAXLENGTH_VALID);
4585 }
4586 } else
4587 /*
4588 * NOTE: That we can pass NULL as xmlSchemaValPtr to
4589 * xmlSchemaValidateFacet, since the remaining facet types
4590 * are: XML_SCHEMA_FACET_PATTERN, XML_SCHEMA_FACET_ENUMERATION.
4591 */
4592 return(xmlSchemaValidateFacet(NULL, facet, value, NULL));
4593 return (0);
4594}
4595
4596/**
Daniel Veillard6927b102004-10-27 17:29:04 +00004597 * xmlSchemaValidateLengthFacet:
Daniel Veillardc0826a72004-08-10 14:17:33 +00004598 * @type: the built-in type
4599 * @facet: the facet to check
4600 * @value: the lexical repr. of the value to be validated
4601 * @val: the precomputed value
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004602 * @ws: the whitespace type of the value
4603 * @length: the actual length of the value
4604 *
4605 * Checka a value against a "length", "minLength" and "maxLength"
4606 * facet; sets @length to the computed length of @value.
4607 *
4608 * Returns 0 if the value is valid, a positive error code
4609 * otherwise and -1 in case of an internal or API error.
4610 */
4611static int
4612xmlSchemaValidateLengthFacetInternal(xmlSchemaFacetPtr facet,
4613 xmlSchemaTypeType valType,
4614 const xmlChar *value,
4615 xmlSchemaValPtr val,
4616 unsigned long *length,
4617 xmlSchemaWhitespaceValueType ws)
4618{
4619 unsigned int len = 0;
4620
4621 if ((length == NULL) || (facet == NULL))
4622 return (-1);
4623 *length = 0;
4624 if ((facet->type != XML_SCHEMA_FACET_LENGTH) &&
4625 (facet->type != XML_SCHEMA_FACET_MAXLENGTH) &&
4626 (facet->type != XML_SCHEMA_FACET_MINLENGTH))
4627 return (-1);
4628
4629 /*
4630 * TODO: length, maxLength and minLength must be of type
4631 * nonNegativeInteger only. Check if decimal is used somehow.
4632 */
4633 if ((facet->val == NULL) ||
4634 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
4635 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
4636 (facet->val->value.decimal.frac != 0)) {
4637 return(-1);
4638 }
4639 if ((val != NULL) && (val->type == XML_SCHEMAS_HEXBINARY))
4640 len = val->value.hex.total;
4641 else if ((val != NULL) && (val->type == XML_SCHEMAS_BASE64BINARY))
4642 len = val->value.base64.total;
4643 else {
4644 switch (valType) {
4645 case XML_SCHEMAS_STRING:
4646 case XML_SCHEMAS_NORMSTRING:
4647 if (ws == XML_SCHEMA_WHITESPACE_UNKNOWN) {
4648 /*
4649 * This is to ensure API compatibility with the old
4650 * xmlSchemaValidateLengthFacet(). Anyway, this was and
4651 * is not the correct handling.
4652 * TODO: Get rid of this case somehow.
4653 */
4654 if (valType == XML_SCHEMAS_STRING)
4655 len = xmlUTF8Strlen(value);
4656 else
4657 len = xmlSchemaNormLen(value);
4658 } else if (value != NULL) {
4659 if (ws == XML_SCHEMA_WHITESPACE_COLLAPSE)
4660 len = xmlSchemaNormLen(value);
4661 else
4662 /*
4663 * Should be OK for "preserve" as well.
4664 */
4665 len = xmlUTF8Strlen(value);
4666 }
4667 break;
4668 case XML_SCHEMAS_IDREF:
4669 case XML_SCHEMAS_TOKEN:
4670 case XML_SCHEMAS_LANGUAGE:
4671 case XML_SCHEMAS_NMTOKEN:
4672 case XML_SCHEMAS_NAME:
4673 case XML_SCHEMAS_NCNAME:
4674 case XML_SCHEMAS_ID:
4675 /*
4676 * FIXME: What exactly to do with anyURI?
4677 */
4678 case XML_SCHEMAS_ANYURI:
4679 if (value != NULL)
4680 len = xmlSchemaNormLen(value);
4681 break;
4682 default:
4683 TODO
4684 }
4685 }
4686 *length = (unsigned long) len;
4687 /*
4688 * TODO: Return the whole expected value, i.e. "lo", "mi" and "hi".
4689 */
4690 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
4691 if (len != facet->val->value.decimal.lo)
4692 return(XML_SCHEMAV_CVC_LENGTH_VALID);
4693 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
4694 if (len < facet->val->value.decimal.lo)
4695 return(XML_SCHEMAV_CVC_MINLENGTH_VALID);
4696 } else {
4697 if (len > facet->val->value.decimal.lo)
4698 return(XML_SCHEMAV_CVC_MAXLENGTH_VALID);
4699 }
4700
4701 return (0);
4702}
4703
4704/**
4705 * xmlSchemaValidateLengthFacet:
4706 * @type: the built-in type
4707 * @facet: the facet to check
4708 * @value: the lexical repr. of the value to be validated
4709 * @val: the precomputed value
Daniel Veillardc0826a72004-08-10 14:17:33 +00004710 * @length: the actual length of the value
4711 *
4712 * Checka a value against a "length", "minLength" and "maxLength"
4713 * facet; sets @length to the computed length of @value.
4714 *
4715 * Returns 0 if the value is valid, a positive error code
4716 * otherwise and -1 in case of an internal or API error.
4717 */
4718int
4719xmlSchemaValidateLengthFacet(xmlSchemaTypePtr type,
4720 xmlSchemaFacetPtr facet,
4721 const xmlChar *value,
4722 xmlSchemaValPtr val,
4723 unsigned long *length)
4724{
Daniel Veillardcc5e2332005-03-16 21:55:35 +00004725 if (type == NULL)
4726 return(-1);
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004727 return (xmlSchemaValidateLengthFacetInternal(facet,
4728 type->builtInType, value, val, length,
4729 XML_SCHEMA_WHITESPACE_UNKNOWN));
4730}
Daniel Veillardc0826a72004-08-10 14:17:33 +00004731
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004732/**
4733 * xmlSchemaValidateLengthFacetWhtsp:
4734 * @facet: the facet to check
4735 * @valType: the built-in type
4736 * @value: the lexical repr. of the value to be validated
4737 * @val: the precomputed value
4738 * @ws: the whitespace type of the value
4739 * @length: the actual length of the value
4740 *
4741 * Checka a value against a "length", "minLength" and "maxLength"
4742 * facet; sets @length to the computed length of @value.
4743 *
4744 * Returns 0 if the value is valid, a positive error code
4745 * otherwise and -1 in case of an internal or API error.
4746 */
4747int
4748xmlSchemaValidateLengthFacetWhtsp(xmlSchemaFacetPtr facet,
4749 xmlSchemaValType valType,
4750 const xmlChar *value,
4751 xmlSchemaValPtr val,
4752 unsigned long *length,
4753 xmlSchemaWhitespaceValueType ws)
4754{
4755 return (xmlSchemaValidateLengthFacetInternal(facet, valType, value, val,
4756 length, ws));
Daniel Veillardc0826a72004-08-10 14:17:33 +00004757}
4758
4759/**
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004760 * xmlSchemaValidateFacetInternal:
Daniel Veillard4255d502002-04-16 15:50:10 +00004761 * @facet: the facet to check
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004762 * @fws: the whitespace type of the facet's value
4763 * @valType: the built-in type of the value
Daniel Veillard4255d502002-04-16 15:50:10 +00004764 * @value: the lexical repr of the value to validate
4765 * @val: the precomputed value
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004766 * @ws: the whitespace type of the value
Daniel Veillard4255d502002-04-16 15:50:10 +00004767 *
4768 * Check a value against a facet condition
4769 *
4770 * Returns 0 if the element is schemas valid, a positive error code
4771 * number otherwise and -1 in case of internal or API error.
4772 */
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004773static int
4774xmlSchemaValidateFacetInternal(xmlSchemaFacetPtr facet,
4775 xmlSchemaWhitespaceValueType fws,
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004776 xmlSchemaValType valType,
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004777 const xmlChar *value,
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004778 xmlSchemaValPtr val,
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004779 xmlSchemaWhitespaceValueType ws)
Daniel Veillard4255d502002-04-16 15:50:10 +00004780{
4781 int ret;
4782
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004783 if (facet == NULL)
4784 return(-1);
4785
Daniel Veillard4255d502002-04-16 15:50:10 +00004786 switch (facet->type) {
4787 case XML_SCHEMA_FACET_PATTERN:
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004788 /*
4789 * NOTE that for patterns, the @value needs to be the normalized
4790 * value, *not* the lexical initial value or the canonical value.
4791 */
4792 if (value == NULL)
4793 return(-1);
Daniel Veillard4255d502002-04-16 15:50:10 +00004794 ret = xmlRegexpExec(facet->regexp, value);
4795 if (ret == 1)
4796 return(0);
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004797 if (ret == 0)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004798 return(XML_SCHEMAV_CVC_PATTERN_VALID);
Daniel Veillard4255d502002-04-16 15:50:10 +00004799 return(ret);
4800 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
4801 ret = xmlSchemaCompareValues(val, facet->val);
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004802 if (ret == -2)
Daniel Veillard4255d502002-04-16 15:50:10 +00004803 return(-1);
Daniel Veillard4255d502002-04-16 15:50:10 +00004804 if (ret == -1)
4805 return(0);
Daniel Veillard01fa6152004-06-29 17:04:39 +00004806 return(XML_SCHEMAV_CVC_MAXEXCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00004807 case XML_SCHEMA_FACET_MAXINCLUSIVE:
4808 ret = xmlSchemaCompareValues(val, facet->val);
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004809 if (ret == -2)
Daniel Veillard070803b2002-05-03 07:29:38 +00004810 return(-1);
Daniel Veillard070803b2002-05-03 07:29:38 +00004811 if ((ret == -1) || (ret == 0))
4812 return(0);
Daniel Veillard01fa6152004-06-29 17:04:39 +00004813 return(XML_SCHEMAV_CVC_MAXINCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00004814 case XML_SCHEMA_FACET_MINEXCLUSIVE:
4815 ret = xmlSchemaCompareValues(val, facet->val);
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004816 if (ret == -2)
Daniel Veillard070803b2002-05-03 07:29:38 +00004817 return(-1);
Daniel Veillard070803b2002-05-03 07:29:38 +00004818 if (ret == 1)
4819 return(0);
Daniel Veillard01fa6152004-06-29 17:04:39 +00004820 return(XML_SCHEMAV_CVC_MINEXCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00004821 case XML_SCHEMA_FACET_MININCLUSIVE:
4822 ret = xmlSchemaCompareValues(val, facet->val);
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004823 if (ret == -2)
Daniel Veillard070803b2002-05-03 07:29:38 +00004824 return(-1);
Daniel Veillard070803b2002-05-03 07:29:38 +00004825 if ((ret == 1) || (ret == 0))
4826 return(0);
Daniel Veillard01fa6152004-06-29 17:04:39 +00004827 return(XML_SCHEMAV_CVC_MININCLUSIVE_VALID);
Daniel Veillard8651f532002-04-17 09:06:27 +00004828 case XML_SCHEMA_FACET_WHITESPACE:
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004829 /* TODO whitespaces */
Daniel Veillard01fa6152004-06-29 17:04:39 +00004830 /*
4831 * NOTE: Whitespace should be handled to normalize
4832 * the value to be validated against a the facets;
4833 * not to normalize the value in-between.
4834 */
Daniel Veillard8651f532002-04-17 09:06:27 +00004835 return(0);
Daniel Veillard88c58912002-04-23 07:12:20 +00004836 case XML_SCHEMA_FACET_ENUMERATION:
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004837 if (ws == XML_SCHEMA_WHITESPACE_UNKNOWN) {
4838 /*
4839 * This is to ensure API compatibility with the old
4840 * xmlSchemaValidateFacet().
4841 * TODO: Get rid of this case.
4842 */
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004843 if ((facet->value != NULL) &&
4844 (xmlStrEqual(facet->value, value)))
4845 return(0);
4846 } else {
4847 ret = xmlSchemaCompareValuesWhtspExt(facet->val->type,
4848 facet->val, facet->value, fws, valType, val,
4849 value, ws);
4850 if (ret == -2)
4851 return(-1);
4852 if (ret == 0)
4853 return(0);
4854 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00004855 return(XML_SCHEMAV_CVC_ENUMERATION_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004856 case XML_SCHEMA_FACET_LENGTH:
Kasimier T. Buchcikaba15f72005-04-01 15:17:27 +00004857 /*
4858 * SPEC (1.3) "if {primitive type definition} is QName or NOTATION,
4859 * then any {value} is facet-valid."
4860 */
4861 if ((valType == XML_SCHEMAS_QNAME) ||
4862 (valType == XML_SCHEMAS_NOTATION))
4863 return (0);
4864 /* No break on purpose. */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004865 case XML_SCHEMA_FACET_MAXLENGTH:
4866 case XML_SCHEMA_FACET_MINLENGTH: {
4867 unsigned int len = 0;
4868
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004869 /*
4870 * TODO: length, maxLength and minLength must be of type
4871 * nonNegativeInteger only. Check if decimal is used somehow.
4872 */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004873 if ((facet->val == NULL) ||
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004874 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
4875 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004876 (facet->val->value.decimal.frac != 0)) {
4877 return(-1);
4878 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00004879 if ((val != NULL) && (val->type == XML_SCHEMAS_HEXBINARY))
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004880 len = val->value.hex.total;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00004881 else if ((val != NULL) && (val->type == XML_SCHEMAS_BASE64BINARY))
4882 len = val->value.base64.total;
4883 else {
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004884 switch (valType) {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004885 case XML_SCHEMAS_STRING:
4886 case XML_SCHEMAS_NORMSTRING:
4887 if (ws == XML_SCHEMA_WHITESPACE_UNKNOWN) {
4888 /*
4889 * This is to ensure API compatibility with the old
4890 * xmlSchemaValidateFacet(). Anyway, this was and
4891 * is not the correct handling.
4892 * TODO: Get rid of this case somehow.
4893 */
4894 if (valType == XML_SCHEMAS_STRING)
4895 len = xmlUTF8Strlen(value);
4896 else
4897 len = xmlSchemaNormLen(value);
4898 } else if (value != NULL) {
4899 if (ws == XML_SCHEMA_WHITESPACE_COLLAPSE)
4900 len = xmlSchemaNormLen(value);
4901 else
4902 /*
4903 * Should be OK for "preserve" as well.
4904 */
4905 len = xmlUTF8Strlen(value);
4906 }
4907 break;
4908 case XML_SCHEMAS_IDREF:
Daniel Veillard560c2a42003-07-06 21:13:49 +00004909 case XML_SCHEMAS_TOKEN:
4910 case XML_SCHEMAS_LANGUAGE:
4911 case XML_SCHEMAS_NMTOKEN:
4912 case XML_SCHEMAS_NAME:
4913 case XML_SCHEMAS_NCNAME:
4914 case XML_SCHEMAS_ID:
Daniel Veillard01fa6152004-06-29 17:04:39 +00004915 case XML_SCHEMAS_ANYURI:
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00004916 if (value != NULL)
4917 len = xmlSchemaNormLen(value);
4918 break;
Daniel Veillard560c2a42003-07-06 21:13:49 +00004919 default:
4920 TODO
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004921 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004922 }
4923 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004924 if (len != facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004925 return(XML_SCHEMAV_CVC_LENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004926 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004927 if (len < facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004928 return(XML_SCHEMAV_CVC_MINLENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004929 } else {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004930 if (len > facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004931 return(XML_SCHEMAV_CVC_MAXLENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004932 }
4933 break;
4934 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00004935 case XML_SCHEMA_FACET_TOTALDIGITS:
4936 case XML_SCHEMA_FACET_FRACTIONDIGITS:
4937
4938 if ((facet->val == NULL) ||
4939 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
4940 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
4941 (facet->val->value.decimal.frac != 0)) {
4942 return(-1);
4943 }
4944 if ((val == NULL) ||
4945 ((val->type != XML_SCHEMAS_DECIMAL) &&
4946 (val->type != XML_SCHEMAS_INTEGER) &&
4947 (val->type != XML_SCHEMAS_NPINTEGER) &&
4948 (val->type != XML_SCHEMAS_NINTEGER) &&
4949 (val->type != XML_SCHEMAS_NNINTEGER) &&
4950 (val->type != XML_SCHEMAS_PINTEGER) &&
4951 (val->type != XML_SCHEMAS_INT) &&
4952 (val->type != XML_SCHEMAS_UINT) &&
4953 (val->type != XML_SCHEMAS_LONG) &&
4954 (val->type != XML_SCHEMAS_ULONG) &&
4955 (val->type != XML_SCHEMAS_SHORT) &&
4956 (val->type != XML_SCHEMAS_USHORT) &&
4957 (val->type != XML_SCHEMAS_BYTE) &&
4958 (val->type != XML_SCHEMAS_UBYTE))) {
4959 return(-1);
4960 }
4961 if (facet->type == XML_SCHEMA_FACET_TOTALDIGITS) {
4962 if (val->value.decimal.total > facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004963 return(XML_SCHEMAV_CVC_TOTALDIGITS_VALID);
Daniel Veillard560c2a42003-07-06 21:13:49 +00004964
4965 } else if (facet->type == XML_SCHEMA_FACET_FRACTIONDIGITS) {
4966 if (val->value.decimal.frac > facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004967 return(XML_SCHEMAV_CVC_FRACTIONDIGITS_VALID);
Daniel Veillard560c2a42003-07-06 21:13:49 +00004968 }
4969 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00004970 default:
4971 TODO
4972 }
4973 return(0);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00004974
Daniel Veillard4255d502002-04-16 15:50:10 +00004975}
4976
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00004977/**
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004978 * xmlSchemaValidateFacet:
4979 * @base: the base type
4980 * @facet: the facet to check
4981 * @value: the lexical repr of the value to validate
4982 * @val: the precomputed value
4983 *
4984 * Check a value against a facet condition
4985 *
4986 * Returns 0 if the element is schemas valid, a positive error code
4987 * number otherwise and -1 in case of internal or API error.
4988 */
4989int
Kasimier T. Buchcik9dbb0ce2005-03-16 16:39:23 +00004990xmlSchemaValidateFacet(xmlSchemaTypePtr base,
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00004991 xmlSchemaFacetPtr facet,
4992 const xmlChar *value,
4993 xmlSchemaValPtr val)
4994{
4995 /*
4996 * This tries to ensure API compatibility regarding the old
4997 * xmlSchemaValidateFacet() and the new xmlSchemaValidateFacetInternal() and
4998 * xmlSchemaValidateFacetWhtsp().
4999 */
Kasimier T. Buchcik9dbb0ce2005-03-16 16:39:23 +00005000 if (val != NULL)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005001 return(xmlSchemaValidateFacetInternal(facet,
Kasimier T. Buchcik9dbb0ce2005-03-16 16:39:23 +00005002 XML_SCHEMA_WHITESPACE_UNKNOWN, val->type, value, val,
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005003 XML_SCHEMA_WHITESPACE_UNKNOWN));
Kasimier T. Buchcik9dbb0ce2005-03-16 16:39:23 +00005004 else if (base != NULL)
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005005 return(xmlSchemaValidateFacetInternal(facet,
Kasimier T. Buchcik9dbb0ce2005-03-16 16:39:23 +00005006 XML_SCHEMA_WHITESPACE_UNKNOWN, base->builtInType, value, val,
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005007 XML_SCHEMA_WHITESPACE_UNKNOWN));
Kasimier T. Buchcik9dbb0ce2005-03-16 16:39:23 +00005008 return(-1);
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005009}
5010
5011/**
5012 * xmlSchemaValidateFacetWhtsp:
5013 * @facet: the facet to check
5014 * @fws: the whitespace type of the facet's value
5015 * @valType: the built-in type of the value
5016 * @value: the lexical (or normalized for pattern) repr of the value to validate
5017 * @val: the precomputed value
5018 * @ws: the whitespace type of the value
5019 *
5020 * Check a value against a facet condition. This takes value normalization
5021 * according to the specified whitespace types into account.
5022 * Note that @value needs to be the *normalized* value if the facet
5023 * is of type "pattern".
5024 *
5025 * Returns 0 if the element is schemas valid, a positive error code
5026 * number otherwise and -1 in case of internal or API error.
5027 */
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005028int
5029xmlSchemaValidateFacetWhtsp(xmlSchemaFacetPtr facet,
5030 xmlSchemaWhitespaceValueType fws,
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005031 xmlSchemaValType valType,
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005032 const xmlChar *value,
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005033 xmlSchemaValPtr val,
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005034 xmlSchemaWhitespaceValueType ws)
5035{
5036 return(xmlSchemaValidateFacetInternal(facet, fws, valType,
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005037 value, val, ws));
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005038}
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005039
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00005040#if 0
5041#ifndef DBL_DIG
5042#define DBL_DIG 16
5043#endif
5044#ifndef DBL_EPSILON
5045#define DBL_EPSILON 1E-9
5046#endif
5047
5048#define INTEGER_DIGITS DBL_DIG
5049#define FRACTION_DIGITS (DBL_DIG + 1)
5050#define EXPONENT_DIGITS (3 + 2)
5051
5052/**
5053 * xmlXPathFormatNumber:
5054 * @number: number to format
5055 * @buffer: output buffer
5056 * @buffersize: size of output buffer
5057 *
5058 * Convert the number into a string representation.
5059 */
5060static void
5061xmlSchemaFormatFloat(double number, char buffer[], int buffersize)
5062{
5063 switch (xmlXPathIsInf(number)) {
5064 case 1:
5065 if (buffersize > (int)sizeof("INF"))
5066 snprintf(buffer, buffersize, "INF");
5067 break;
5068 case -1:
5069 if (buffersize > (int)sizeof("-INF"))
5070 snprintf(buffer, buffersize, "-INF");
5071 break;
5072 default:
5073 if (xmlXPathIsNaN(number)) {
5074 if (buffersize > (int)sizeof("NaN"))
5075 snprintf(buffer, buffersize, "NaN");
5076 } else if (number == 0) {
5077 snprintf(buffer, buffersize, "0.0E0");
5078 } else {
5079 /* 3 is sign, decimal point, and terminating zero */
5080 char work[DBL_DIG + EXPONENT_DIGITS + 3];
5081 int integer_place, fraction_place;
5082 char *ptr;
5083 char *after_fraction;
5084 double absolute_value;
5085 int size;
5086
5087 absolute_value = fabs(number);
5088
5089 /*
5090 * Result is in work, and after_fraction points
5091 * just past the fractional part.
5092 * Use scientific notation
5093 */
5094 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
5095 fraction_place = DBL_DIG - 1;
5096 snprintf(work, sizeof(work),"%*.*e",
5097 integer_place, fraction_place, number);
5098 after_fraction = strchr(work + DBL_DIG, 'e');
5099 /* Remove fractional trailing zeroes */
5100 ptr = after_fraction;
5101 while (*(--ptr) == '0')
5102 ;
5103 if (*ptr != '.')
5104 ptr++;
5105 while ((*ptr++ = *after_fraction++) != 0);
5106
5107 /* Finally copy result back to caller */
5108 size = strlen(work) + 1;
5109 if (size > buffersize) {
5110 work[buffersize - 1] = 0;
5111 size = buffersize;
5112 }
5113 memmove(buffer, work, size);
5114 }
5115 break;
5116 }
5117}
5118#endif
5119
Kasimier T. Buchcik6c81d0e2005-03-15 14:58:11 +00005120/**
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00005121 * xmlSchemaGetCanonValue:
5122 * @val: the precomputed value
5123 * @retValue: the returned value
5124 *
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005125 * Get a the cononical lexical representation of the value.
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00005126 * The caller has to FREE the returned retValue.
5127 *
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005128 * WARNING: Some value types are not supported yet, resulting
5129 * in a @retValue of "???".
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00005130 *
5131 * TODO: XML Schema 1.0 does not define canonical representations
5132 * for: duration, gYearMonth, gYear, gMonthDay, gMonth, gDay,
5133 * anyURI, QName, NOTATION. This will be fixed in XML Schema 1.1.
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00005134 *
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00005135 *
5136 * Returns 0 if the value could be built, 1 if the value type is
5137 * not supported yet and -1 in case of API errors.
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00005138 */
5139int
Daniel Veillardb5839c32005-02-19 18:27:14 +00005140xmlSchemaGetCanonValue(xmlSchemaValPtr val, const xmlChar **retValue)
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00005141{
Daniel Veillardb5839c32005-02-19 18:27:14 +00005142 if ((retValue == NULL) || (val == NULL))
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00005143 return (-1);
5144 *retValue = NULL;
5145 switch (val->type) {
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005146 case XML_SCHEMAS_STRING:
5147 if (val->value.str == NULL)
5148 *retValue = BAD_CAST xmlStrdup(BAD_CAST "");
5149 else
5150 *retValue =
5151 BAD_CAST xmlStrdup((const xmlChar *) val->value.str);
5152 break;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00005153 case XML_SCHEMAS_NORMSTRING:
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005154 if (val->value.str == NULL)
5155 *retValue = BAD_CAST xmlStrdup(BAD_CAST "");
5156 else {
5157 *retValue = xmlSchemaWhiteSpaceReplace(
5158 (const xmlChar *) val->value.str);
5159 if ((*retValue) == NULL)
5160 *retValue = BAD_CAST xmlStrdup(
5161 (const xmlChar *) val->value.str);
5162 }
5163 break;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00005164 case XML_SCHEMAS_TOKEN:
5165 case XML_SCHEMAS_LANGUAGE:
5166 case XML_SCHEMAS_NMTOKEN:
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005167 case XML_SCHEMAS_NAME:
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00005168 case XML_SCHEMAS_NCNAME:
5169 case XML_SCHEMAS_ID:
5170 case XML_SCHEMAS_IDREF:
5171 case XML_SCHEMAS_ENTITY:
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00005172 case XML_SCHEMAS_NOTATION: /* Unclear */
5173 case XML_SCHEMAS_ANYURI: /* Unclear */
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00005174 if (val->value.str == NULL)
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005175 return (-1);
Kasimier T. Buchcikaba15f72005-04-01 15:17:27 +00005176 *retValue =
5177 BAD_CAST xmlSchemaCollapseString(BAD_CAST val->value.str);
5178 if (*retValue == NULL)
5179 *retValue =
5180 BAD_CAST xmlStrdup((const xmlChar *) val->value.str);
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005181 break;
5182 case XML_SCHEMAS_QNAME:
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00005183 /* TODO: Unclear in XML Schema 1.0. */
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005184 if (val->value.qname.uri == NULL) {
5185 *retValue = BAD_CAST xmlStrdup(BAD_CAST val->value.qname.name);
5186 return (0);
5187 } else {
5188 *retValue = BAD_CAST xmlStrdup(BAD_CAST "{");
5189 *retValue = BAD_CAST xmlStrcat((xmlChar *) (*retValue),
5190 BAD_CAST val->value.qname.uri);
5191 *retValue = BAD_CAST xmlStrcat((xmlChar *) (*retValue),
5192 BAD_CAST "}");
5193 *retValue = BAD_CAST xmlStrcat((xmlChar *) (*retValue),
5194 BAD_CAST val->value.qname.uri);
5195 }
5196 break;
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00005197 case XML_SCHEMAS_DECIMAL:
5198 /*
5199 * TODO: Lookout for a more simple implementation.
5200 */
5201 if ((val->value.decimal.total == 1) &&
5202 (val->value.decimal.lo == 0)) {
5203 *retValue = xmlStrdup(BAD_CAST "0.0");
5204 } else {
5205 xmlSchemaValDecimal dec = val->value.decimal;
5206 int bufsize;
5207 char *buf = NULL, *offs;
5208
5209 /* Add room for the decimal point as well. */
5210 bufsize = dec.total + 2;
5211 if (dec.sign)
5212 bufsize++;
5213 /* Add room for leading/trailing zero. */
5214 if ((dec.frac == 0) || (dec.frac == dec.total))
5215 bufsize++;
5216 buf = xmlMalloc(bufsize);
5217 offs = buf;
5218 if (dec.sign)
5219 *offs++ = '-';
5220 if (dec.frac == dec.total) {
5221 *offs++ = '0';
5222 *offs++ = '.';
5223 }
5224 if (dec.hi != 0)
5225 snprintf(offs, bufsize - (offs - buf),
5226 "%lu%lu%lu", dec.hi, dec.mi, dec.lo);
5227 else if (dec.mi != 0)
5228 snprintf(offs, bufsize - (offs - buf),
5229 "%lu%lu", dec.mi, dec.lo);
5230 else
5231 snprintf(offs, bufsize - (offs - buf),
5232 "%lu", dec.lo);
5233
5234 if (dec.frac != 0) {
5235 if (dec.frac != dec.total) {
5236 int diff = dec.total - dec.frac;
5237 /*
5238 * Insert the decimal point.
5239 */
5240 memmove(offs + diff + 1, offs + diff, dec.frac +1);
5241 offs[diff] = '.';
5242 } else {
5243 unsigned int i = 0;
5244 /*
5245 * Insert missing zeroes behind the decimal point.
5246 */
5247 while (*(offs + i) != 0)
5248 i++;
5249 if (i < dec.total) {
5250 memmove(offs + (dec.total - i), offs, i +1);
5251 memset(offs, '0', dec.total - i);
5252 }
5253 }
5254 } else {
5255 /*
5256 * Append decimal point and zero.
5257 */
5258 offs = buf + bufsize - 1;
5259 *offs-- = 0;
5260 *offs-- = '0';
5261 *offs-- = '.';
5262 }
5263 *retValue = BAD_CAST buf;
5264 }
5265 break;
5266 case XML_SCHEMAS_INTEGER:
5267 case XML_SCHEMAS_PINTEGER:
5268 case XML_SCHEMAS_NPINTEGER:
5269 case XML_SCHEMAS_NINTEGER:
5270 case XML_SCHEMAS_NNINTEGER:
5271 case XML_SCHEMAS_LONG:
5272 case XML_SCHEMAS_BYTE:
5273 case XML_SCHEMAS_SHORT:
5274 case XML_SCHEMAS_INT:
5275 case XML_SCHEMAS_UINT:
5276 case XML_SCHEMAS_ULONG:
5277 case XML_SCHEMAS_USHORT:
5278 case XML_SCHEMAS_UBYTE:
5279 if ((val->value.decimal.total == 1) &&
5280 (val->value.decimal.lo == 0))
5281 *retValue = xmlStrdup(BAD_CAST "0");
5282 else {
5283 xmlSchemaValDecimal dec = val->value.decimal;
5284 int bufsize = dec.total + 1;
5285
5286 /* Add room for the decimal point as well. */
5287 if (dec.sign)
5288 bufsize++;
5289 *retValue = xmlMalloc(bufsize);
5290 if (dec.hi != 0) {
5291 if (dec.sign)
5292 snprintf((char *) *retValue, bufsize,
5293 "-%lu%lu%lu", dec.hi, dec.mi, dec.lo);
5294 else
5295 snprintf((char *) *retValue, bufsize,
5296 "%lu%lu%lu", dec.hi, dec.mi, dec.lo);
5297 } else if (dec.mi != 0) {
5298 if (dec.sign)
5299 snprintf((char *) *retValue, bufsize,
5300 "-%lu%lu", dec.mi, dec.lo);
5301 else
5302 snprintf((char *) *retValue, bufsize,
5303 "%lu%lu", dec.mi, dec.lo);
5304 } else {
5305 if (dec.sign)
5306 snprintf((char *) *retValue, bufsize, "-%lu", dec.lo);
5307 else
5308 snprintf((char *) *retValue, bufsize, "%lu", dec.lo);
5309 }
5310 }
5311 break;
5312 case XML_SCHEMAS_BOOLEAN:
5313 if (val->value.b)
5314 *retValue = BAD_CAST xmlStrdup(BAD_CAST "true");
5315 else
5316 *retValue = BAD_CAST xmlStrdup(BAD_CAST "false");
5317 break;
5318 case XML_SCHEMAS_DURATION: {
5319 char buf[100];
5320 unsigned long year;
5321 unsigned long mon, day, hour = 0, min = 0;
5322 double sec = 0, left;
5323
5324 /* TODO: Unclear in XML Schema 1.0 */
5325 /*
5326 * TODO: This results in a normalized output of the value
5327 * - which is NOT conformant to the spec -
5328 * since the exact values of each property are not
5329 * recoverable. Think about extending the structure to
5330 * provide a field for every property.
5331 */
5332 year = (unsigned long) FQUOTIENT(labs(val->value.dur.mon), 12);
5333 mon = labs(val->value.dur.mon) - 12 * year;
5334
5335 day = (unsigned long) FQUOTIENT(fabs(val->value.dur.sec), 86400);
5336 left = fabs(val->value.dur.sec) - day * 86400;
5337 if (left > 0) {
5338 hour = (unsigned long) FQUOTIENT(left, 3600);
5339 left = left - (hour * 3600);
5340 if (left > 0) {
5341 min = (unsigned long) FQUOTIENT(left, 60);
5342 sec = left - (min * 60);
5343 }
5344 }
5345 if ((val->value.dur.mon < 0) || (val->value.dur.sec < 0))
5346 snprintf(buf, 100, "P%luY%luM%luDT%luH%luM%.14gS",
5347 year, mon, day, hour, min, sec);
5348 else
5349 snprintf(buf, 100, "-P%luY%luM%luDT%luH%luM%.14gS",
5350 year, mon, day, hour, min, sec);
5351 *retValue = BAD_CAST xmlStrdup(BAD_CAST buf);
5352 }
5353 break;
5354 case XML_SCHEMAS_GYEAR: {
5355 char buf[30];
5356 /* TODO: Unclear in XML Schema 1.0 */
5357 /* TODO: What to do with the timezone? */
5358 snprintf(buf, 30, "%04ld", val->value.date.year);
5359 *retValue = BAD_CAST xmlStrdup(BAD_CAST buf);
5360 }
5361 break;
5362 case XML_SCHEMAS_GMONTH: {
5363 /* TODO: Unclear in XML Schema 1.0 */
5364 /* TODO: What to do with the timezone? */
5365 *retValue = xmlMalloc(5);
5366 snprintf((char *) *retValue, 6, "--%02u",
5367 val->value.date.mon);
5368 }
5369 break;
5370 case XML_SCHEMAS_GDAY: {
5371 /* TODO: Unclear in XML Schema 1.0 */
5372 /* TODO: What to do with the timezone? */
5373 *retValue = xmlMalloc(6);
5374 snprintf((char *) *retValue, 6, "---%02u",
5375 val->value.date.day);
5376 }
5377 break;
5378 case XML_SCHEMAS_GMONTHDAY: {
5379 /* TODO: Unclear in XML Schema 1.0 */
5380 /* TODO: What to do with the timezone? */
5381 *retValue = xmlMalloc(8);
5382 snprintf((char *) *retValue, 8, "--%02u-%02u",
5383 val->value.date.mon, val->value.date.day);
5384 }
5385 break;
5386 case XML_SCHEMAS_GYEARMONTH: {
5387 char buf[35];
5388 /* TODO: Unclear in XML Schema 1.0 */
5389 /* TODO: What to do with the timezone? */
5390 if (val->value.date.year < 0)
5391 snprintf(buf, 35, "-%04ld-%02u",
5392 labs(val->value.date.year),
5393 val->value.date.mon);
5394 else
5395 snprintf(buf, 35, "%04ld-%02u",
5396 val->value.date.year, val->value.date.mon);
5397 *retValue = BAD_CAST xmlStrdup(BAD_CAST buf);
5398 }
5399 break;
5400 case XML_SCHEMAS_TIME:
5401 {
5402 char buf[30];
5403
5404 if (val->value.date.tz_flag) {
5405 xmlSchemaValPtr norm;
5406
5407 norm = xmlSchemaDateNormalize(val, 0);
5408 if (norm == NULL)
5409 return (-1);
5410 /*
5411 * TODO: Check if "%.14g" is portable.
5412 */
5413 snprintf(buf, 30,
5414 "%02u:%02u:%02.14gZ",
5415 norm->value.date.hour,
5416 norm->value.date.min,
5417 norm->value.date.sec);
5418 xmlSchemaFreeValue(norm);
5419 } else {
5420 snprintf(buf, 30,
5421 "%02u:%02u:%02.14g",
5422 val->value.date.hour,
5423 val->value.date.min,
5424 val->value.date.sec);
5425 }
5426 *retValue = BAD_CAST xmlStrdup(BAD_CAST buf);
5427 }
5428 break;
5429 case XML_SCHEMAS_DATE:
5430 {
5431 char buf[30];
5432
5433 if (val->value.date.tz_flag) {
5434 xmlSchemaValPtr norm;
5435
5436 norm = xmlSchemaDateNormalize(val, 0);
5437 if (norm == NULL)
5438 return (-1);
5439 /*
5440 * TODO: Append the canonical value of the
5441 * recoverable timezone and not "Z".
5442 */
5443 snprintf(buf, 30,
5444 "%04ld:%02u:%02uZ",
5445 norm->value.date.year, norm->value.date.mon,
5446 norm->value.date.day);
5447 xmlSchemaFreeValue(norm);
5448 } else {
5449 snprintf(buf, 30,
5450 "%04ld:%02u:%02u",
5451 val->value.date.year, val->value.date.mon,
5452 val->value.date.day);
5453 }
5454 *retValue = BAD_CAST xmlStrdup(BAD_CAST buf);
5455 }
5456 break;
5457 case XML_SCHEMAS_DATETIME:
5458 {
5459 char buf[50];
5460
5461 if (val->value.date.tz_flag) {
5462 xmlSchemaValPtr norm;
5463
5464 norm = xmlSchemaDateNormalize(val, 0);
5465 if (norm == NULL)
5466 return (-1);
5467 /*
5468 * TODO: Check if "%.14g" is portable.
5469 */
5470 snprintf(buf, 50,
5471 "%04ld:%02u:%02uT%02u:%02u:%02.14gZ",
5472 norm->value.date.year, norm->value.date.mon,
5473 norm->value.date.day, norm->value.date.hour,
5474 norm->value.date.min, norm->value.date.sec);
5475 xmlSchemaFreeValue(norm);
5476 } else {
5477 snprintf(buf, 50,
5478 "%04ld:%02u:%02uT%02u:%02u:%02.14g",
5479 val->value.date.year, val->value.date.mon,
5480 val->value.date.day, val->value.date.hour,
5481 val->value.date.min, val->value.date.sec);
5482 }
5483 *retValue = BAD_CAST xmlStrdup(BAD_CAST buf);
5484 }
5485 break;
5486 case XML_SCHEMAS_HEXBINARY:
5487 *retValue = BAD_CAST xmlStrdup(BAD_CAST val->value.hex.str);
5488 break;
5489 case XML_SCHEMAS_BASE64BINARY:
5490 /*
5491 * TODO: Is the following spec piece implemented?:
5492 * SPEC: "Note: For some values the canonical form defined
5493 * above does not conform to [RFC 2045], which requires breaking
5494 * with linefeeds at appropriate intervals."
5495 */
5496 *retValue = BAD_CAST xmlStrdup(BAD_CAST val->value.base64.str);
5497 break;
5498 case XML_SCHEMAS_FLOAT: {
5499 char buf[30];
5500 /*
5501 * |m| < 16777216, -149 <= e <= 104.
5502 * TODO: Handle, NaN, INF, -INF. The format is not
5503 * yet conformant. The c type float does not cover
5504 * the whole range.
5505 */
5506 snprintf(buf, 30, "%01.14e", val->value.f);
5507 *retValue = BAD_CAST xmlStrdup(BAD_CAST buf);
5508 }
5509 break;
5510 case XML_SCHEMAS_DOUBLE: {
5511 char buf[40];
5512 /* |m| < 9007199254740992, -1075 <= e <= 970 */
5513 /*
5514 * TODO: Handle, NaN, INF, -INF. The format is not
5515 * yet conformant. The c type float does not cover
5516 * the whole range.
5517 */
5518 snprintf(buf, 40, "%01.14e", val->value.d);
5519 *retValue = BAD_CAST xmlStrdup(BAD_CAST buf);
5520 }
5521 break;
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00005522 default:
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005523 *retValue = BAD_CAST xmlStrdup(BAD_CAST "???");
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00005524 return (1);
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00005525 }
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005526 return (0);
5527}
5528
Daniel Veillardbda59572005-04-01 17:15:17 +00005529/**
Kasimier T. Buchcikc872afb2005-04-18 10:57:04 +00005530 * xmlSchemaGetCanonValueWhtsp:
5531 * @val: the precomputed value
5532 * @retValue: the returned value
5533 * @ws: the whitespace type of the value
5534 *
5535 * Get a the cononical representation of the value.
5536 * The caller has to free the returned @retValue.
5537 *
5538 * Returns 0 if the value could be built, 1 if the value type is
5539 * not supported yet and -1 in case of API errors.
5540 */
5541int
5542xmlSchemaGetCanonValueWhtsp(xmlSchemaValPtr val,
5543 const xmlChar **retValue,
5544 xmlSchemaWhitespaceValueType ws)
5545{
5546 if ((retValue == NULL) || (val == NULL))
5547 return (-1);
5548 if ((ws == XML_SCHEMA_WHITESPACE_UNKNOWN) ||
5549 (ws > XML_SCHEMA_WHITESPACE_COLLAPSE))
5550 return (-1);
5551
5552 *retValue = NULL;
5553 switch (val->type) {
5554 case XML_SCHEMAS_STRING:
5555 if (val->value.str == NULL)
5556 *retValue = BAD_CAST xmlStrdup(BAD_CAST "");
5557 else if (ws == XML_SCHEMA_WHITESPACE_COLLAPSE)
5558 *retValue = xmlSchemaCollapseString(val->value.str);
5559 else if (ws == XML_SCHEMA_WHITESPACE_REPLACE)
5560 *retValue = xmlSchemaWhiteSpaceReplace(val->value.str);
5561 if ((*retValue) == NULL)
5562 *retValue = BAD_CAST xmlStrdup(val->value.str);
5563 break;
5564 case XML_SCHEMAS_NORMSTRING:
5565 if (val->value.str == NULL)
5566 *retValue = BAD_CAST xmlStrdup(BAD_CAST "");
5567 else {
5568 if (ws == XML_SCHEMA_WHITESPACE_COLLAPSE)
5569 *retValue = xmlSchemaCollapseString(val->value.str);
5570 else
5571 *retValue = xmlSchemaWhiteSpaceReplace(val->value.str);
5572 if ((*retValue) == NULL)
5573 *retValue = BAD_CAST xmlStrdup(val->value.str);
5574 }
5575 break;
5576 default:
5577 return (xmlSchemaGetCanonValue(val, retValue));
5578 }
5579 return (0);
5580}
5581
5582/**
Daniel Veillardbda59572005-04-01 17:15:17 +00005583 * xmlSchemaGetValType:
5584 * @val: a schemas value
5585 *
5586 * Accessor for the type of a value
5587 *
5588 * Returns the xmlSchemaValType of the value
5589 */
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005590xmlSchemaValType
5591xmlSchemaGetValType(xmlSchemaValPtr val)
5592{
Daniel Veillardbda59572005-04-01 17:15:17 +00005593 if (val == NULL)
5594 return(XML_SCHEMAS_UNKNOWN);
Kasimier T. Buchcik478d6932005-03-16 16:29:18 +00005595 return (val->type);
Kasimier T. Buchcik6e224f12005-02-17 11:10:44 +00005596}
5597
Daniel Veillard5d4644e2005-04-01 13:11:58 +00005598#define bottom_xmlschemastypes
5599#include "elfgcchack.h"
Daniel Veillard4255d502002-04-16 15:50:10 +00005600#endif /* LIBXML_SCHEMAS_ENABLED */