blob: f07518bd94a571745501c56aa9015cdb3c1ef894 [file] [log] [blame]
Daniel Veillard4255d502002-04-16 15:50:10 +00001/*
2 * schemastypes.c : implementation of the XML Schema Datatypes
3 * definition and validity checking
4 *
5 * See Copyright for the status of this software.
6 *
7 * Daniel Veillard <veillard@redhat.com>
8 */
9
10#define IN_LIBXML
11#include "libxml.h"
12
13#ifdef LIBXML_SCHEMAS_ENABLED
14
15#include <string.h>
16#include <libxml/xmlmemory.h>
17#include <libxml/parser.h>
18#include <libxml/parserInternals.h>
19#include <libxml/hash.h>
20#include <libxml/valid.h>
Daniel Veillard96a4b252003-02-06 08:22:32 +000021#include <libxml/xpath.h>
22#include <libxml/uri.h>
Daniel Veillard4255d502002-04-16 15:50:10 +000023
24#include <libxml/xmlschemas.h>
25#include <libxml/schemasInternals.h>
26#include <libxml/xmlschemastypes.h>
27
Daniel Veillard070803b2002-05-03 07:29:38 +000028#ifdef HAVE_MATH_H
29#include <math.h>
30#endif
31
Daniel Veillard4255d502002-04-16 15:50:10 +000032#define DEBUG
33
34#define TODO \
35 xmlGenericError(xmlGenericErrorContext, \
36 "Unimplemented block at %s:%d\n", \
37 __FILE__, __LINE__);
38
39#define XML_SCHEMAS_NAMESPACE_NAME \
40 (const xmlChar *)"http://www.w3.org/2001/XMLSchema"
41
Daniel Veillard4255d502002-04-16 15:50:10 +000042
Daniel Veillard5f704af2003-03-05 10:01:43 +000043static unsigned long powten[10] = {
Daniel Veillard4255d502002-04-16 15:50:10 +000044 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000L,
45 100000000L, 1000000000L
46};
47
Daniel Veillard01fa6152004-06-29 17:04:39 +000048
Daniel Veillard070803b2002-05-03 07:29:38 +000049/* Date value */
50typedef struct _xmlSchemaValDate xmlSchemaValDate;
51typedef xmlSchemaValDate *xmlSchemaValDatePtr;
52struct _xmlSchemaValDate {
53 long year;
54 unsigned int mon :4; /* 1 <= mon <= 12 */
55 unsigned int day :5; /* 1 <= day <= 31 */
56 unsigned int hour :5; /* 0 <= hour <= 23 */
57 unsigned int min :6; /* 0 <= min <= 59 */
58 double sec;
Daniel Veillarda77cf712003-05-09 23:09:55 +000059 unsigned int tz_flag :1; /* is tzo explicitely set? */
Daniel Veillard070803b2002-05-03 07:29:38 +000060 int tzo :11; /* -1440 <= tzo <= 1440 */
61};
62
63/* Duration value */
64typedef struct _xmlSchemaValDuration xmlSchemaValDuration;
65typedef xmlSchemaValDuration *xmlSchemaValDurationPtr;
66struct _xmlSchemaValDuration {
67 long mon; /* mon stores years also */
68 long day;
69 double sec; /* sec stores min and hour also */
70};
71
Daniel Veillard4255d502002-04-16 15:50:10 +000072typedef struct _xmlSchemaValDecimal xmlSchemaValDecimal;
73typedef xmlSchemaValDecimal *xmlSchemaValDecimalPtr;
74struct _xmlSchemaValDecimal {
75 /* would use long long but not portable */
Daniel Veillarde637c4a2003-03-30 21:10:09 +000076 unsigned long lo;
77 unsigned long mi;
78 unsigned long hi;
Daniel Veillard4255d502002-04-16 15:50:10 +000079 unsigned int extra;
Daniel Veillard5a872412002-05-22 06:40:27 +000080 unsigned int sign:1;
William M. Brackc1939562003-08-05 15:52:22 +000081 unsigned int frac:7;
82 unsigned int total:8;
Daniel Veillard4255d502002-04-16 15:50:10 +000083};
84
Daniel Veillarde637c4a2003-03-30 21:10:09 +000085typedef struct _xmlSchemaValQName xmlSchemaValQName;
86typedef xmlSchemaValQName *xmlSchemaValQNamePtr;
87struct _xmlSchemaValQName {
88 xmlChar *name;
89 xmlChar *uri;
90};
91
Daniel Veillard70bcb0e2003-08-08 14:00:28 +000092typedef struct _xmlSchemaValHex xmlSchemaValHex;
93typedef xmlSchemaValHex *xmlSchemaValHexPtr;
94struct _xmlSchemaValHex {
95 xmlChar *str;
96 unsigned int total;
97};
98
Daniel Veillard1ac24d32003-08-27 14:15:15 +000099typedef struct _xmlSchemaValBase64 xmlSchemaValBase64;
100typedef xmlSchemaValBase64 *xmlSchemaValBase64Ptr;
101struct _xmlSchemaValBase64 {
102 xmlChar *str;
103 unsigned int total;
104};
105
Daniel Veillard4255d502002-04-16 15:50:10 +0000106struct _xmlSchemaVal {
107 xmlSchemaValType type;
108 union {
Daniel Veillard5a872412002-05-22 06:40:27 +0000109 xmlSchemaValDecimal decimal;
Daniel Veillard070803b2002-05-03 07:29:38 +0000110 xmlSchemaValDate date;
111 xmlSchemaValDuration dur;
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000112 xmlSchemaValQName qname;
Daniel Veillard70bcb0e2003-08-08 14:00:28 +0000113 xmlSchemaValHex hex;
Daniel Veillard1ac24d32003-08-27 14:15:15 +0000114 xmlSchemaValBase64 base64;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000115 float f;
116 double d;
Daniel Veillardc5a70f22003-02-06 23:41:59 +0000117 int b;
Daniel Veillardc4c21552003-03-29 10:53:38 +0000118 xmlChar *str;
Daniel Veillard4255d502002-04-16 15:50:10 +0000119 } value;
120};
121
122static int xmlSchemaTypesInitialized = 0;
123static xmlHashTablePtr xmlSchemaTypesBank = NULL;
124
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000125/*
126 * Basic types
127 */
Daniel Veillard4255d502002-04-16 15:50:10 +0000128static xmlSchemaTypePtr xmlSchemaTypeStringDef = NULL;
129static xmlSchemaTypePtr xmlSchemaTypeAnyTypeDef = NULL;
130static xmlSchemaTypePtr xmlSchemaTypeAnySimpleTypeDef = NULL;
131static xmlSchemaTypePtr xmlSchemaTypeDecimalDef = NULL;
Daniel Veillard070803b2002-05-03 07:29:38 +0000132static xmlSchemaTypePtr xmlSchemaTypeDatetimeDef = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +0000133static xmlSchemaTypePtr xmlSchemaTypeDateDef = NULL;
Daniel Veillard070803b2002-05-03 07:29:38 +0000134static xmlSchemaTypePtr xmlSchemaTypeTimeDef = NULL;
135static xmlSchemaTypePtr xmlSchemaTypeGYearDef = NULL;
136static xmlSchemaTypePtr xmlSchemaTypeGYearMonthDef = NULL;
137static xmlSchemaTypePtr xmlSchemaTypeGDayDef = NULL;
138static xmlSchemaTypePtr xmlSchemaTypeGMonthDayDef = NULL;
139static xmlSchemaTypePtr xmlSchemaTypeGMonthDef = NULL;
140static xmlSchemaTypePtr xmlSchemaTypeDurationDef = NULL;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000141static xmlSchemaTypePtr xmlSchemaTypeFloatDef = NULL;
Daniel Veillardc5a70f22003-02-06 23:41:59 +0000142static xmlSchemaTypePtr xmlSchemaTypeBooleanDef = NULL;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000143static xmlSchemaTypePtr xmlSchemaTypeDoubleDef = NULL;
Daniel Veillard560c2a42003-07-06 21:13:49 +0000144static xmlSchemaTypePtr xmlSchemaTypeHexBinaryDef = NULL;
Daniel Veillard1ac24d32003-08-27 14:15:15 +0000145static xmlSchemaTypePtr xmlSchemaTypeBase64BinaryDef = NULL;
Daniel Veillarde5b110b2003-02-04 14:43:39 +0000146static xmlSchemaTypePtr xmlSchemaTypeAnyURIDef = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +0000147
148/*
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000149 * Derived types
150 */
151static xmlSchemaTypePtr xmlSchemaTypePositiveIntegerDef = NULL;
152static xmlSchemaTypePtr xmlSchemaTypeNonPositiveIntegerDef = NULL;
153static xmlSchemaTypePtr xmlSchemaTypeNegativeIntegerDef = NULL;
154static xmlSchemaTypePtr xmlSchemaTypeNonNegativeIntegerDef = NULL;
155static xmlSchemaTypePtr xmlSchemaTypeIntegerDef = NULL;
156static xmlSchemaTypePtr xmlSchemaTypeLongDef = NULL;
157static xmlSchemaTypePtr xmlSchemaTypeIntDef = NULL;
158static xmlSchemaTypePtr xmlSchemaTypeShortDef = NULL;
159static xmlSchemaTypePtr xmlSchemaTypeByteDef = NULL;
160static xmlSchemaTypePtr xmlSchemaTypeUnsignedLongDef = NULL;
161static xmlSchemaTypePtr xmlSchemaTypeUnsignedIntDef = NULL;
162static xmlSchemaTypePtr xmlSchemaTypeUnsignedShortDef = NULL;
163static xmlSchemaTypePtr xmlSchemaTypeUnsignedByteDef = NULL;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000164static xmlSchemaTypePtr xmlSchemaTypeNormStringDef = NULL;
165static xmlSchemaTypePtr xmlSchemaTypeTokenDef = NULL;
166static xmlSchemaTypePtr xmlSchemaTypeLanguageDef = NULL;
167static xmlSchemaTypePtr xmlSchemaTypeNameDef = NULL;
168static xmlSchemaTypePtr xmlSchemaTypeQNameDef = NULL;
Daniel Veillarde5b110b2003-02-04 14:43:39 +0000169static xmlSchemaTypePtr xmlSchemaTypeNCNameDef = NULL;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000170static xmlSchemaTypePtr xmlSchemaTypeIdDef = NULL;
171static xmlSchemaTypePtr xmlSchemaTypeIdrefDef = NULL;
172static xmlSchemaTypePtr xmlSchemaTypeIdrefsDef = NULL;
Daniel Veillarda1a9d042003-03-18 16:53:17 +0000173static xmlSchemaTypePtr xmlSchemaTypeEntityDef = NULL;
174static xmlSchemaTypePtr xmlSchemaTypeEntitiesDef = NULL;
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000175static xmlSchemaTypePtr xmlSchemaTypeNotationDef = NULL;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000176static xmlSchemaTypePtr xmlSchemaTypeNmtokenDef = NULL;
177static xmlSchemaTypePtr xmlSchemaTypeNmtokensDef = NULL;
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000178
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000179/************************************************************************
180 * *
181 * Datatype error handlers *
182 * *
183 ************************************************************************/
184/**
185 * xmlSchemaTypeErrMemory:
186 * @extra: extra informations
187 *
188 * Handle an out of memory condition
189 */
190static void
191xmlSchemaTypeErrMemory(xmlNodePtr node, const char *extra)
192{
193 __xmlSimpleError(XML_FROM_DATATYPE, XML_ERR_NO_MEMORY, node, NULL, extra);
194}
195
196/************************************************************************
197 * *
198 * Base types support *
199 * *
200 ************************************************************************/
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000201/*
Daniel Veillard4255d502002-04-16 15:50:10 +0000202 * xmlSchemaInitBasicType:
203 * @name: the type name
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000204 * @type: the value type associated
Daniel Veillard4255d502002-04-16 15:50:10 +0000205 *
Daniel Veillard01fa6152004-06-29 17:04:39 +0000206 * Initialize one primitive built-in type
Daniel Veillard4255d502002-04-16 15:50:10 +0000207 */
208static xmlSchemaTypePtr
Daniel Veillard01fa6152004-06-29 17:04:39 +0000209xmlSchemaInitBasicType(const char *name, xmlSchemaValType type,
210 xmlSchemaTypePtr baseType) {
Daniel Veillard4255d502002-04-16 15:50:10 +0000211 xmlSchemaTypePtr ret;
212
213 ret = (xmlSchemaTypePtr) xmlMalloc(sizeof(xmlSchemaType));
214 if (ret == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000215 xmlSchemaTypeErrMemory(NULL, "could not initialize basic types");
Daniel Veillard4255d502002-04-16 15:50:10 +0000216 return(NULL);
217 }
218 memset(ret, 0, sizeof(xmlSchemaType));
Daniel Veillardbe9c6322003-11-22 20:37:51 +0000219 ret->name = (const xmlChar *)name;
Daniel Veillard4255d502002-04-16 15:50:10 +0000220 ret->type = XML_SCHEMA_TYPE_BASIC;
Daniel Veillard01fa6152004-06-29 17:04:39 +0000221 ret->baseType = baseType;
222 /*
223 * Hack to reflect the variety.
224 */
225 if ((type == XML_SCHEMAS_IDREFS) ||
226 (type == XML_SCHEMAS_NMTOKENS) ||
227 (type == XML_SCHEMAS_ENTITIES))
228 ret->flags |= XML_SCHEMAS_TYPE_VARIETY_LIST;
229 else if (type != XML_SCHEMAS_UNKNOWN)
230 ret->flags |= XML_SCHEMAS_TYPE_VARIETY_ATOMIC;
Daniel Veillard4255d502002-04-16 15:50:10 +0000231 ret->contentType = XML_SCHEMA_CONTENT_BASIC;
Daniel Veillard01fa6152004-06-29 17:04:39 +0000232 switch (type) {
233 case XML_SCHEMAS_STRING:
234 case XML_SCHEMAS_DECIMAL:
235 case XML_SCHEMAS_DATE:
236 case XML_SCHEMAS_DATETIME:
237 case XML_SCHEMAS_TIME:
238 case XML_SCHEMAS_GYEAR:
239 case XML_SCHEMAS_GYEARMONTH:
240 case XML_SCHEMAS_GMONTH:
241 case XML_SCHEMAS_GMONTHDAY:
242 case XML_SCHEMAS_GDAY:
243 case XML_SCHEMAS_DURATION:
244 case XML_SCHEMAS_FLOAT:
245 case XML_SCHEMAS_DOUBLE:
246 case XML_SCHEMAS_BOOLEAN:
247 case XML_SCHEMAS_ANYURI:
248 case XML_SCHEMAS_HEXBINARY:
249 case XML_SCHEMAS_BASE64BINARY:
250 case XML_SCHEMAS_QNAME:
251 case XML_SCHEMAS_NOTATION:
252 ret->flags |= XML_SCHEMAS_TYPE_BUILTIN_PRIMITIVE;
William M. Brack96d2eff2004-06-30 11:48:47 +0000253 default:
254 break;
Daniel Veillard01fa6152004-06-29 17:04:39 +0000255 }
256
Daniel Veillard4255d502002-04-16 15:50:10 +0000257 xmlHashAddEntry2(xmlSchemaTypesBank, ret->name,
258 XML_SCHEMAS_NAMESPACE_NAME, ret);
Daniel Veillard01fa6152004-06-29 17:04:39 +0000259 ret->builtInType = type;
Daniel Veillard4255d502002-04-16 15:50:10 +0000260 return(ret);
261}
262
263/*
264 * xmlSchemaInitTypes:
265 *
266 * Initialize the default XML Schemas type library
267 */
268void
Daniel Veillard6560a422003-03-27 21:25:38 +0000269xmlSchemaInitTypes(void)
270{
Daniel Veillard4255d502002-04-16 15:50:10 +0000271 if (xmlSchemaTypesInitialized != 0)
Daniel Veillard6560a422003-03-27 21:25:38 +0000272 return;
Daniel Veillard4255d502002-04-16 15:50:10 +0000273 xmlSchemaTypesBank = xmlHashCreate(40);
Daniel Veillard6560a422003-03-27 21:25:38 +0000274
Daniel Veillard01fa6152004-06-29 17:04:39 +0000275
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000276 /*
Daniel Veillard01fa6152004-06-29 17:04:39 +0000277 * 3.4.7 Built-in Complex Type Definition
278 */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000279 xmlSchemaTypeAnyTypeDef = xmlSchemaInitBasicType("anyType",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000280 XML_SCHEMAS_UNKNOWN,
281 NULL);
282 xmlSchemaTypeAnyTypeDef->baseType = xmlSchemaTypeAnyTypeDef;
283 xmlSchemaTypeAnyTypeDef->contentType = XML_SCHEMA_CONTENT_MIXED;
284 {
285 xmlSchemaWildcardPtr wild;
286
287 wild = (xmlSchemaWildcardPtr) xmlMalloc(sizeof(xmlSchemaWildcard));
288 if (wild == NULL) {
289 xmlSchemaTypeErrMemory(NULL, "could not create a wildcard on anyType");
290 return;
291 }
292 memset(wild, 0, sizeof(xmlSchemaWildcard));
293 wild->any = 1;
294 wild->processContents = XML_SCHEMAS_ANY_LAX;
295 wild->minOccurs = 1;
296 wild->maxOccurs = 1;
297 xmlSchemaTypeAnyTypeDef->attributeWildcard = wild;
298 }
299 xmlSchemaTypeAnySimpleTypeDef = xmlSchemaInitBasicType("anySimpleType",
300 XML_SCHEMAS_UNKNOWN,
301 xmlSchemaTypeAnyTypeDef);
302 /*
303 * primitive datatypes
304 */
305 xmlSchemaTypeStringDef = xmlSchemaInitBasicType("string",
306 XML_SCHEMAS_STRING,
307 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000308 xmlSchemaTypeDecimalDef = xmlSchemaInitBasicType("decimal",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000309 XML_SCHEMAS_DECIMAL,
310 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000311 xmlSchemaTypeDateDef = xmlSchemaInitBasicType("date",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000312 XML_SCHEMAS_DATE,
313 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000314 xmlSchemaTypeDatetimeDef = xmlSchemaInitBasicType("dateTime",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000315 XML_SCHEMAS_DATETIME,
316 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000317 xmlSchemaTypeTimeDef = xmlSchemaInitBasicType("time",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000318 XML_SCHEMAS_TIME,
319 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000320 xmlSchemaTypeGYearDef = xmlSchemaInitBasicType("gYear",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000321 XML_SCHEMAS_GYEAR,
322 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000323 xmlSchemaTypeGYearMonthDef = xmlSchemaInitBasicType("gYearMonth",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000324 XML_SCHEMAS_GYEARMONTH,
325 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000326 xmlSchemaTypeGMonthDef = xmlSchemaInitBasicType("gMonth",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000327 XML_SCHEMAS_GMONTH,
328 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000329 xmlSchemaTypeGMonthDayDef = xmlSchemaInitBasicType("gMonthDay",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000330 XML_SCHEMAS_GMONTHDAY,
331 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000332 xmlSchemaTypeGDayDef = xmlSchemaInitBasicType("gDay",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000333 XML_SCHEMAS_GDAY,
334 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000335 xmlSchemaTypeDurationDef = xmlSchemaInitBasicType("duration",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000336 XML_SCHEMAS_DURATION,
337 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000338 xmlSchemaTypeFloatDef = xmlSchemaInitBasicType("float",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000339 XML_SCHEMAS_FLOAT,
340 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000341 xmlSchemaTypeDoubleDef = xmlSchemaInitBasicType("double",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000342 XML_SCHEMAS_DOUBLE,
343 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000344 xmlSchemaTypeBooleanDef = xmlSchemaInitBasicType("boolean",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000345 XML_SCHEMAS_BOOLEAN,
346 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000347 xmlSchemaTypeAnyURIDef = xmlSchemaInitBasicType("anyURI",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000348 XML_SCHEMAS_ANYURI,
349 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard560c2a42003-07-06 21:13:49 +0000350 xmlSchemaTypeHexBinaryDef = xmlSchemaInitBasicType("hexBinary",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000351 XML_SCHEMAS_HEXBINARY,
352 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard1ac24d32003-08-27 14:15:15 +0000353 xmlSchemaTypeBase64BinaryDef
Daniel Veillard01fa6152004-06-29 17:04:39 +0000354 = xmlSchemaInitBasicType("base64Binary", XML_SCHEMAS_BASE64BINARY,
355 xmlSchemaTypeAnySimpleTypeDef);
356 xmlSchemaTypeNotationDef = xmlSchemaInitBasicType("NOTATION",
357 XML_SCHEMAS_NOTATION,
358 xmlSchemaTypeAnySimpleTypeDef);
359 xmlSchemaTypeQNameDef = xmlSchemaInitBasicType("QName",
360 XML_SCHEMAS_QNAME,
361 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard4255d502002-04-16 15:50:10 +0000362
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000363 /*
364 * derived datatypes
365 */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000366 xmlSchemaTypeIntegerDef = xmlSchemaInitBasicType("integer",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000367 XML_SCHEMAS_INTEGER,
368 xmlSchemaTypeDecimalDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000369 xmlSchemaTypeNonPositiveIntegerDef =
370 xmlSchemaInitBasicType("nonPositiveInteger",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000371 XML_SCHEMAS_NPINTEGER,
372 xmlSchemaTypeIntegerDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000373 xmlSchemaTypeNegativeIntegerDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000374 xmlSchemaInitBasicType("negativeInteger", XML_SCHEMAS_NINTEGER,
375 xmlSchemaTypeNonPositiveIntegerDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000376 xmlSchemaTypeLongDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000377 xmlSchemaInitBasicType("long", XML_SCHEMAS_LONG,
378 xmlSchemaTypeIntegerDef);
379 xmlSchemaTypeIntDef = xmlSchemaInitBasicType("int", XML_SCHEMAS_INT,
380 xmlSchemaTypeLongDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000381 xmlSchemaTypeShortDef = xmlSchemaInitBasicType("short",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000382 XML_SCHEMAS_SHORT,
383 xmlSchemaTypeIntDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000384 xmlSchemaTypeByteDef = xmlSchemaInitBasicType("byte",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000385 XML_SCHEMAS_BYTE,
386 xmlSchemaTypeShortDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000387 xmlSchemaTypeNonNegativeIntegerDef =
388 xmlSchemaInitBasicType("nonNegativeInteger",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000389 XML_SCHEMAS_NNINTEGER,
390 xmlSchemaTypeIntegerDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000391 xmlSchemaTypeUnsignedLongDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000392 xmlSchemaInitBasicType("unsignedLong", XML_SCHEMAS_ULONG,
393 xmlSchemaTypeNonNegativeIntegerDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000394 xmlSchemaTypeUnsignedIntDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000395 xmlSchemaInitBasicType("unsignedInt", XML_SCHEMAS_UINT,
396 xmlSchemaTypeUnsignedLongDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000397 xmlSchemaTypeUnsignedShortDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000398 xmlSchemaInitBasicType("unsignedShort", XML_SCHEMAS_USHORT,
399 xmlSchemaTypeUnsignedIntDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000400 xmlSchemaTypeUnsignedByteDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000401 xmlSchemaInitBasicType("unsignedByte", XML_SCHEMAS_UBYTE,
402 xmlSchemaTypeUnsignedShortDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000403 xmlSchemaTypePositiveIntegerDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000404 xmlSchemaInitBasicType("positiveInteger", XML_SCHEMAS_PINTEGER,
405 xmlSchemaTypeNonNegativeIntegerDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000406 xmlSchemaTypeNormStringDef = xmlSchemaInitBasicType("normalizedString",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000407 XML_SCHEMAS_NORMSTRING,
408 xmlSchemaTypeStringDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000409 xmlSchemaTypeTokenDef = xmlSchemaInitBasicType("token",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000410 XML_SCHEMAS_TOKEN,
411 xmlSchemaTypeNormStringDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000412 xmlSchemaTypeLanguageDef = xmlSchemaInitBasicType("language",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000413 XML_SCHEMAS_LANGUAGE,
414 xmlSchemaTypeTokenDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000415 xmlSchemaTypeNameDef = xmlSchemaInitBasicType("Name",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000416 XML_SCHEMAS_NAME,
417 xmlSchemaTypeTokenDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000418 xmlSchemaTypeNmtokenDef = xmlSchemaInitBasicType("NMTOKEN",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000419 XML_SCHEMAS_NMTOKEN,
420 xmlSchemaTypeTokenDef);
421 xmlSchemaTypeNCNameDef = xmlSchemaInitBasicType("NCName",
422 XML_SCHEMAS_NCNAME,
423 xmlSchemaTypeNameDef);
424 xmlSchemaTypeIdDef = xmlSchemaInitBasicType("ID", XML_SCHEMAS_ID,
425 xmlSchemaTypeNCNameDef);
426 xmlSchemaTypeIdrefDef = xmlSchemaInitBasicType("IDREF",
427 XML_SCHEMAS_IDREF,
428 xmlSchemaTypeNCNameDef);
429 xmlSchemaTypeIdrefsDef = xmlSchemaInitBasicType("IDREFS",
430 XML_SCHEMAS_IDREFS,
431 xmlSchemaTypeIdrefDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000432 xmlSchemaTypeNmtokensDef = xmlSchemaInitBasicType("NMTOKENS",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000433 XML_SCHEMAS_NMTOKENS,
434 xmlSchemaTypeNmtokenDef);
435 xmlSchemaTypeEntityDef = xmlSchemaInitBasicType("ENTITY",
436 XML_SCHEMAS_ENTITY,
437 xmlSchemaTypeNCNameDef);
438 xmlSchemaTypeEntitiesDef = xmlSchemaInitBasicType("ENTITIES",
439 XML_SCHEMAS_ENTITIES,
440 xmlSchemaTypeNCNameDef);
Daniel Veillard4255d502002-04-16 15:50:10 +0000441 xmlSchemaTypesInitialized = 1;
442}
443
444/**
445 * xmlSchemaCleanupTypes:
446 *
447 * Cleanup the default XML Schemas type library
448 */
449void
450xmlSchemaCleanupTypes(void) {
451 if (xmlSchemaTypesInitialized == 0)
452 return;
Daniel Veillard01fa6152004-06-29 17:04:39 +0000453 xmlSchemaFreeWildcard(xmlSchemaTypeAnyTypeDef->attributeWildcard);
Daniel Veillard4255d502002-04-16 15:50:10 +0000454 xmlHashFree(xmlSchemaTypesBank, (xmlHashDeallocator) xmlSchemaFreeType);
455 xmlSchemaTypesInitialized = 0;
456}
457
458/**
Daniel Veillardc0826a72004-08-10 14:17:33 +0000459 * xmlSchemaGetBuiltInType:
Daniel Veillard01fa6152004-06-29 17:04:39 +0000460 * @type: the built-in type
461 * @facetType: the facet type
462 *
463 * Evaluates if a specific facet can be
464 * used in conjunction with a type.
465 *
466 * Returns 1 if the facet can be used with the given built-in type,
467 * 0 otherwise and -1 in case the type is not a built-in type.
468 */
469int
470xmlSchemaIsBuiltInTypeFacet(xmlSchemaTypePtr type, int facetType)
471{
472 if (type->type != XML_SCHEMA_TYPE_BASIC)
473 return (-1);
474 switch (type->builtInType) {
475 case XML_SCHEMAS_BOOLEAN:
476 if ((facetType == XML_SCHEMA_FACET_PATTERN) ||
477 (facetType == XML_SCHEMA_FACET_WHITESPACE))
478 return (1);
479 else
480 return (0);
481 case XML_SCHEMAS_STRING:
482 case XML_SCHEMAS_NOTATION:
483 case XML_SCHEMAS_QNAME:
484 case XML_SCHEMAS_ANYURI:
485 case XML_SCHEMAS_BASE64BINARY:
486 case XML_SCHEMAS_HEXBINARY:
487 if ((facetType == XML_SCHEMA_FACET_LENGTH) ||
488 (facetType == XML_SCHEMA_FACET_MINLENGTH) ||
489 (facetType == XML_SCHEMA_FACET_MAXLENGTH) ||
490 (facetType == XML_SCHEMA_FACET_PATTERN) ||
491 (facetType == XML_SCHEMA_FACET_ENUMERATION) ||
492 (facetType == XML_SCHEMA_FACET_WHITESPACE))
493 return (1);
494 else
495 return (0);
496 case XML_SCHEMAS_DECIMAL:
497 if ((facetType == XML_SCHEMA_FACET_TOTALDIGITS) ||
498 (facetType == XML_SCHEMA_FACET_FRACTIONDIGITS) ||
499 (facetType == XML_SCHEMA_FACET_PATTERN) ||
500 (facetType == XML_SCHEMA_FACET_WHITESPACE) ||
501 (facetType == XML_SCHEMA_FACET_ENUMERATION) ||
502 (facetType == XML_SCHEMA_FACET_MAXINCLUSIVE) ||
503 (facetType == XML_SCHEMA_FACET_MAXEXCLUSIVE) ||
504 (facetType == XML_SCHEMA_FACET_MININCLUSIVE) ||
505 (facetType == XML_SCHEMA_FACET_MINEXCLUSIVE))
506 return (1);
507 else
508 return (0);
509 case XML_SCHEMAS_TIME:
510 case XML_SCHEMAS_GDAY:
511 case XML_SCHEMAS_GMONTH:
512 case XML_SCHEMAS_GMONTHDAY:
513 case XML_SCHEMAS_GYEAR:
514 case XML_SCHEMAS_GYEARMONTH:
515 case XML_SCHEMAS_DATE:
516 case XML_SCHEMAS_DATETIME:
517 case XML_SCHEMAS_DURATION:
518 case XML_SCHEMAS_FLOAT:
519 case XML_SCHEMAS_DOUBLE:
520 if ((facetType == XML_SCHEMA_FACET_PATTERN) ||
521 (facetType == XML_SCHEMA_FACET_ENUMERATION) ||
522 (facetType == XML_SCHEMA_FACET_WHITESPACE) ||
523 (facetType == XML_SCHEMA_FACET_MAXINCLUSIVE) ||
524 (facetType == XML_SCHEMA_FACET_MAXEXCLUSIVE) ||
525 (facetType == XML_SCHEMA_FACET_MININCLUSIVE) ||
526 (facetType == XML_SCHEMA_FACET_MINEXCLUSIVE))
527 return (1);
528 else
529 return (0);
530 default:
531 return (0);
532 }
533 return (0);
534}
535
536/**
537 * xmlSchemaGetBuiltInType:
538 * @type: the type of the built in type
539 *
540 * Gives you the type struct for a built-in
541 * type by its type id.
542 *
543 * Returns the type if found, NULL otherwise.
544 */
545xmlSchemaTypePtr
546xmlSchemaGetBuiltInType(xmlSchemaValType type)
547{
548 if (xmlSchemaTypesInitialized == 0)
549 xmlSchemaInitTypes();
550 switch (type) {
551
552 case XML_SCHEMAS_ANYSIMPLETYPE:
553 return (xmlSchemaTypeAnySimpleTypeDef);
554 case XML_SCHEMAS_STRING:
555 return (xmlSchemaTypeStringDef);
556 case XML_SCHEMAS_NORMSTRING:
557 return (xmlSchemaTypeNormStringDef);
558 case XML_SCHEMAS_DECIMAL:
559 return (xmlSchemaTypeDecimalDef);
560 case XML_SCHEMAS_TIME:
561 return (xmlSchemaTypeTimeDef);
562 case XML_SCHEMAS_GDAY:
563 return (xmlSchemaTypeGDayDef);
564 case XML_SCHEMAS_GMONTH:
565 return (xmlSchemaTypeGMonthDef);
566 case XML_SCHEMAS_GMONTHDAY:
567 return (xmlSchemaTypeGMonthDayDef);
568 case XML_SCHEMAS_GYEAR:
569 return (xmlSchemaTypeGYearDef);
570 case XML_SCHEMAS_GYEARMONTH:
571 return (xmlSchemaTypeGYearMonthDef);
572 case XML_SCHEMAS_DATE:
573 return (xmlSchemaTypeDateDef);
574 case XML_SCHEMAS_DATETIME:
575 return (xmlSchemaTypeDatetimeDef);
576 case XML_SCHEMAS_DURATION:
577 return (xmlSchemaTypeDurationDef);
578 case XML_SCHEMAS_FLOAT:
579 return (xmlSchemaTypeFloatDef);
580 case XML_SCHEMAS_DOUBLE:
581 return (xmlSchemaTypeDoubleDef);
582 case XML_SCHEMAS_BOOLEAN:
583 return (xmlSchemaTypeBooleanDef);
584 case XML_SCHEMAS_TOKEN:
585 return (xmlSchemaTypeTokenDef);
586 case XML_SCHEMAS_LANGUAGE:
587 return (xmlSchemaTypeLanguageDef);
588 case XML_SCHEMAS_NMTOKEN:
589 return (xmlSchemaTypeNmtokenDef);
590 case XML_SCHEMAS_NMTOKENS:
591 return (xmlSchemaTypeNmtokensDef);
592 case XML_SCHEMAS_NAME:
593 return (xmlSchemaTypeNameDef);
594 case XML_SCHEMAS_QNAME:
595 return (xmlSchemaTypeQNameDef);
596 case XML_SCHEMAS_NCNAME:
597 return (xmlSchemaTypeNCNameDef);
598 case XML_SCHEMAS_ID:
599 return (xmlSchemaTypeIdDef);
600 case XML_SCHEMAS_IDREF:
601 return (xmlSchemaTypeIdrefDef);
602 case XML_SCHEMAS_IDREFS:
603 return (xmlSchemaTypeIdrefsDef);
604 case XML_SCHEMAS_ENTITY:
605 return (xmlSchemaTypeEntityDef);
606 case XML_SCHEMAS_ENTITIES:
607 return (xmlSchemaTypeEntitiesDef);
608 case XML_SCHEMAS_NOTATION:
609 return (xmlSchemaTypeNotationDef);
610 case XML_SCHEMAS_ANYURI:
611 return (xmlSchemaTypeAnyURIDef);
612 case XML_SCHEMAS_INTEGER:
613 return (xmlSchemaTypeIntegerDef);
614 case XML_SCHEMAS_NPINTEGER:
615 return (xmlSchemaTypeNonPositiveIntegerDef);
616 case XML_SCHEMAS_NINTEGER:
617 return (xmlSchemaTypeNegativeIntegerDef);
618 case XML_SCHEMAS_NNINTEGER:
619 return (xmlSchemaTypeNonNegativeIntegerDef);
620 case XML_SCHEMAS_PINTEGER:
621 return (xmlSchemaTypePositiveIntegerDef);
622 case XML_SCHEMAS_INT:
623 return (xmlSchemaTypeIntDef);
624 case XML_SCHEMAS_UINT:
625 return (xmlSchemaTypeUnsignedIntDef);
626 case XML_SCHEMAS_LONG:
627 return (xmlSchemaTypeLongDef);
628 case XML_SCHEMAS_ULONG:
629 return (xmlSchemaTypeUnsignedLongDef);
630 case XML_SCHEMAS_SHORT:
631 return (xmlSchemaTypeShortDef);
632 case XML_SCHEMAS_USHORT:
633 return (xmlSchemaTypeUnsignedShortDef);
634 case XML_SCHEMAS_BYTE:
635 return (xmlSchemaTypeByteDef);
636 case XML_SCHEMAS_UBYTE:
637 return (xmlSchemaTypeUnsignedByteDef);
638 case XML_SCHEMAS_HEXBINARY:
639 return (xmlSchemaTypeHexBinaryDef);
640 case XML_SCHEMAS_BASE64BINARY:
641 return (xmlSchemaTypeBase64BinaryDef);
642 case XML_SCHEMAS_ANYTYPE:
643 return (xmlSchemaTypeAnyTypeDef);
644 default:
645 return (NULL);
646 }
647}
648
649/**
Daniel Veillard4255d502002-04-16 15:50:10 +0000650 * xmlSchemaNewValue:
651 * @type: the value type
652 *
653 * Allocate a new simple type value
654 *
655 * Returns a pointer to the new value or NULL in case of error
656 */
657static xmlSchemaValPtr
658xmlSchemaNewValue(xmlSchemaValType type) {
659 xmlSchemaValPtr value;
660
661 value = (xmlSchemaValPtr) xmlMalloc(sizeof(xmlSchemaVal));
662 if (value == NULL) {
663 return(NULL);
664 }
665 memset(value, 0, sizeof(xmlSchemaVal));
666 value->type = type;
667 return(value);
668}
669
670/**
671 * xmlSchemaFreeValue:
672 * @value: the value to free
673 *
674 * Cleanup the default XML Schemas type library
675 */
676void
677xmlSchemaFreeValue(xmlSchemaValPtr value) {
678 if (value == NULL)
679 return;
Daniel Veillardc4c21552003-03-29 10:53:38 +0000680 switch (value->type) {
681 case XML_SCHEMAS_STRING:
682 case XML_SCHEMAS_NORMSTRING:
683 case XML_SCHEMAS_TOKEN:
684 case XML_SCHEMAS_LANGUAGE:
685 case XML_SCHEMAS_NMTOKEN:
686 case XML_SCHEMAS_NMTOKENS:
687 case XML_SCHEMAS_NAME:
Daniel Veillardc4c21552003-03-29 10:53:38 +0000688 case XML_SCHEMAS_NCNAME:
689 case XML_SCHEMAS_ID:
690 case XML_SCHEMAS_IDREF:
691 case XML_SCHEMAS_IDREFS:
692 case XML_SCHEMAS_ENTITY:
693 case XML_SCHEMAS_ENTITIES:
694 case XML_SCHEMAS_NOTATION:
695 case XML_SCHEMAS_ANYURI:
696 if (value->value.str != NULL)
697 xmlFree(value->value.str);
698 break;
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000699 case XML_SCHEMAS_QNAME:
700 if (value->value.qname.uri != NULL)
701 xmlFree(value->value.qname.uri);
702 if (value->value.qname.name != NULL)
703 xmlFree(value->value.qname.name);
704 break;
Daniel Veillard70bcb0e2003-08-08 14:00:28 +0000705 case XML_SCHEMAS_HEXBINARY:
706 if (value->value.hex.str != NULL)
707 xmlFree(value->value.hex.str);
708 break;
Daniel Veillard1ac24d32003-08-27 14:15:15 +0000709 case XML_SCHEMAS_BASE64BINARY:
710 if (value->value.base64.str != NULL)
711 xmlFree(value->value.base64.str);
712 break;
Daniel Veillardc4c21552003-03-29 10:53:38 +0000713 default:
714 break;
715 }
Daniel Veillard4255d502002-04-16 15:50:10 +0000716 xmlFree(value);
717}
718
719/**
720 * xmlSchemaGetPredefinedType:
721 * @name: the type name
722 * @ns: the URI of the namespace usually "http://www.w3.org/2001/XMLSchema"
723 *
724 * Lookup a type in the default XML Schemas type library
725 *
726 * Returns the type if found, NULL otherwise
727 */
728xmlSchemaTypePtr
729xmlSchemaGetPredefinedType(const xmlChar *name, const xmlChar *ns) {
730 if (xmlSchemaTypesInitialized == 0)
731 xmlSchemaInitTypes();
732 if (name == NULL)
733 return(NULL);
734 return((xmlSchemaTypePtr) xmlHashLookup2(xmlSchemaTypesBank, name, ns));
735}
Daniel Veillard070803b2002-05-03 07:29:38 +0000736
Daniel Veillard01fa6152004-06-29 17:04:39 +0000737/**
738 * xmlSchemaGetBuiltInListSimpleTypeItemType:
739 * @type: the built-in simple type.
740 *
Daniel Veillardc0826a72004-08-10 14:17:33 +0000741 * Returns the item type of @type as defined by the built-in datatype
742 * hierarchy of XML Schema Part 2: Datatypes, or NULL in case of an error.
Daniel Veillard01fa6152004-06-29 17:04:39 +0000743 */
744xmlSchemaTypePtr
745xmlSchemaGetBuiltInListSimpleTypeItemType(xmlSchemaTypePtr type)
746{
747 if (type->type != XML_SCHEMA_TYPE_BASIC)
748 return (NULL);
749 switch (type->builtInType) {
750 case XML_SCHEMAS_NMTOKENS:
751 return (xmlSchemaTypeNmtokenDef );
752 case XML_SCHEMAS_IDREFS:
753 return (xmlSchemaTypeIdrefDef);
754 case XML_SCHEMAS_ENTITIES:
755 return (xmlSchemaTypeEntityDef);
756 default:
757 return (NULL);
758 }
759}
760
Daniel Veillard070803b2002-05-03 07:29:38 +0000761/****************************************************************
762 * *
763 * Convenience macros and functions *
764 * *
765 ****************************************************************/
766
767#define IS_TZO_CHAR(c) \
768 ((c == 0) || (c == 'Z') || (c == '+') || (c == '-'))
769
770#define VALID_YEAR(yr) (yr != 0)
771#define VALID_MONTH(mon) ((mon >= 1) && (mon <= 12))
772/* VALID_DAY should only be used when month is unknown */
773#define VALID_DAY(day) ((day >= 1) && (day <= 31))
774#define VALID_HOUR(hr) ((hr >= 0) && (hr <= 23))
775#define VALID_MIN(min) ((min >= 0) && (min <= 59))
776#define VALID_SEC(sec) ((sec >= 0) && (sec < 60))
777#define VALID_TZO(tzo) ((tzo > -1440) && (tzo < 1440))
778#define IS_LEAP(y) \
779 (((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0))
780
Daniel Veillardebe25d42004-03-25 09:35:49 +0000781static const unsigned int daysInMonth[12] =
Daniel Veillard070803b2002-05-03 07:29:38 +0000782 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
Daniel Veillardebe25d42004-03-25 09:35:49 +0000783static const unsigned int daysInMonthLeap[12] =
Daniel Veillard070803b2002-05-03 07:29:38 +0000784 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
785
Daniel Veillard5a872412002-05-22 06:40:27 +0000786#define MAX_DAYINMONTH(yr,mon) \
787 (IS_LEAP(yr) ? daysInMonthLeap[mon - 1] : daysInMonth[mon - 1])
788
Daniel Veillard070803b2002-05-03 07:29:38 +0000789#define VALID_MDAY(dt) \
790 (IS_LEAP(dt->year) ? \
791 (dt->day <= daysInMonthLeap[dt->mon - 1]) : \
792 (dt->day <= daysInMonth[dt->mon - 1]))
793
794#define VALID_DATE(dt) \
795 (VALID_YEAR(dt->year) && VALID_MONTH(dt->mon) && VALID_MDAY(dt))
796
797#define VALID_TIME(dt) \
798 (VALID_HOUR(dt->hour) && VALID_MIN(dt->min) && \
799 VALID_SEC(dt->sec) && VALID_TZO(dt->tzo))
800
801#define VALID_DATETIME(dt) \
802 (VALID_DATE(dt) && VALID_TIME(dt))
803
804#define SECS_PER_MIN (60)
805#define SECS_PER_HOUR (60 * SECS_PER_MIN)
806#define SECS_PER_DAY (24 * SECS_PER_HOUR)
807
Daniel Veillard5a872412002-05-22 06:40:27 +0000808static const long dayInYearByMonth[12] =
809 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
810static const long dayInLeapYearByMonth[12] =
811 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 };
812
813#define DAY_IN_YEAR(day, month, year) \
814 ((IS_LEAP(year) ? \
815 dayInLeapYearByMonth[month - 1] : \
816 dayInYearByMonth[month - 1]) + day)
817
818#ifdef DEBUG
819#define DEBUG_DATE(dt) \
820 xmlGenericError(xmlGenericErrorContext, \
821 "type=%o %04ld-%02u-%02uT%02u:%02u:%03f", \
822 dt->type,dt->value.date.year,dt->value.date.mon, \
823 dt->value.date.day,dt->value.date.hour,dt->value.date.min, \
824 dt->value.date.sec); \
825 if (dt->value.date.tz_flag) \
826 if (dt->value.date.tzo != 0) \
827 xmlGenericError(xmlGenericErrorContext, \
828 "%+05d\n",dt->value.date.tzo); \
829 else \
830 xmlGenericError(xmlGenericErrorContext, "Z\n"); \
831 else \
832 xmlGenericError(xmlGenericErrorContext,"\n")
833#else
834#define DEBUG_DATE(dt)
835#endif
836
Daniel Veillard070803b2002-05-03 07:29:38 +0000837/**
838 * _xmlSchemaParseGYear:
839 * @dt: pointer to a date structure
840 * @str: pointer to the string to analyze
841 *
842 * Parses a xs:gYear without time zone and fills in the appropriate
843 * field of the @dt structure. @str is updated to point just after the
844 * xs:gYear. It is supposed that @dt->year is big enough to contain
845 * the year.
846 *
847 * Returns 0 or the error code
848 */
849static int
850_xmlSchemaParseGYear (xmlSchemaValDatePtr dt, const xmlChar **str) {
851 const xmlChar *cur = *str, *firstChar;
852 int isneg = 0, digcnt = 0;
853
854 if (((*cur < '0') || (*cur > '9')) &&
855 (*cur != '-') && (*cur != '+'))
856 return -1;
857
858 if (*cur == '-') {
859 isneg = 1;
860 cur++;
861 }
862
863 firstChar = cur;
864
865 while ((*cur >= '0') && (*cur <= '9')) {
866 dt->year = dt->year * 10 + (*cur - '0');
867 cur++;
868 digcnt++;
869 }
870
871 /* year must be at least 4 digits (CCYY); over 4
872 * digits cannot have a leading zero. */
873 if ((digcnt < 4) || ((digcnt > 4) && (*firstChar == '0')))
874 return 1;
875
876 if (isneg)
877 dt->year = - dt->year;
878
879 if (!VALID_YEAR(dt->year))
880 return 2;
881
882 *str = cur;
883 return 0;
884}
885
886/**
887 * PARSE_2_DIGITS:
888 * @num: the integer to fill in
889 * @cur: an #xmlChar *
890 * @invalid: an integer
891 *
892 * Parses a 2-digits integer and updates @num with the value. @cur is
893 * updated to point just after the integer.
894 * In case of error, @invalid is set to %TRUE, values of @num and
895 * @cur are undefined.
896 */
897#define PARSE_2_DIGITS(num, cur, invalid) \
898 if ((cur[0] < '0') || (cur[0] > '9') || \
899 (cur[1] < '0') || (cur[1] > '9')) \
900 invalid = 1; \
901 else \
902 num = (cur[0] - '0') * 10 + (cur[1] - '0'); \
903 cur += 2;
904
905/**
906 * PARSE_FLOAT:
907 * @num: the double to fill in
908 * @cur: an #xmlChar *
909 * @invalid: an integer
910 *
911 * Parses a float and updates @num with the value. @cur is
912 * updated to point just after the float. The float must have a
913 * 2-digits integer part and may or may not have a decimal part.
914 * In case of error, @invalid is set to %TRUE, values of @num and
915 * @cur are undefined.
916 */
917#define PARSE_FLOAT(num, cur, invalid) \
918 PARSE_2_DIGITS(num, cur, invalid); \
919 if (!invalid && (*cur == '.')) { \
920 double mult = 1; \
921 cur++; \
922 if ((*cur < '0') || (*cur > '9')) \
923 invalid = 1; \
924 while ((*cur >= '0') && (*cur <= '9')) { \
925 mult /= 10; \
926 num += (*cur - '0') * mult; \
927 cur++; \
928 } \
929 }
930
931/**
932 * _xmlSchemaParseGMonth:
933 * @dt: pointer to a date structure
934 * @str: pointer to the string to analyze
935 *
936 * Parses a xs:gMonth without time zone and fills in the appropriate
937 * field of the @dt structure. @str is updated to point just after the
938 * xs:gMonth.
939 *
940 * Returns 0 or the error code
941 */
942static int
943_xmlSchemaParseGMonth (xmlSchemaValDatePtr dt, const xmlChar **str) {
944 const xmlChar *cur = *str;
945 int ret = 0;
946
947 PARSE_2_DIGITS(dt->mon, cur, ret);
948 if (ret != 0)
949 return ret;
950
951 if (!VALID_MONTH(dt->mon))
952 return 2;
953
954 *str = cur;
955 return 0;
956}
957
958/**
959 * _xmlSchemaParseGDay:
960 * @dt: pointer to a date structure
961 * @str: pointer to the string to analyze
962 *
963 * Parses a xs:gDay without time zone and fills in the appropriate
964 * field of the @dt structure. @str is updated to point just after the
965 * xs:gDay.
966 *
967 * Returns 0 or the error code
968 */
969static int
970_xmlSchemaParseGDay (xmlSchemaValDatePtr dt, const xmlChar **str) {
971 const xmlChar *cur = *str;
972 int ret = 0;
973
974 PARSE_2_DIGITS(dt->day, cur, ret);
975 if (ret != 0)
976 return ret;
977
978 if (!VALID_DAY(dt->day))
979 return 2;
980
981 *str = cur;
982 return 0;
983}
984
985/**
986 * _xmlSchemaParseTime:
987 * @dt: pointer to a date structure
988 * @str: pointer to the string to analyze
989 *
990 * Parses a xs:time without time zone and fills in the appropriate
991 * fields of the @dt structure. @str is updated to point just after the
992 * xs:time.
993 * In case of error, values of @dt fields are undefined.
994 *
995 * Returns 0 or the error code
996 */
997static int
998_xmlSchemaParseTime (xmlSchemaValDatePtr dt, const xmlChar **str) {
999 const xmlChar *cur = *str;
1000 unsigned int hour = 0; /* use temp var in case str is not xs:time */
1001 int ret = 0;
1002
1003 PARSE_2_DIGITS(hour, cur, ret);
1004 if (ret != 0)
1005 return ret;
1006
1007 if (*cur != ':')
1008 return 1;
1009 cur++;
1010
1011 /* the ':' insures this string is xs:time */
1012 dt->hour = hour;
1013
1014 PARSE_2_DIGITS(dt->min, cur, ret);
1015 if (ret != 0)
1016 return ret;
1017
1018 if (*cur != ':')
1019 return 1;
1020 cur++;
1021
1022 PARSE_FLOAT(dt->sec, cur, ret);
1023 if (ret != 0)
1024 return ret;
1025
1026 if (!VALID_TIME(dt))
1027 return 2;
1028
1029 *str = cur;
1030 return 0;
1031}
1032
1033/**
1034 * _xmlSchemaParseTimeZone:
1035 * @dt: pointer to a date structure
1036 * @str: pointer to the string to analyze
1037 *
1038 * Parses a time zone without time zone and fills in the appropriate
1039 * field of the @dt structure. @str is updated to point just after the
1040 * time zone.
1041 *
1042 * Returns 0 or the error code
1043 */
1044static int
1045_xmlSchemaParseTimeZone (xmlSchemaValDatePtr dt, const xmlChar **str) {
1046 const xmlChar *cur = *str;
1047 int ret = 0;
1048
1049 if (str == NULL)
1050 return -1;
1051
1052 switch (*cur) {
1053 case 0:
1054 dt->tz_flag = 0;
1055 dt->tzo = 0;
1056 break;
1057
1058 case 'Z':
1059 dt->tz_flag = 1;
1060 dt->tzo = 0;
1061 cur++;
1062 break;
1063
1064 case '+':
1065 case '-': {
1066 int isneg = 0, tmp = 0;
1067 isneg = (*cur == '-');
1068
1069 cur++;
1070
1071 PARSE_2_DIGITS(tmp, cur, ret);
1072 if (ret != 0)
1073 return ret;
1074 if (!VALID_HOUR(tmp))
1075 return 2;
1076
1077 if (*cur != ':')
1078 return 1;
1079 cur++;
1080
1081 dt->tzo = tmp * 60;
1082
1083 PARSE_2_DIGITS(tmp, cur, ret);
1084 if (ret != 0)
1085 return ret;
1086 if (!VALID_MIN(tmp))
1087 return 2;
1088
1089 dt->tzo += tmp;
1090 if (isneg)
1091 dt->tzo = - dt->tzo;
1092
1093 if (!VALID_TZO(dt->tzo))
1094 return 2;
1095
Daniel Veillard5a872412002-05-22 06:40:27 +00001096 dt->tz_flag = 1;
Daniel Veillard070803b2002-05-03 07:29:38 +00001097 break;
1098 }
1099 default:
1100 return 1;
1101 }
1102
1103 *str = cur;
1104 return 0;
1105}
1106
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001107/**
1108 * _xmlSchemaBase64Decode:
1109 * @ch: a character
1110 *
1111 * Converts a base64 encoded character to its base 64 value.
1112 *
1113 * Returns 0-63 (value), 64 (pad), or -1 (not recognized)
1114 */
1115static int
1116_xmlSchemaBase64Decode (const xmlChar ch) {
1117 if (('A' <= ch) && (ch <= 'Z')) return ch - 'A';
1118 if (('a' <= ch) && (ch <= 'z')) return ch - 'a' + 26;
1119 if (('0' <= ch) && (ch <= '9')) return ch - '0' + 52;
1120 if ('+' == ch) return 62;
1121 if ('/' == ch) return 63;
1122 if ('=' == ch) return 64;
1123 return -1;
1124}
1125
Daniel Veillard070803b2002-05-03 07:29:38 +00001126/****************************************************************
1127 * *
1128 * XML Schema Dates/Times Datatypes Handling *
1129 * *
1130 ****************************************************************/
1131
1132/**
1133 * PARSE_DIGITS:
1134 * @num: the integer to fill in
1135 * @cur: an #xmlChar *
1136 * @num_type: an integer flag
1137 *
1138 * Parses a digits integer and updates @num with the value. @cur is
1139 * updated to point just after the integer.
1140 * In case of error, @num_type is set to -1, values of @num and
1141 * @cur are undefined.
1142 */
1143#define PARSE_DIGITS(num, cur, num_type) \
1144 if ((*cur < '0') || (*cur > '9')) \
1145 num_type = -1; \
1146 else \
1147 while ((*cur >= '0') && (*cur <= '9')) { \
1148 num = num * 10 + (*cur - '0'); \
1149 cur++; \
1150 }
1151
1152/**
1153 * PARSE_NUM:
1154 * @num: the double to fill in
1155 * @cur: an #xmlChar *
1156 * @num_type: an integer flag
1157 *
1158 * Parses a float or integer and updates @num with the value. @cur is
1159 * updated to point just after the number. If the number is a float,
1160 * then it must have an integer part and a decimal part; @num_type will
1161 * be set to 1. If there is no decimal part, @num_type is set to zero.
1162 * In case of error, @num_type is set to -1, values of @num and
1163 * @cur are undefined.
1164 */
1165#define PARSE_NUM(num, cur, num_type) \
1166 num = 0; \
1167 PARSE_DIGITS(num, cur, num_type); \
1168 if (!num_type && (*cur == '.')) { \
1169 double mult = 1; \
1170 cur++; \
1171 if ((*cur < '0') || (*cur > '9')) \
1172 num_type = -1; \
1173 else \
1174 num_type = 1; \
1175 while ((*cur >= '0') && (*cur <= '9')) { \
1176 mult /= 10; \
1177 num += (*cur - '0') * mult; \
1178 cur++; \
1179 } \
1180 }
1181
1182/**
Daniel Veillard5a872412002-05-22 06:40:27 +00001183 * xmlSchemaValidateDates:
Daniel Veillard455cc072003-03-31 10:13:23 +00001184 * @type: the expected type or XML_SCHEMAS_UNKNOWN
Daniel Veillard070803b2002-05-03 07:29:38 +00001185 * @dateTime: string to analyze
1186 * @val: the return computed value
1187 *
1188 * Check that @dateTime conforms to the lexical space of one of the date types.
1189 * if true a value is computed and returned in @val.
1190 *
1191 * Returns 0 if this validates, a positive error code number otherwise
1192 * and -1 in case of internal or API error.
1193 */
1194static int
Daniel Veillard455cc072003-03-31 10:13:23 +00001195xmlSchemaValidateDates (xmlSchemaValType type,
Daniel Veillard118aed72002-09-24 14:13:13 +00001196 const xmlChar *dateTime, xmlSchemaValPtr *val) {
Daniel Veillard070803b2002-05-03 07:29:38 +00001197 xmlSchemaValPtr dt;
1198 int ret;
1199 const xmlChar *cur = dateTime;
1200
1201#define RETURN_TYPE_IF_VALID(t) \
1202 if (IS_TZO_CHAR(*cur)) { \
1203 ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur); \
1204 if (ret == 0) { \
1205 if (*cur != 0) \
1206 goto error; \
1207 dt->type = t; \
Daniel Veillard455cc072003-03-31 10:13:23 +00001208 goto done; \
Daniel Veillard070803b2002-05-03 07:29:38 +00001209 } \
1210 }
1211
1212 if (dateTime == NULL)
1213 return -1;
1214
1215 if ((*cur != '-') && (*cur < '0') && (*cur > '9'))
1216 return 1;
1217
1218 dt = xmlSchemaNewValue(XML_SCHEMAS_UNKNOWN);
1219 if (dt == NULL)
1220 return -1;
1221
1222 if ((cur[0] == '-') && (cur[1] == '-')) {
1223 /*
1224 * It's an incomplete date (xs:gMonthDay, xs:gMonth or
1225 * xs:gDay)
1226 */
1227 cur += 2;
1228
1229 /* is it an xs:gDay? */
1230 if (*cur == '-') {
Daniel Veillard455cc072003-03-31 10:13:23 +00001231 if (type == XML_SCHEMAS_GMONTH)
1232 goto error;
Daniel Veillard070803b2002-05-03 07:29:38 +00001233 ++cur;
1234 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
1235 if (ret != 0)
1236 goto error;
1237
1238 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GDAY);
1239
1240 goto error;
1241 }
1242
1243 /*
1244 * it should be an xs:gMonthDay or xs:gMonth
1245 */
1246 ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
1247 if (ret != 0)
1248 goto error;
1249
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001250 /*
1251 * a '-' char could indicate this type is xs:gMonthDay or
1252 * a negative time zone offset. Check for xs:gMonthDay first.
1253 * Also the first three char's of a negative tzo (-MM:SS) can
1254 * appear to be a valid day; so even if the day portion
1255 * of the xs:gMonthDay verifies, we must insure it was not
1256 * a tzo.
1257 */
1258 if (*cur == '-') {
1259 const xmlChar *rewnd = cur;
1260 cur++;
Daniel Veillard070803b2002-05-03 07:29:38 +00001261
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001262 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
1263 if ((ret == 0) && ((*cur == 0) || (*cur != ':'))) {
1264
1265 /*
1266 * we can use the VALID_MDAY macro to validate the month
1267 * and day because the leap year test will flag year zero
1268 * as a leap year (even though zero is an invalid year).
1269 */
1270 if (VALID_MDAY((&(dt->value.date)))) {
1271
1272 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTHDAY);
1273
1274 goto error;
1275 }
1276 }
1277
1278 /*
1279 * not xs:gMonthDay so rewind and check if just xs:gMonth
1280 * with an optional time zone.
1281 */
1282 cur = rewnd;
1283 }
1284
1285 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTH);
Daniel Veillard070803b2002-05-03 07:29:38 +00001286
1287 goto error;
1288 }
1289
1290 /*
1291 * It's a right-truncated date or an xs:time.
1292 * Try to parse an xs:time then fallback on right-truncated dates.
1293 */
1294 if ((*cur >= '0') && (*cur <= '9')) {
1295 ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
1296 if (ret == 0) {
1297 /* it's an xs:time */
1298 RETURN_TYPE_IF_VALID(XML_SCHEMAS_TIME);
1299 }
1300 }
1301
1302 /* fallback on date parsing */
1303 cur = dateTime;
1304
1305 ret = _xmlSchemaParseGYear(&(dt->value.date), &cur);
1306 if (ret != 0)
1307 goto error;
1308
1309 /* is it an xs:gYear? */
1310 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEAR);
1311
1312 if (*cur != '-')
1313 goto error;
1314 cur++;
1315
1316 ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
1317 if (ret != 0)
1318 goto error;
1319
1320 /* is it an xs:gYearMonth? */
1321 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEARMONTH);
1322
1323 if (*cur != '-')
1324 goto error;
1325 cur++;
1326
1327 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
1328 if ((ret != 0) || !VALID_DATE((&(dt->value.date))))
1329 goto error;
1330
1331 /* is it an xs:date? */
1332 RETURN_TYPE_IF_VALID(XML_SCHEMAS_DATE);
1333
1334 if (*cur != 'T')
1335 goto error;
1336 cur++;
1337
1338 /* it should be an xs:dateTime */
1339 ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
1340 if (ret != 0)
1341 goto error;
1342
1343 ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur);
1344 if ((ret != 0) || (*cur != 0) || !VALID_DATETIME((&(dt->value.date))))
1345 goto error;
1346
Daniel Veillard455cc072003-03-31 10:13:23 +00001347
Daniel Veillard070803b2002-05-03 07:29:38 +00001348 dt->type = XML_SCHEMAS_DATETIME;
1349
Daniel Veillard455cc072003-03-31 10:13:23 +00001350done:
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001351#if 1
1352 if ((type != XML_SCHEMAS_UNKNOWN) && (type != dt->type))
1353 goto error;
1354#else
1355 /*
1356 * insure the parsed type is equal to or less significant (right
1357 * truncated) than the desired type.
1358 */
1359 if ((type != XML_SCHEMAS_UNKNOWN) && (type != dt->type)) {
1360
1361 /* time only matches time */
1362 if ((type == XML_SCHEMAS_TIME) && (dt->type == XML_SCHEMAS_TIME))
1363 goto error;
1364
1365 if ((type == XML_SCHEMAS_DATETIME) &&
1366 ((dt->type != XML_SCHEMAS_DATE) ||
1367 (dt->type != XML_SCHEMAS_GYEARMONTH) ||
1368 (dt->type != XML_SCHEMAS_GYEAR)))
1369 goto error;
1370
1371 if ((type == XML_SCHEMAS_DATE) &&
1372 ((dt->type != XML_SCHEMAS_GYEAR) ||
1373 (dt->type != XML_SCHEMAS_GYEARMONTH)))
1374 goto error;
1375
1376 if ((type == XML_SCHEMAS_GYEARMONTH) && (dt->type != XML_SCHEMAS_GYEAR))
1377 goto error;
1378
1379 if ((type == XML_SCHEMAS_GMONTHDAY) && (dt->type != XML_SCHEMAS_GMONTH))
1380 goto error;
1381 }
Daniel Veillard455cc072003-03-31 10:13:23 +00001382#endif
1383
Daniel Veillard070803b2002-05-03 07:29:38 +00001384 if (val != NULL)
1385 *val = dt;
Daniel Veillard80b19092003-03-28 13:29:53 +00001386 else
1387 xmlSchemaFreeValue(dt);
Daniel Veillard070803b2002-05-03 07:29:38 +00001388
1389 return 0;
1390
1391error:
1392 if (dt != NULL)
1393 xmlSchemaFreeValue(dt);
1394 return 1;
1395}
1396
1397/**
Daniel Veillard5a872412002-05-22 06:40:27 +00001398 * xmlSchemaValidateDuration:
Daniel Veillard070803b2002-05-03 07:29:38 +00001399 * @type: the predefined type
1400 * @duration: string to analyze
1401 * @val: the return computed value
1402 *
1403 * Check that @duration conforms to the lexical space of the duration type.
1404 * if true a value is computed and returned in @val.
1405 *
1406 * Returns 0 if this validates, a positive error code number otherwise
1407 * and -1 in case of internal or API error.
1408 */
1409static int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00001410xmlSchemaValidateDuration (xmlSchemaTypePtr type ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +00001411 const xmlChar *duration, xmlSchemaValPtr *val) {
Daniel Veillard070803b2002-05-03 07:29:38 +00001412 const xmlChar *cur = duration;
1413 xmlSchemaValPtr dur;
1414 int isneg = 0;
1415 unsigned int seq = 0;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001416 double num;
1417 int num_type = 0; /* -1 = invalid, 0 = int, 1 = floating */
1418 const xmlChar desig[] = {'Y', 'M', 'D', 'H', 'M', 'S'};
1419 const double multi[] = { 0.0, 0.0, 86400.0, 3600.0, 60.0, 1.0, 0.0};
Daniel Veillard070803b2002-05-03 07:29:38 +00001420
1421 if (duration == NULL)
1422 return -1;
1423
1424 if (*cur == '-') {
1425 isneg = 1;
1426 cur++;
1427 }
1428
1429 /* duration must start with 'P' (after sign) */
1430 if (*cur++ != 'P')
1431 return 1;
1432
Daniel Veillard80b19092003-03-28 13:29:53 +00001433 if (*cur == 0)
1434 return 1;
1435
Daniel Veillard070803b2002-05-03 07:29:38 +00001436 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
1437 if (dur == NULL)
1438 return -1;
1439
1440 while (*cur != 0) {
Daniel Veillard070803b2002-05-03 07:29:38 +00001441
1442 /* input string should be empty or invalid date/time item */
1443 if (seq >= sizeof(desig))
1444 goto error;
1445
1446 /* T designator must be present for time items */
1447 if (*cur == 'T') {
1448 if (seq <= 3) {
1449 seq = 3;
1450 cur++;
1451 } else
1452 return 1;
1453 } else if (seq == 3)
1454 goto error;
1455
1456 /* parse the number portion of the item */
1457 PARSE_NUM(num, cur, num_type);
1458
1459 if ((num_type == -1) || (*cur == 0))
1460 goto error;
1461
1462 /* update duration based on item type */
1463 while (seq < sizeof(desig)) {
1464 if (*cur == desig[seq]) {
1465
1466 /* verify numeric type; only seconds can be float */
1467 if ((num_type != 0) && (seq < (sizeof(desig)-1)))
1468 goto error;
1469
1470 switch (seq) {
1471 case 0:
1472 dur->value.dur.mon = (long)num * 12;
1473 break;
1474 case 1:
1475 dur->value.dur.mon += (long)num;
1476 break;
1477 default:
1478 /* convert to seconds using multiplier */
1479 dur->value.dur.sec += num * multi[seq];
1480 seq++;
1481 break;
1482 }
1483
1484 break; /* exit loop */
1485 }
1486 /* no date designators found? */
1487 if (++seq == 3)
1488 goto error;
1489 }
1490 cur++;
1491 }
1492
1493 if (isneg) {
1494 dur->value.dur.mon = -dur->value.dur.mon;
1495 dur->value.dur.day = -dur->value.dur.day;
1496 dur->value.dur.sec = -dur->value.dur.sec;
1497 }
1498
1499 if (val != NULL)
1500 *val = dur;
Daniel Veillard80b19092003-03-28 13:29:53 +00001501 else
1502 xmlSchemaFreeValue(dur);
Daniel Veillard070803b2002-05-03 07:29:38 +00001503
1504 return 0;
1505
1506error:
1507 if (dur != NULL)
1508 xmlSchemaFreeValue(dur);
1509 return 1;
1510}
1511
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001512/**
1513 * xmlSchemaStrip:
1514 * @value: a value
1515 *
1516 * Removes the leading and ending spaces of a string
1517 *
1518 * Returns the new string or NULL if no change was required.
1519 */
1520static xmlChar *
1521xmlSchemaStrip(const xmlChar *value) {
1522 const xmlChar *start = value, *end, *f;
1523
1524 if (value == NULL) return(NULL);
William M. Brack76e95df2003-10-18 16:20:14 +00001525 while ((*start != 0) && (IS_BLANK_CH(*start))) start++;
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001526 end = start;
1527 while (*end != 0) end++;
1528 f = end;
1529 end--;
William M. Brack76e95df2003-10-18 16:20:14 +00001530 while ((end > start) && (IS_BLANK_CH(*end))) end--;
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001531 end++;
1532 if ((start == value) && (f == end)) return(NULL);
1533 return(xmlStrndup(start, end - start));
1534}
Daniel Veillard96a4b252003-02-06 08:22:32 +00001535
1536/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001537 * xmlSchemaCollapseString:
1538 * @value: a value
1539 *
1540 * Removes and normalize white spaces in the string
1541 *
1542 * Returns the new string or NULL if no change was required.
1543 */
Daniel Veillard01fa6152004-06-29 17:04:39 +00001544xmlChar *
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001545xmlSchemaCollapseString(const xmlChar *value) {
1546 const xmlChar *start = value, *end, *f;
1547 xmlChar *g;
1548 int col = 0;
1549
1550 if (value == NULL) return(NULL);
William M. Brack76e95df2003-10-18 16:20:14 +00001551 while ((*start != 0) && (IS_BLANK_CH(*start))) start++;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001552 end = start;
1553 while (*end != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00001554 if ((*end == ' ') && (IS_BLANK_CH(end[1]))) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001555 col = end - start;
1556 break;
1557 } else if ((*end == 0xa) || (*end == 0x9) || (*end == 0xd)) {
1558 col = end - start;
1559 break;
1560 }
1561 end++;
1562 }
1563 if (col == 0) {
1564 f = end;
1565 end--;
William M. Brack76e95df2003-10-18 16:20:14 +00001566 while ((end > start) && (IS_BLANK_CH(*end))) end--;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001567 end++;
1568 if ((start == value) && (f == end)) return(NULL);
1569 return(xmlStrndup(start, end - start));
1570 }
1571 start = xmlStrdup(start);
1572 if (start == NULL) return(NULL);
1573 g = (xmlChar *) (start + col);
1574 end = g;
1575 while (*end != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00001576 if (IS_BLANK_CH(*end)) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001577 end++;
William M. Brack76e95df2003-10-18 16:20:14 +00001578 while (IS_BLANK_CH(*end)) end++;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001579 if (*end != 0)
1580 *g++ = ' ';
1581 } else
1582 *g++ = *end++;
1583 }
1584 *g = 0;
1585 return((xmlChar *) start);
1586}
1587
1588/**
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001589 * xmlSchemaValAtomicListNode:
1590 * @type: the predefined atomic type for a token in the list
1591 * @value: the list value to check
1592 * @ret: the return computed value
1593 * @node: the node containing the value
1594 *
1595 * Check that a value conforms to the lexical space of the predefined
1596 * list type. if true a value is computed and returned in @ret.
1597 *
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001598 * Returns the number of items if this validates, a negative error code
1599 * number otherwise
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001600 */
1601static int
1602xmlSchemaValAtomicListNode(xmlSchemaTypePtr type, const xmlChar *value,
1603 xmlSchemaValPtr *ret, xmlNodePtr node) {
1604 xmlChar *val, *cur, *endval;
1605 int nb_values = 0;
Daniel Veillard580ced82003-03-21 21:22:48 +00001606 int tmp = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001607
1608 if (value == NULL) {
1609 return(-1);
1610 }
1611 val = xmlStrdup(value);
1612 if (val == NULL) {
1613 return(-1);
1614 }
1615 cur = val;
1616 /*
1617 * Split the list
1618 */
William M. Brack76e95df2003-10-18 16:20:14 +00001619 while (IS_BLANK_CH(*cur)) *cur++ = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001620 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00001621 if (IS_BLANK_CH(*cur)) {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001622 *cur = 0;
1623 cur++;
William M. Brack76e95df2003-10-18 16:20:14 +00001624 while (IS_BLANK_CH(*cur)) *cur++ = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001625 } else {
1626 nb_values++;
1627 cur++;
William M. Brack76e95df2003-10-18 16:20:14 +00001628 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001629 }
1630 }
1631 if (nb_values == 0) {
1632 if (ret != NULL) {
1633 TODO
1634 }
1635 xmlFree(val);
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001636 return(nb_values);
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001637 }
1638 endval = cur;
1639 cur = val;
1640 while ((*cur == 0) && (cur != endval)) cur++;
1641 while (cur != endval) {
1642 tmp = xmlSchemaValPredefTypeNode(type, cur, NULL, node);
1643 if (tmp != 0)
1644 break;
1645 while (*cur != 0) cur++;
1646 while ((*cur == 0) && (cur != endval)) cur++;
1647 }
1648 xmlFree(val);
1649 if (ret != NULL) {
1650 TODO
1651 }
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001652 if (tmp == 0)
1653 return(nb_values);
1654 return(-1);
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001655}
1656
1657/**
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001658 * xmlSchemaParseUInt:
1659 * @str: pointer to the string R/W
1660 * @llo: pointer to the low result
1661 * @lmi: pointer to the mid result
1662 * @lhi: pointer to the high result
1663 *
1664 * Parse an unsigned long into 3 fields.
1665 *
1666 * Returns the number of chars parsed or -1 if overflow of the capacity
1667 */
1668static int
1669xmlSchemaParseUInt(const xmlChar **str, unsigned long *llo,
1670 unsigned long *lmi, unsigned long *lhi) {
1671 unsigned long lo = 0, mi = 0, hi = 0;
1672 const xmlChar *tmp, *cur = *str;
1673 int ret = 0, i = 0;
1674
1675 while (*cur == '0') {
1676 ret++;
1677 cur++;
1678 }
1679 tmp = cur;
1680 while ((*tmp != 0) && (*tmp >= '0') && (*tmp <= '9')) {
1681 i++;tmp++;ret++;
1682 }
1683 if (i > 24) {
1684 *str = tmp;
1685 return(-1);
1686 }
1687 while (i > 16) {
1688 hi = hi * 10 + (*cur++ - '0');
1689 i--;
1690 }
1691 while (i > 8) {
1692 mi = mi * 10 + (*cur++ - '0');
1693 i--;
1694 }
1695 while (i > 0) {
1696 lo = lo * 10 + (*cur++ - '0');
1697 i--;
1698 }
1699
1700 *str = cur;
1701 *llo = lo;
1702 *lmi = mi;
1703 *lhi = hi;
1704 return(ret);
1705}
1706
1707/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001708 * xmlSchemaValAtomicType:
1709 * @type: the predefined type
1710 * @value: the value to check
1711 * @val: the return computed value
1712 * @node: the node containing the value
1713 * flags: flags to control the vlidation
1714 *
1715 * Check that a value conforms to the lexical space of the atomic type.
1716 * if true a value is computed and returned in @val.
Daniel Veillard01fa6152004-06-29 17:04:39 +00001717 * This checks the value space for list types as well (IDREFS, NMTOKENS).
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001718 *
1719 * Returns 0 if this validates, a positive error code number otherwise
1720 * and -1 in case of internal or API error.
1721 */
1722static int
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001723xmlSchemaValAtomicType(xmlSchemaTypePtr type, const xmlChar * value,
1724 xmlSchemaValPtr * val, xmlNodePtr node, int flags)
1725{
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001726 xmlSchemaValPtr v;
1727 xmlChar *norm = NULL;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001728 int ret = 0;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001729
1730 if (xmlSchemaTypesInitialized == 0)
Daniel Veillard01fa6152004-06-29 17:04:39 +00001731 xmlSchemaInitTypes();
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001732 if (type == NULL)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001733 return (-1);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001734
1735 if (val != NULL)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001736 *val = NULL;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001737 if ((flags == 0) && (value != NULL)) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00001738 if ((type->builtInType != XML_SCHEMAS_STRING) &&
1739 (type->builtInType != XML_SCHEMAS_NORMSTRING)) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001740 norm = xmlSchemaCollapseString(value);
1741 if (norm != NULL)
1742 value = norm;
1743 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001744 }
1745
Daniel Veillard01fa6152004-06-29 17:04:39 +00001746 switch (type->builtInType) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001747 case XML_SCHEMAS_UNKNOWN:
Daniel Veillardc0826a72004-08-10 14:17:33 +00001748 if ((type == xmlSchemaTypeAnySimpleTypeDef) ||
1749 (type == xmlSchemaTypeAnyTypeDef))
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001750 goto return0;
1751 goto error;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001752 case XML_SCHEMAS_STRING:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001753 goto return0;
Daniel Veillard1516d5b2004-01-22 07:27:45 +00001754 case XML_SCHEMAS_NORMSTRING:{
1755 const xmlChar *cur = value;
1756
1757 while (*cur != 0) {
1758 if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) {
1759 goto return1;
1760 } else {
1761 cur++;
1762 }
1763 }
1764 if (val != NULL) {
1765 v = xmlSchemaNewValue(XML_SCHEMAS_NORMSTRING);
1766 if (v != NULL) {
1767 v->value.str = xmlStrdup(value);
1768 *val = v;
1769 } else {
1770 goto error;
1771 }
1772 }
1773 goto return0;
1774 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001775 case XML_SCHEMAS_DECIMAL:{
1776 const xmlChar *cur = value, *tmp;
1777 unsigned int frac = 0, len, neg = 0;
1778 unsigned long base = 0;
1779
1780 if (cur == NULL)
1781 goto return1;
1782 if (*cur == '+')
1783 cur++;
1784 else if (*cur == '-') {
1785 neg = 1;
1786 cur++;
1787 }
1788 tmp = cur;
1789 while ((*cur >= '0') && (*cur <= '9')) {
1790 base = base * 10 + (*cur - '0');
1791 cur++;
1792 }
1793 len = cur - tmp;
1794 if (*cur == '.') {
1795 cur++;
1796 tmp = cur;
1797 while ((*cur >= '0') && (*cur <= '9')) {
1798 base = base * 10 + (*cur - '0');
1799 cur++;
1800 }
1801 frac = cur - tmp;
1802 }
1803 if (*cur != 0)
1804 goto return1;
1805 if (val != NULL) {
1806 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
1807 if (v != NULL) {
1808 v->value.decimal.lo = base;
1809 v->value.decimal.sign = neg;
1810 v->value.decimal.frac = frac;
1811 v->value.decimal.total = frac + len;
1812 *val = v;
1813 }
1814 }
1815 goto return0;
1816 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001817 case XML_SCHEMAS_TIME:
1818 case XML_SCHEMAS_GDAY:
1819 case XML_SCHEMAS_GMONTH:
1820 case XML_SCHEMAS_GMONTHDAY:
1821 case XML_SCHEMAS_GYEAR:
1822 case XML_SCHEMAS_GYEARMONTH:
1823 case XML_SCHEMAS_DATE:
1824 case XML_SCHEMAS_DATETIME:
Daniel Veillard01fa6152004-06-29 17:04:39 +00001825 ret = xmlSchemaValidateDates(type->builtInType, value, val);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001826 break;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001827 case XML_SCHEMAS_DURATION:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001828 ret = xmlSchemaValidateDuration(type, value, val);
1829 break;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001830 case XML_SCHEMAS_FLOAT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001831 case XML_SCHEMAS_DOUBLE:{
1832 const xmlChar *cur = value;
1833 int neg = 0;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001834
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001835 if (cur == NULL)
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00001836 goto return1;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001837 if ((cur[0] == 'N') && (cur[1] == 'a') && (cur[2] == 'N')) {
1838 cur += 3;
1839 if (*cur != 0)
1840 goto return1;
1841 if (val != NULL) {
1842 if (type == xmlSchemaTypeFloatDef) {
1843 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1844 if (v != NULL) {
1845 v->value.f = (float) xmlXPathNAN;
1846 } else {
1847 xmlSchemaFreeValue(v);
1848 goto error;
1849 }
1850 } else {
1851 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1852 if (v != NULL) {
1853 v->value.d = xmlXPathNAN;
1854 } else {
1855 xmlSchemaFreeValue(v);
1856 goto error;
1857 }
1858 }
1859 *val = v;
1860 }
1861 goto return0;
1862 }
1863 if (*cur == '-') {
1864 neg = 1;
1865 cur++;
1866 }
1867 if ((cur[0] == 'I') && (cur[1] == 'N') && (cur[2] == 'F')) {
1868 cur += 3;
1869 if (*cur != 0)
1870 goto return1;
1871 if (val != NULL) {
1872 if (type == xmlSchemaTypeFloatDef) {
1873 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1874 if (v != NULL) {
1875 if (neg)
1876 v->value.f = (float) xmlXPathNINF;
1877 else
1878 v->value.f = (float) xmlXPathPINF;
1879 } else {
1880 xmlSchemaFreeValue(v);
1881 goto error;
1882 }
1883 } else {
1884 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1885 if (v != NULL) {
1886 if (neg)
1887 v->value.d = xmlXPathNINF;
1888 else
1889 v->value.d = xmlXPathPINF;
1890 } else {
1891 xmlSchemaFreeValue(v);
1892 goto error;
1893 }
1894 }
1895 *val = v;
1896 }
1897 goto return0;
1898 }
1899 if ((neg == 0) && (*cur == '+'))
1900 cur++;
1901 if ((cur[0] == 0) || (cur[0] == '+') || (cur[0] == '-'))
1902 goto return1;
1903 while ((*cur >= '0') && (*cur <= '9')) {
1904 cur++;
1905 }
1906 if (*cur == '.') {
1907 cur++;
1908 while ((*cur >= '0') && (*cur <= '9'))
1909 cur++;
1910 }
1911 if ((*cur == 'e') || (*cur == 'E')) {
1912 cur++;
1913 if ((*cur == '-') || (*cur == '+'))
1914 cur++;
1915 while ((*cur >= '0') && (*cur <= '9'))
1916 cur++;
1917 }
1918 if (*cur != 0)
1919 goto return1;
1920 if (val != NULL) {
1921 if (type == xmlSchemaTypeFloatDef) {
1922 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1923 if (v != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001924 if (sscanf((const char *) value, "%f",
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001925 &(v->value.f)) == 1) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00001926 *val = v;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001927 } else {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001928 xmlSchemaFreeValue(v);
1929 goto return1;
1930 }
1931 } else {
1932 goto error;
1933 }
1934 } else {
1935 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1936 if (v != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001937 if (sscanf((const char *) value, "%lf",
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001938 &(v->value.d)) == 1) {
1939 *val = v;
1940 } else {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001941 xmlSchemaFreeValue(v);
1942 goto return1;
1943 }
1944 } else {
1945 goto error;
1946 }
1947 }
1948 }
1949 goto return0;
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00001950 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001951 case XML_SCHEMAS_BOOLEAN:{
1952 const xmlChar *cur = value;
1953
1954 if ((cur[0] == '0') && (cur[1] == 0))
1955 ret = 0;
1956 else if ((cur[0] == '1') && (cur[1] == 0))
1957 ret = 1;
1958 else if ((cur[0] == 't') && (cur[1] == 'r')
1959 && (cur[2] == 'u') && (cur[3] == 'e')
1960 && (cur[4] == 0))
1961 ret = 1;
1962 else if ((cur[0] == 'f') && (cur[1] == 'a')
1963 && (cur[2] == 'l') && (cur[3] == 's')
1964 && (cur[4] == 'e') && (cur[5] == 0))
1965 ret = 0;
1966 else
1967 goto return1;
1968 if (val != NULL) {
1969 v = xmlSchemaNewValue(XML_SCHEMAS_BOOLEAN);
1970 if (v != NULL) {
1971 v->value.b = ret;
1972 *val = v;
1973 } else {
1974 goto error;
1975 }
1976 }
1977 goto return0;
1978 }
1979 case XML_SCHEMAS_TOKEN:{
1980 const xmlChar *cur = value;
1981
William M. Brack76e95df2003-10-18 16:20:14 +00001982 if (IS_BLANK_CH(*cur))
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001983 goto return1;
1984
1985 while (*cur != 0) {
1986 if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) {
1987 goto return1;
1988 } else if (*cur == ' ') {
1989 cur++;
1990 if (*cur == 0)
1991 goto return1;
1992 if (*cur == ' ')
1993 goto return1;
1994 } else {
1995 cur++;
1996 }
1997 }
1998 if (val != NULL) {
1999 v = xmlSchemaNewValue(XML_SCHEMAS_TOKEN);
2000 if (v != NULL) {
2001 v->value.str = xmlStrdup(value);
2002 *val = v;
2003 } else {
2004 goto error;
2005 }
2006 }
2007 goto return0;
2008 }
2009 case XML_SCHEMAS_LANGUAGE:
2010 if (xmlCheckLanguageID(value) == 1) {
2011 if (val != NULL) {
2012 v = xmlSchemaNewValue(XML_SCHEMAS_LANGUAGE);
2013 if (v != NULL) {
2014 v->value.str = xmlStrdup(value);
2015 *val = v;
2016 } else {
2017 goto error;
2018 }
2019 }
2020 goto return0;
2021 }
2022 goto return1;
2023 case XML_SCHEMAS_NMTOKEN:
2024 if (xmlValidateNMToken(value, 1) == 0) {
2025 if (val != NULL) {
2026 v = xmlSchemaNewValue(XML_SCHEMAS_NMTOKEN);
2027 if (v != NULL) {
2028 v->value.str = xmlStrdup(value);
2029 *val = v;
2030 } else {
2031 goto error;
2032 }
2033 }
2034 goto return0;
2035 }
2036 goto return1;
2037 case XML_SCHEMAS_NMTOKENS:
2038 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeNmtokenDef,
2039 value, val, node);
2040 if (ret > 0)
2041 ret = 0;
2042 else
2043 ret = 1;
2044 goto done;
2045 case XML_SCHEMAS_NAME:
2046 ret = xmlValidateName(value, 1);
2047 if ((ret == 0) && (val != NULL)) {
2048 TODO;
2049 }
2050 goto done;
2051 case XML_SCHEMAS_QNAME:{
2052 xmlChar *uri = NULL;
2053 xmlChar *local = NULL;
2054
2055 ret = xmlValidateQName(value, 1);
2056 if ((ret == 0) && (node != NULL)) {
2057 xmlChar *prefix;
2058
2059 local = xmlSplitQName2(value, &prefix);
2060 if (prefix != NULL) {
2061 xmlNsPtr ns;
2062
2063 ns = xmlSearchNs(node->doc, node, prefix);
2064 if (ns == NULL)
2065 ret = 1;
2066 else if (val != NULL)
2067 uri = xmlStrdup(ns->href);
2068 }
2069 if ((local != NULL) && ((val == NULL) || (ret != 0)))
2070 xmlFree(local);
2071 if (prefix != NULL)
2072 xmlFree(prefix);
2073 }
2074 if ((ret == 0) && (val != NULL)) {
2075 v = xmlSchemaNewValue(XML_SCHEMAS_QNAME);
2076 if (v != NULL) {
2077 if (local != NULL)
2078 v->value.qname.name = local;
2079 else
2080 v->value.qname.name = xmlStrdup(value);
2081 if (uri != NULL)
2082 v->value.qname.uri = uri;
2083
2084 *val = v;
2085 } else {
2086 if (local != NULL)
2087 xmlFree(local);
2088 if (uri != NULL)
2089 xmlFree(uri);
2090 goto error;
2091 }
2092 }
2093 goto done;
2094 }
2095 case XML_SCHEMAS_NCNAME:
2096 ret = xmlValidateNCName(value, 1);
2097 if ((ret == 0) && (val != NULL)) {
2098 v = xmlSchemaNewValue(XML_SCHEMAS_NCNAME);
2099 if (v != NULL) {
2100 v->value.str = xmlStrdup(value);
2101 *val = v;
2102 } else {
2103 goto error;
2104 }
2105 }
2106 goto done;
2107 case XML_SCHEMAS_ID:
2108 ret = xmlValidateNCName(value, 1);
2109 if ((ret == 0) && (val != NULL)) {
2110 v = xmlSchemaNewValue(XML_SCHEMAS_ID);
2111 if (v != NULL) {
2112 v->value.str = xmlStrdup(value);
2113 *val = v;
2114 } else {
2115 goto error;
2116 }
2117 }
2118 if ((ret == 0) && (node != NULL) &&
2119 (node->type == XML_ATTRIBUTE_NODE)) {
2120 xmlAttrPtr attr = (xmlAttrPtr) node;
2121
2122 /*
2123 * NOTE: the IDness might have already be declared in the DTD
2124 */
2125 if (attr->atype != XML_ATTRIBUTE_ID) {
2126 xmlIDPtr res;
2127 xmlChar *strip;
2128
2129 strip = xmlSchemaStrip(value);
2130 if (strip != NULL) {
2131 res = xmlAddID(NULL, node->doc, strip, attr);
2132 xmlFree(strip);
2133 } else
2134 res = xmlAddID(NULL, node->doc, value, attr);
2135 if (res == NULL) {
2136 ret = 2;
2137 } else {
2138 attr->atype = XML_ATTRIBUTE_ID;
2139 }
2140 }
2141 }
2142 goto done;
2143 case XML_SCHEMAS_IDREF:
2144 ret = xmlValidateNCName(value, 1);
2145 if ((ret == 0) && (val != NULL)) {
2146 TODO;
2147 }
2148 if ((ret == 0) && (node != NULL) &&
2149 (node->type == XML_ATTRIBUTE_NODE)) {
2150 xmlAttrPtr attr = (xmlAttrPtr) node;
2151 xmlChar *strip;
2152
2153 strip = xmlSchemaStrip(value);
2154 if (strip != NULL) {
2155 xmlAddRef(NULL, node->doc, strip, attr);
2156 xmlFree(strip);
2157 } else
2158 xmlAddRef(NULL, node->doc, value, attr);
2159 attr->atype = XML_ATTRIBUTE_IDREF;
2160 }
2161 goto done;
2162 case XML_SCHEMAS_IDREFS:
2163 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeIdrefDef,
2164 value, val, node);
2165 if (ret < 0)
2166 ret = 2;
2167 else
2168 ret = 0;
2169 if ((ret == 0) && (node != NULL) &&
2170 (node->type == XML_ATTRIBUTE_NODE)) {
2171 xmlAttrPtr attr = (xmlAttrPtr) node;
2172
2173 attr->atype = XML_ATTRIBUTE_IDREFS;
2174 }
2175 goto done;
2176 case XML_SCHEMAS_ENTITY:{
2177 xmlChar *strip;
2178
2179 ret = xmlValidateNCName(value, 1);
2180 if ((node == NULL) || (node->doc == NULL))
2181 ret = 3;
2182 if (ret == 0) {
2183 xmlEntityPtr ent;
2184
2185 strip = xmlSchemaStrip(value);
2186 if (strip != NULL) {
2187 ent = xmlGetDocEntity(node->doc, strip);
2188 xmlFree(strip);
2189 } else {
2190 ent = xmlGetDocEntity(node->doc, value);
2191 }
2192 if ((ent == NULL) ||
2193 (ent->etype !=
2194 XML_EXTERNAL_GENERAL_UNPARSED_ENTITY))
2195 ret = 4;
2196 }
2197 if ((ret == 0) && (val != NULL)) {
2198 TODO;
2199 }
2200 if ((ret == 0) && (node != NULL) &&
2201 (node->type == XML_ATTRIBUTE_NODE)) {
2202 xmlAttrPtr attr = (xmlAttrPtr) node;
2203
2204 attr->atype = XML_ATTRIBUTE_ENTITY;
2205 }
2206 goto done;
2207 }
2208 case XML_SCHEMAS_ENTITIES:
2209 if ((node == NULL) || (node->doc == NULL))
2210 goto return3;
2211 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeEntityDef,
2212 value, val, node);
2213 if (ret <= 0)
2214 ret = 1;
2215 else
2216 ret = 0;
2217 if ((ret == 0) && (node != NULL) &&
2218 (node->type == XML_ATTRIBUTE_NODE)) {
2219 xmlAttrPtr attr = (xmlAttrPtr) node;
2220
2221 attr->atype = XML_ATTRIBUTE_ENTITIES;
2222 }
2223 goto done;
2224 case XML_SCHEMAS_NOTATION:{
2225 xmlChar *uri = NULL;
2226 xmlChar *local = NULL;
2227
2228 ret = xmlValidateQName(value, 1);
2229 if ((ret == 0) && (node != NULL)) {
2230 xmlChar *prefix;
2231
2232 local = xmlSplitQName2(value, &prefix);
2233 if (prefix != NULL) {
2234 xmlNsPtr ns;
2235
2236 ns = xmlSearchNs(node->doc, node, prefix);
2237 if (ns == NULL)
2238 ret = 1;
2239 else if (val != NULL)
2240 uri = xmlStrdup(ns->href);
2241 }
2242 if ((local != NULL) && ((val == NULL) || (ret != 0)))
2243 xmlFree(local);
2244 if (prefix != NULL)
2245 xmlFree(prefix);
2246 }
2247 if ((node == NULL) || (node->doc == NULL))
2248 ret = 3;
2249 if (ret == 0) {
2250 ret = xmlValidateNotationUse(NULL, node->doc, value);
2251 if (ret == 1)
2252 ret = 0;
2253 else
2254 ret = 1;
2255 }
2256 if ((ret == 0) && (val != NULL)) {
2257 v = xmlSchemaNewValue(XML_SCHEMAS_NOTATION);
2258 if (v != NULL) {
2259 if (local != NULL)
2260 v->value.qname.name = local;
2261 else
2262 v->value.qname.name = xmlStrdup(value);
2263 if (uri != NULL)
2264 v->value.qname.uri = uri;
2265
2266 *val = v;
2267 } else {
2268 if (local != NULL)
2269 xmlFree(local);
2270 if (uri != NULL)
2271 xmlFree(uri);
2272 goto error;
2273 }
2274 }
2275 goto done;
2276 }
2277 case XML_SCHEMAS_ANYURI:{
Daniel Veillard11c466a2004-03-14 12:20:15 +00002278 if (*value != 0) {
2279 xmlURIPtr uri = xmlParseURI((const char *) value);
2280 if (uri == NULL)
2281 goto return1;
2282 xmlFreeURI(uri);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002283 }
Daniel Veillard11c466a2004-03-14 12:20:15 +00002284
2285 if (val != NULL) {
2286 v = xmlSchemaNewValue(XML_SCHEMAS_ANYURI);
2287 if (v == NULL)
2288 goto error;
2289 v->value.str = xmlStrdup(value);
2290 *val = v;
2291 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002292 goto return0;
2293 }
2294 case XML_SCHEMAS_HEXBINARY:{
2295 const xmlChar *cur = value;
2296 xmlChar *base;
2297 int total, i = 0;
2298
2299 if (cur == NULL)
2300 goto return1;
2301
2302 while (((*cur >= '0') && (*cur <= '9')) ||
2303 ((*cur >= 'A') && (*cur <= 'F')) ||
2304 ((*cur >= 'a') && (*cur <= 'f'))) {
2305 i++;
2306 cur++;
2307 }
2308
2309 if (*cur != 0)
2310 goto return1;
2311 if ((i % 2) != 0)
2312 goto return1;
2313
2314 if (val != NULL) {
2315
2316 v = xmlSchemaNewValue(XML_SCHEMAS_HEXBINARY);
2317 if (v == NULL)
2318 goto error;
2319
2320 cur = xmlStrdup(value);
2321 if (cur == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002322 xmlSchemaTypeErrMemory(node, "allocating hexbin data");
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002323 xmlFree(v);
2324 goto return1;
2325 }
2326
2327 total = i / 2; /* number of octets */
2328
2329 base = (xmlChar *) cur;
2330 while (i-- > 0) {
2331 if (*base >= 'a')
2332 *base = *base - ('a' - 'A');
2333 base++;
2334 }
2335
2336 v->value.hex.str = (xmlChar *) cur;
2337 v->value.hex.total = total;
2338 *val = v;
2339 }
2340 goto return0;
2341 }
2342 case XML_SCHEMAS_BASE64BINARY:{
2343 /* ISSUE:
2344 *
2345 * Ignore all stray characters? (yes, currently)
2346 * Worry about long lines? (no, currently)
2347 *
2348 * rfc2045.txt:
2349 *
2350 * "The encoded output stream must be represented in lines of
2351 * no more than 76 characters each. All line breaks or other
2352 * characters not found in Table 1 must be ignored by decoding
2353 * software. In base64 data, characters other than those in
2354 * Table 1, line breaks, and other white space probably
2355 * indicate a transmission error, about which a warning
2356 * message or even a message rejection might be appropriate
2357 * under some circumstances." */
2358 const xmlChar *cur = value;
2359 xmlChar *base;
2360 int total, i = 0, pad = 0;
2361
2362 if (cur == NULL)
2363 goto return1;
2364
2365 for (; *cur; ++cur) {
2366 int decc;
2367
2368 decc = _xmlSchemaBase64Decode(*cur);
2369 if (decc < 0) ;
2370 else if (decc < 64)
2371 i++;
2372 else
2373 break;
2374 }
2375 for (; *cur; ++cur) {
2376 int decc;
2377
2378 decc = _xmlSchemaBase64Decode(*cur);
2379 if (decc < 0) ;
2380 else if (decc < 64)
2381 goto return1;
2382 if (decc == 64)
2383 pad++;
2384 }
2385
2386 /* rfc2045.txt: "Special processing is performed if fewer than
2387 * 24 bits are available at the end of the data being encoded.
2388 * A full encoding quantum is always completed at the end of a
2389 * body. When fewer than 24 input bits are available in an
2390 * input group, zero bits are added (on the right) to form an
2391 * integral number of 6-bit groups. Padding at the end of the
2392 * data is performed using the "=" character. Since all
2393 * base64 input is an integral number of octets, only the
2394 * following cases can arise: (1) the final quantum of
2395 * encoding input is an integral multiple of 24 bits; here,
2396 * the final unit of encoded output will be an integral
2397 * multiple ofindent: Standard input:701: Warning:old style
2398 * assignment ambiguity in "=*". Assuming "= *" 4 characters
2399 * with no "=" padding, (2) the final
2400 * quantum of encoding input is exactly 8 bits; here, the
2401 * final unit of encoded output will be two characters
2402 * followed by two "=" padding characters, or (3) the final
2403 * quantum of encoding input is exactly 16 bits; here, the
2404 * final unit of encoded output will be three characters
2405 * followed by one "=" padding character." */
2406
2407 total = 3 * (i / 4);
2408 if (pad == 0) {
2409 if (i % 4 != 0)
2410 goto return1;
2411 } else if (pad == 1) {
2412 int decc;
2413
2414 if (i % 4 != 3)
2415 goto return1;
2416 for (decc = _xmlSchemaBase64Decode(*cur);
2417 (decc < 0) || (decc > 63);
2418 decc = _xmlSchemaBase64Decode(*cur))
2419 --cur;
2420 /* 16bits in 24bits means 2 pad bits: nnnnnn nnmmmm mmmm00*/
2421 /* 00111100 -> 0x3c */
2422 if (decc & ~0x3c)
2423 goto return1;
2424 total += 2;
2425 } else if (pad == 2) {
2426 int decc;
2427
2428 if (i % 4 != 2)
2429 goto return1;
2430 for (decc = _xmlSchemaBase64Decode(*cur);
2431 (decc < 0) || (decc > 63);
2432 decc = _xmlSchemaBase64Decode(*cur))
2433 --cur;
2434 /* 8bits in 12bits means 4 pad bits: nnnnnn nn0000 */
2435 /* 00110000 -> 0x30 */
2436 if (decc & ~0x30)
2437 goto return1;
2438 total += 1;
2439 } else
2440 goto return1;
2441
2442 if (val != NULL) {
2443 v = xmlSchemaNewValue(XML_SCHEMAS_BASE64BINARY);
2444 if (v == NULL)
2445 goto error;
2446 base =
2447 (xmlChar *) xmlMallocAtomic((i + pad + 1) *
2448 sizeof(xmlChar));
2449 if (base == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002450 xmlSchemaTypeErrMemory(node, "allocating base64 data");
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002451 xmlFree(v);
2452 goto return1;
2453 }
2454 v->value.base64.str = base;
2455 for (cur = value; *cur; ++cur)
2456 if (_xmlSchemaBase64Decode(*cur) >= 0) {
2457 *base = *cur;
2458 ++base;
2459 }
2460 *base = 0;
2461 v->value.base64.total = total;
2462 *val = v;
2463 }
2464 goto return0;
2465 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002466 case XML_SCHEMAS_INTEGER:
2467 case XML_SCHEMAS_PINTEGER:
2468 case XML_SCHEMAS_NPINTEGER:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002469 case XML_SCHEMAS_NINTEGER:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002470 case XML_SCHEMAS_NNINTEGER:{
2471 const xmlChar *cur = value;
2472 unsigned long lo, mi, hi;
2473 int sign = 0;
2474
2475 if (cur == NULL)
2476 goto return1;
2477 if (*cur == '-') {
2478 sign = 1;
2479 cur++;
2480 } else if (*cur == '+')
2481 cur++;
2482 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2483 if (ret == 0)
2484 goto return1;
2485 if (*cur != 0)
2486 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002487 if (type->builtInType == XML_SCHEMAS_NPINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002488 if ((sign == 0) &&
2489 ((hi != 0) || (mi != 0) || (lo != 0)))
2490 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002491 } else if (type->builtInType == XML_SCHEMAS_PINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002492 if (sign == 1)
2493 goto return1;
2494 if ((hi == 0) && (mi == 0) && (lo == 0))
2495 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002496 } else if (type->builtInType == XML_SCHEMAS_NINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002497 if (sign == 0)
2498 goto return1;
2499 if ((hi == 0) && (mi == 0) && (lo == 0))
2500 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002501 } else if (type->builtInType == XML_SCHEMAS_NNINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002502 if ((sign == 1) &&
2503 ((hi != 0) || (mi != 0) || (lo != 0)))
2504 goto return1;
2505 }
2506 /*
2507 * We can store a value only if no overflow occured
2508 */
2509 if ((ret > 0) && (val != NULL)) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00002510 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002511 if (v != NULL) {
2512 v->value.decimal.lo = lo;
2513 v->value.decimal.mi = lo;
2514 v->value.decimal.hi = lo;
2515 v->value.decimal.sign = sign;
2516 v->value.decimal.frac = 0;
2517 v->value.decimal.total = cur - value;
2518 *val = v;
2519 }
2520 }
2521 goto return0;
2522 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002523 case XML_SCHEMAS_LONG:
2524 case XML_SCHEMAS_BYTE:
2525 case XML_SCHEMAS_SHORT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002526 case XML_SCHEMAS_INT:{
2527 const xmlChar *cur = value;
2528 unsigned long lo, mi, hi;
2529 int total = 0;
2530 int sign = 0;
2531
2532 if (cur == NULL)
2533 goto return1;
2534 if (*cur == '-') {
2535 sign = 1;
2536 cur++;
2537 } else if (*cur == '+')
2538 cur++;
2539 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2540 if (ret <= 0)
2541 goto return1;
2542 if (*cur != 0)
2543 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002544 if (type->builtInType == XML_SCHEMAS_LONG) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002545 if (hi >= 922) {
2546 if (hi > 922)
2547 goto return1;
2548 if (mi >= 33720368) {
2549 if (mi > 33720368)
2550 goto return1;
2551 if ((sign == 0) && (lo > 54775807))
2552 goto return1;
2553 if ((sign == 1) && (lo > 54775808))
2554 goto return1;
2555 }
2556 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002557 } else if (type->builtInType == XML_SCHEMAS_INT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002558 if (hi != 0)
2559 goto return1;
2560 if (mi >= 21) {
2561 if (mi > 21)
2562 goto return1;
2563 if ((sign == 0) && (lo > 47483647))
2564 goto return1;
2565 if ((sign == 1) && (lo > 47483648))
2566 goto return1;
2567 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002568 } else if (type->builtInType == XML_SCHEMAS_SHORT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002569 if ((mi != 0) || (hi != 0))
2570 goto return1;
2571 if ((sign == 1) && (lo > 32768))
2572 goto return1;
2573 if ((sign == 0) && (lo > 32767))
2574 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002575 } else if (type->builtInType == XML_SCHEMAS_BYTE) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002576 if ((mi != 0) || (hi != 0))
2577 goto return1;
2578 if ((sign == 1) && (lo > 128))
2579 goto return1;
2580 if ((sign == 0) && (lo > 127))
2581 goto return1;
2582 }
2583 if (val != NULL) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00002584 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002585 if (v != NULL) {
2586 v->value.decimal.lo = lo;
2587 v->value.decimal.mi = lo;
2588 v->value.decimal.hi = lo;
2589 v->value.decimal.sign = sign;
2590 v->value.decimal.frac = 0;
2591 v->value.decimal.total = total;
2592 *val = v;
2593 }
2594 }
2595 goto return0;
2596 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002597 case XML_SCHEMAS_UINT:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002598 case XML_SCHEMAS_ULONG:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002599 case XML_SCHEMAS_USHORT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002600 case XML_SCHEMAS_UBYTE:{
2601 const xmlChar *cur = value;
2602 unsigned long lo, mi, hi;
2603 int total = 0;
2604
2605 if (cur == NULL)
2606 goto return1;
2607 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2608 if (ret <= 0)
2609 goto return1;
2610 if (*cur != 0)
2611 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002612 if (type->builtInType == XML_SCHEMAS_ULONG) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002613 if (hi >= 1844) {
2614 if (hi > 1844)
2615 goto return1;
2616 if (mi >= 67440737) {
2617 if (mi > 67440737)
2618 goto return1;
2619 if (lo > 9551615)
2620 goto return1;
2621 }
2622 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002623 } else if (type->builtInType == XML_SCHEMAS_UINT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002624 if (hi != 0)
2625 goto return1;
2626 if (mi >= 42) {
2627 if (mi > 42)
2628 goto return1;
2629 if (lo > 94967295)
2630 goto return1;
2631 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002632 } else if (type->builtInType == XML_SCHEMAS_USHORT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002633 if ((mi != 0) || (hi != 0))
2634 goto return1;
2635 if (lo > 65535)
2636 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002637 } else if (type->builtInType == XML_SCHEMAS_UBYTE) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002638 if ((mi != 0) || (hi != 0))
2639 goto return1;
2640 if (lo > 255)
2641 goto return1;
2642 }
2643 if (val != NULL) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00002644 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002645 if (v != NULL) {
2646 v->value.decimal.lo = lo;
2647 v->value.decimal.mi = mi;
2648 v->value.decimal.hi = hi;
2649 v->value.decimal.sign = 0;
2650 v->value.decimal.frac = 0;
2651 v->value.decimal.total = total;
2652 *val = v;
2653 }
2654 }
2655 goto return0;
2656 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002657 }
2658
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002659 done:
2660 if (norm != NULL)
2661 xmlFree(norm);
2662 return (ret);
2663 return3:
2664 if (norm != NULL)
2665 xmlFree(norm);
2666 return (3);
2667 return1:
2668 if (norm != NULL)
2669 xmlFree(norm);
2670 return (1);
2671 return0:
2672 if (norm != NULL)
2673 xmlFree(norm);
2674 return (0);
2675 error:
2676 if (norm != NULL)
2677 xmlFree(norm);
2678 return (-1);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002679}
2680
2681/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002682 * xmlSchemaValPredefTypeNode:
Daniel Veillard4255d502002-04-16 15:50:10 +00002683 * @type: the predefined type
2684 * @value: the value to check
2685 * @val: the return computed value
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002686 * @node: the node containing the value
Daniel Veillard4255d502002-04-16 15:50:10 +00002687 *
2688 * Check that a value conforms to the lexical space of the predefined type.
2689 * if true a value is computed and returned in @val.
2690 *
2691 * Returns 0 if this validates, a positive error code number otherwise
2692 * and -1 in case of internal or API error.
2693 */
2694int
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002695xmlSchemaValPredefTypeNode(xmlSchemaTypePtr type, const xmlChar *value,
2696 xmlSchemaValPtr *val, xmlNodePtr node) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002697 return(xmlSchemaValAtomicType(type, value, val, node, 0));
Daniel Veillard4255d502002-04-16 15:50:10 +00002698}
2699
2700/**
Daniel Veillardc0826a72004-08-10 14:17:33 +00002701 * xmlSchemaValPredefTypeNodeNoNorm:
2702 * @type: the predefined type
2703 * @value: the value to check
2704 * @val: the return computed value
2705 * @node: the node containing the value
2706 *
2707 * Check that a value conforms to the lexical space of the predefined type.
2708 * if true a value is computed and returned in @val.
2709 * This one does apply any normalization to the value.
2710 *
2711 * Returns 0 if this validates, a positive error code number otherwise
2712 * and -1 in case of internal or API error.
2713 */
2714int
2715xmlSchemaValPredefTypeNodeNoNorm(xmlSchemaTypePtr type, const xmlChar *value,
2716 xmlSchemaValPtr *val, xmlNodePtr node) {
2717 return(xmlSchemaValAtomicType(type, value, val, node, 1));
2718}
2719
2720/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002721 * xmlSchemaValidatePredefinedType:
2722 * @type: the predefined type
2723 * @value: the value to check
2724 * @val: the return computed value
2725 *
2726 * Check that a value conforms to the lexical space of the predefined type.
2727 * if true a value is computed and returned in @val.
2728 *
2729 * Returns 0 if this validates, a positive error code number otherwise
2730 * and -1 in case of internal or API error.
2731 */
2732int
2733xmlSchemaValidatePredefinedType(xmlSchemaTypePtr type, const xmlChar *value,
2734 xmlSchemaValPtr *val) {
2735 return(xmlSchemaValPredefTypeNode(type, value, val, NULL));
2736}
2737
2738/**
Daniel Veillard4255d502002-04-16 15:50:10 +00002739 * xmlSchemaCompareDecimals:
2740 * @x: a first decimal value
2741 * @y: a second decimal value
2742 *
2743 * Compare 2 decimals
2744 *
2745 * Returns -1 if x < y, 0 if x == y, 1 if x > y and -2 in case of error
2746 */
2747static int
2748xmlSchemaCompareDecimals(xmlSchemaValPtr x, xmlSchemaValPtr y)
2749{
2750 xmlSchemaValPtr swp;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002751 int order = 1, p;
Daniel Veillard4255d502002-04-16 15:50:10 +00002752 unsigned long tmp;
2753
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002754 if ((x->value.decimal.sign) &&
2755 ((x->value.decimal.lo != 0) ||
2756 (x->value.decimal.mi != 0) ||
2757 (x->value.decimal.hi != 0))) {
2758 if ((y->value.decimal.sign) &&
2759 ((y->value.decimal.lo != 0) ||
2760 (y->value.decimal.mi != 0) ||
2761 (y->value.decimal.hi != 0)))
Daniel Veillard80b19092003-03-28 13:29:53 +00002762 order = -1;
2763 else
2764 return (-1);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002765 } else if ((y->value.decimal.sign) &&
2766 ((y->value.decimal.lo != 0) ||
2767 (y->value.decimal.mi != 0) ||
2768 (y->value.decimal.hi != 0))) {
Daniel Veillard4255d502002-04-16 15:50:10 +00002769 return (1);
Daniel Veillard80b19092003-03-28 13:29:53 +00002770 }
Daniel Veillard4255d502002-04-16 15:50:10 +00002771 if (x->value.decimal.frac == y->value.decimal.frac) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002772 if (x->value.decimal.hi < y->value.decimal.hi)
2773 return (-order);
Daniel Veillard01fa6152004-06-29 17:04:39 +00002774 if (x->value.decimal.hi > y->value.decimal.hi)
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002775 return (order);
2776 if (x->value.decimal.mi < y->value.decimal.mi)
2777 return (-order);
Daniel Veillard01fa6152004-06-29 17:04:39 +00002778 if (x->value.decimal.mi > y->value.decimal.mi)
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002779 return (order);
2780 if (x->value.decimal.lo < y->value.decimal.lo)
Daniel Veillard80b19092003-03-28 13:29:53 +00002781 return (-order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002782 if (x->value.decimal.lo > y->value.decimal.lo)
Daniel Veillard80b19092003-03-28 13:29:53 +00002783 return(order);
2784 return(0);
Daniel Veillard4255d502002-04-16 15:50:10 +00002785 }
2786 if (y->value.decimal.frac > x->value.decimal.frac) {
2787 swp = y;
2788 y = x;
2789 x = swp;
2790 order = -order;
2791 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002792 p = powten[x->value.decimal.frac - y->value.decimal.frac];
2793 tmp = x->value.decimal.lo / p;
2794 if (tmp > y->value.decimal.lo)
Daniel Veillard4255d502002-04-16 15:50:10 +00002795 return (order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002796 if (tmp < y->value.decimal.lo)
Daniel Veillard4255d502002-04-16 15:50:10 +00002797 return (-order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002798 tmp = y->value.decimal.lo * p;
2799 if (x->value.decimal.lo < tmp)
Daniel Veillard4255d502002-04-16 15:50:10 +00002800 return (-order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002801 if (x->value.decimal.lo == tmp)
Daniel Veillard4255d502002-04-16 15:50:10 +00002802 return (0);
2803 return (order);
2804}
2805
2806/**
Daniel Veillard070803b2002-05-03 07:29:38 +00002807 * xmlSchemaCompareDurations:
2808 * @x: a first duration value
2809 * @y: a second duration value
2810 *
2811 * Compare 2 durations
2812 *
2813 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
2814 * case of error
2815 */
2816static int
2817xmlSchemaCompareDurations(xmlSchemaValPtr x, xmlSchemaValPtr y)
2818{
2819 long carry, mon, day;
2820 double sec;
Daniel Veillard80b19092003-03-28 13:29:53 +00002821 int invert = 1;
2822 long xmon, xday, myear, minday, maxday;
Daniel Veillard070803b2002-05-03 07:29:38 +00002823 static const long dayRange [2][12] = {
2824 { 0, 28, 59, 89, 120, 150, 181, 212, 242, 273, 303, 334, },
2825 { 0, 31, 62, 92, 123, 153, 184, 215, 245, 276, 306, 337} };
2826
2827 if ((x == NULL) || (y == NULL))
Daniel Veillard5a872412002-05-22 06:40:27 +00002828 return -2;
Daniel Veillard070803b2002-05-03 07:29:38 +00002829
2830 /* months */
2831 mon = x->value.dur.mon - y->value.dur.mon;
2832
2833 /* seconds */
2834 sec = x->value.dur.sec - y->value.dur.sec;
2835 carry = (long)sec / SECS_PER_DAY;
2836 sec -= (double)(carry * SECS_PER_DAY);
2837
2838 /* days */
2839 day = x->value.dur.day - y->value.dur.day + carry;
2840
2841 /* easy test */
2842 if (mon == 0) {
2843 if (day == 0)
2844 if (sec == 0.0)
2845 return 0;
2846 else if (sec < 0.0)
2847 return -1;
2848 else
2849 return 1;
2850 else if (day < 0)
2851 return -1;
2852 else
2853 return 1;
2854 }
2855
2856 if (mon > 0) {
2857 if ((day >= 0) && (sec >= 0.0))
2858 return 1;
2859 else {
2860 xmon = mon;
2861 xday = -day;
2862 }
2863 } else if ((day <= 0) && (sec <= 0.0)) {
2864 return -1;
2865 } else {
Daniel Veillard80b19092003-03-28 13:29:53 +00002866 invert = -1;
Daniel Veillard070803b2002-05-03 07:29:38 +00002867 xmon = -mon;
2868 xday = day;
2869 }
2870
2871 myear = xmon / 12;
Daniel Veillard80b19092003-03-28 13:29:53 +00002872 if (myear == 0) {
2873 minday = 0;
2874 maxday = 0;
2875 } else {
2876 maxday = 366 * ((myear + 3) / 4) +
2877 365 * ((myear - 1) % 4);
2878 minday = maxday - 1;
2879 }
2880
Daniel Veillard070803b2002-05-03 07:29:38 +00002881 xmon = xmon % 12;
2882 minday += dayRange[0][xmon];
2883 maxday += dayRange[1][xmon];
2884
Daniel Veillard80b19092003-03-28 13:29:53 +00002885 if ((maxday == minday) && (maxday == xday))
2886 return(0); /* can this really happen ? */
Daniel Veillard070803b2002-05-03 07:29:38 +00002887 if (maxday < xday)
Daniel Veillard80b19092003-03-28 13:29:53 +00002888 return(-invert);
2889 if (minday > xday)
2890 return(invert);
Daniel Veillard070803b2002-05-03 07:29:38 +00002891
2892 /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00002893 return 2;
2894}
2895
2896/*
2897 * macros for adding date/times and durations
2898 */
2899#define FQUOTIENT(a,b) (floor(((double)a/(double)b)))
2900#define MODULO(a,b) (a - FQUOTIENT(a,b) * b)
2901#define FQUOTIENT_RANGE(a,low,high) (FQUOTIENT((a-low),(high-low)))
2902#define MODULO_RANGE(a,low,high) ((MODULO((a-low),(high-low)))+low)
2903
2904/**
Daniel Veillard669adfc2004-05-29 20:12:46 +00002905 * xmlSchemaDupVal:
2906 * @v: the #xmlSchemaValPtr value to duplicate
2907 *
2908 * Makes a copy of @v. The calling program is responsible for freeing
2909 * the returned value.
2910 *
2911 * returns a pointer to a duplicated #xmlSchemaValPtr or NULL if error.
2912 */
2913static xmlSchemaValPtr
2914xmlSchemaDupVal (xmlSchemaValPtr v)
2915{
2916 xmlSchemaValPtr ret = xmlSchemaNewValue(v->type);
2917 if (ret == NULL)
2918 return NULL;
2919
2920 memcpy(ret, v, sizeof(xmlSchemaVal));
2921 return ret;
2922}
2923
2924/**
Daniel Veillard5a872412002-05-22 06:40:27 +00002925 * _xmlSchemaDateAdd:
2926 * @dt: an #xmlSchemaValPtr
2927 * @dur: an #xmlSchemaValPtr of type #XS_DURATION
2928 *
2929 * Compute a new date/time from @dt and @dur. This function assumes @dt
2930 * is either #XML_SCHEMAS_DATETIME, #XML_SCHEMAS_DATE, #XML_SCHEMAS_GYEARMONTH,
Daniel Veillard669adfc2004-05-29 20:12:46 +00002931 * or #XML_SCHEMAS_GYEAR. The returned #xmlSchemaVal is the same type as
2932 * @dt. The calling program is responsible for freeing the returned value.
Daniel Veillard5a872412002-05-22 06:40:27 +00002933 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00002934 * Returns a pointer to a new #xmlSchemaVal or NULL if error.
Daniel Veillard5a872412002-05-22 06:40:27 +00002935 */
2936static xmlSchemaValPtr
2937_xmlSchemaDateAdd (xmlSchemaValPtr dt, xmlSchemaValPtr dur)
2938{
Daniel Veillard669adfc2004-05-29 20:12:46 +00002939 xmlSchemaValPtr ret, tmp;
Daniel Veillard5a872412002-05-22 06:40:27 +00002940 long carry, tempdays, temp;
2941 xmlSchemaValDatePtr r, d;
2942 xmlSchemaValDurationPtr u;
2943
2944 if ((dt == NULL) || (dur == NULL))
2945 return NULL;
2946
2947 ret = xmlSchemaNewValue(dt->type);
2948 if (ret == NULL)
2949 return NULL;
2950
Daniel Veillard669adfc2004-05-29 20:12:46 +00002951 /* make a copy so we don't alter the original value */
2952 tmp = xmlSchemaDupVal(dt);
2953 if (tmp == NULL) {
2954 xmlSchemaFreeValue(ret);
2955 return NULL;
2956 }
2957
Daniel Veillard5a872412002-05-22 06:40:27 +00002958 r = &(ret->value.date);
Daniel Veillard669adfc2004-05-29 20:12:46 +00002959 d = &(tmp->value.date);
Daniel Veillard5a872412002-05-22 06:40:27 +00002960 u = &(dur->value.dur);
2961
2962 /* normalization */
2963 if (d->mon == 0)
2964 d->mon = 1;
2965
2966 /* normalize for time zone offset */
2967 u->sec -= (d->tzo * 60);
2968 d->tzo = 0;
2969
2970 /* normalization */
2971 if (d->day == 0)
2972 d->day = 1;
2973
2974 /* month */
2975 carry = d->mon + u->mon;
Daniel Veillardebe25d42004-03-25 09:35:49 +00002976 r->mon = (unsigned int) MODULO_RANGE(carry, 1, 13);
2977 carry = (long) FQUOTIENT_RANGE(carry, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00002978
2979 /* year (may be modified later) */
2980 r->year = d->year + carry;
2981 if (r->year == 0) {
2982 if (d->year > 0)
2983 r->year--;
2984 else
2985 r->year++;
2986 }
2987
2988 /* time zone */
2989 r->tzo = d->tzo;
2990 r->tz_flag = d->tz_flag;
2991
2992 /* seconds */
2993 r->sec = d->sec + u->sec;
Daniel Veillardebe25d42004-03-25 09:35:49 +00002994 carry = (long) FQUOTIENT((long)r->sec, 60);
Daniel Veillard5a872412002-05-22 06:40:27 +00002995 if (r->sec != 0.0) {
2996 r->sec = MODULO(r->sec, 60.0);
2997 }
2998
2999 /* minute */
3000 carry += d->min;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003001 r->min = (unsigned int) MODULO(carry, 60);
3002 carry = (long) FQUOTIENT(carry, 60);
Daniel Veillard5a872412002-05-22 06:40:27 +00003003
3004 /* hours */
3005 carry += d->hour;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003006 r->hour = (unsigned int) MODULO(carry, 24);
3007 carry = (long)FQUOTIENT(carry, 24);
Daniel Veillard5a872412002-05-22 06:40:27 +00003008
3009 /*
3010 * days
3011 * Note we use tempdays because the temporary values may need more
3012 * than 5 bits
3013 */
3014 if ((VALID_YEAR(r->year)) && (VALID_MONTH(r->mon)) &&
3015 (d->day > MAX_DAYINMONTH(r->year, r->mon)))
3016 tempdays = MAX_DAYINMONTH(r->year, r->mon);
3017 else if (d->day < 1)
3018 tempdays = 1;
3019 else
3020 tempdays = d->day;
3021
3022 tempdays += u->day + carry;
3023
3024 while (1) {
3025 if (tempdays < 1) {
Daniel Veillardebe25d42004-03-25 09:35:49 +00003026 long tmon = (long) MODULO_RANGE(r->mon-1, 1, 13);
3027 long tyr = r->year + (long)FQUOTIENT_RANGE(r->mon-1, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00003028 if (tyr == 0)
3029 tyr--;
3030 tempdays += MAX_DAYINMONTH(tyr, tmon);
3031 carry = -1;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003032 } else if (tempdays > (long) MAX_DAYINMONTH(r->year, r->mon)) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003033 tempdays = tempdays - MAX_DAYINMONTH(r->year, r->mon);
3034 carry = 1;
3035 } else
3036 break;
3037
3038 temp = r->mon + carry;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003039 r->mon = (unsigned int) MODULO_RANGE(temp, 1, 13);
3040 r->year = r->year + (unsigned int) FQUOTIENT_RANGE(temp, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00003041 if (r->year == 0) {
3042 if (temp < 1)
3043 r->year--;
3044 else
3045 r->year++;
3046 }
3047 }
3048
3049 r->day = tempdays;
3050
3051 /*
3052 * adjust the date/time type to the date values
3053 */
3054 if (ret->type != XML_SCHEMAS_DATETIME) {
3055 if ((r->hour) || (r->min) || (r->sec))
3056 ret->type = XML_SCHEMAS_DATETIME;
3057 else if (ret->type != XML_SCHEMAS_DATE) {
3058 if ((r->mon != 1) && (r->day != 1))
3059 ret->type = XML_SCHEMAS_DATE;
3060 else if ((ret->type != XML_SCHEMAS_GYEARMONTH) && (r->mon != 1))
3061 ret->type = XML_SCHEMAS_GYEARMONTH;
3062 }
3063 }
3064
Daniel Veillard669adfc2004-05-29 20:12:46 +00003065 xmlSchemaFreeValue(tmp);
Daniel Veillard5a872412002-05-22 06:40:27 +00003066
Daniel Veillard5a872412002-05-22 06:40:27 +00003067 return ret;
3068}
3069
3070/**
3071 * xmlSchemaDateNormalize:
Daniel Veillard669adfc2004-05-29 20:12:46 +00003072 * @dt: an #xmlSchemaValPtr of a date/time type value.
3073 * @offset: number of seconds to adjust @dt by.
Daniel Veillard5a872412002-05-22 06:40:27 +00003074 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00003075 * Normalize @dt to GMT time. The @offset parameter is subtracted from
3076 * the return value is a time-zone offset is present on @dt.
Daniel Veillard5a872412002-05-22 06:40:27 +00003077 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00003078 * Returns a normalized copy of @dt or NULL if error.
Daniel Veillard5a872412002-05-22 06:40:27 +00003079 */
3080static xmlSchemaValPtr
3081xmlSchemaDateNormalize (xmlSchemaValPtr dt, double offset)
3082{
3083 xmlSchemaValPtr dur, ret;
3084
3085 if (dt == NULL)
3086 return NULL;
3087
3088 if (((dt->type != XML_SCHEMAS_TIME) &&
3089 (dt->type != XML_SCHEMAS_DATETIME)) || (dt->value.date.tzo == 0))
3090 return xmlSchemaDupVal(dt);
3091
3092 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
3093 if (dur == NULL)
3094 return NULL;
3095
3096 dur->value.date.sec -= offset;
3097
3098 ret = _xmlSchemaDateAdd(dt, dur);
3099 if (ret == NULL)
3100 return NULL;
3101
3102 xmlSchemaFreeValue(dur);
3103
3104 /* ret->value.date.tzo = 0; */
3105 return ret;
3106}
3107
3108/**
3109 * _xmlSchemaDateCastYMToDays:
3110 * @dt: an #xmlSchemaValPtr
3111 *
3112 * Convert mon and year of @dt to total number of days. Take the
3113 * number of years since (or before) 1 AD and add the number of leap
3114 * years. This is a function because negative
3115 * years must be handled a little differently and there is no zero year.
3116 *
3117 * Returns number of days.
3118 */
3119static long
3120_xmlSchemaDateCastYMToDays (const xmlSchemaValPtr dt)
3121{
3122 long ret;
3123
3124 if (dt->value.date.year < 0)
3125 ret = (dt->value.date.year * 365) +
3126 (((dt->value.date.year+1)/4)-((dt->value.date.year+1)/100)+
3127 ((dt->value.date.year+1)/400)) +
3128 DAY_IN_YEAR(0, dt->value.date.mon, dt->value.date.year);
3129 else
3130 ret = ((dt->value.date.year-1) * 365) +
3131 (((dt->value.date.year-1)/4)-((dt->value.date.year-1)/100)+
3132 ((dt->value.date.year-1)/400)) +
3133 DAY_IN_YEAR(0, dt->value.date.mon, dt->value.date.year);
3134
3135 return ret;
3136}
3137
3138/**
3139 * TIME_TO_NUMBER:
3140 * @dt: an #xmlSchemaValPtr
3141 *
3142 * Calculates the number of seconds in the time portion of @dt.
3143 *
3144 * Returns seconds.
3145 */
3146#define TIME_TO_NUMBER(dt) \
3147 ((double)((dt->value.date.hour * SECS_PER_HOUR) + \
Daniel Veillardb3721c22003-03-31 11:22:25 +00003148 (dt->value.date.min * SECS_PER_MIN) + \
3149 (dt->value.date.tzo * SECS_PER_MIN)) + \
3150 dt->value.date.sec)
Daniel Veillard5a872412002-05-22 06:40:27 +00003151
3152/**
3153 * xmlSchemaCompareDates:
3154 * @x: a first date/time value
3155 * @y: a second date/time value
3156 *
3157 * Compare 2 date/times
3158 *
3159 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3160 * case of error
3161 */
3162static int
3163xmlSchemaCompareDates (xmlSchemaValPtr x, xmlSchemaValPtr y)
3164{
3165 unsigned char xmask, ymask, xor_mask, and_mask;
3166 xmlSchemaValPtr p1, p2, q1, q2;
3167 long p1d, p2d, q1d, q2d;
3168
3169 if ((x == NULL) || (y == NULL))
3170 return -2;
3171
3172 if (x->value.date.tz_flag) {
3173
3174 if (!y->value.date.tz_flag) {
3175 p1 = xmlSchemaDateNormalize(x, 0);
3176 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3177 /* normalize y + 14:00 */
3178 q1 = xmlSchemaDateNormalize(y, (14 * SECS_PER_HOUR));
3179
3180 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003181 if (p1d < q1d) {
3182 xmlSchemaFreeValue(p1);
3183 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003184 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003185 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003186 double sec;
3187
3188 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00003189 if (sec < 0.0) {
3190 xmlSchemaFreeValue(p1);
3191 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003192 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003193 } else {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003194 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003195 /* normalize y - 14:00 */
3196 q2 = xmlSchemaDateNormalize(y, -(14 * SECS_PER_HOUR));
3197 q2d = _xmlSchemaDateCastYMToDays(q2) + q2->value.date.day;
3198 if (p1d > q2d)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003199 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003200 else if (p1d == q2d) {
3201 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q2);
3202 if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003203 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003204 else
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003205 ret = 2; /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00003206 }
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003207 xmlSchemaFreeValue(p1);
3208 xmlSchemaFreeValue(q1);
3209 xmlSchemaFreeValue(q2);
3210 if (ret != 0)
3211 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003212 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00003213 } else {
3214 xmlSchemaFreeValue(p1);
3215 xmlSchemaFreeValue(q1);
3216 }
Daniel Veillard5a872412002-05-22 06:40:27 +00003217 }
3218 } else if (y->value.date.tz_flag) {
3219 q1 = xmlSchemaDateNormalize(y, 0);
3220 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
3221
3222 /* normalize x - 14:00 */
3223 p1 = xmlSchemaDateNormalize(x, -(14 * SECS_PER_HOUR));
3224 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3225
Daniel Veillardfdc91562002-07-01 21:52:03 +00003226 if (p1d < q1d) {
3227 xmlSchemaFreeValue(p1);
3228 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003229 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003230 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003231 double sec;
3232
3233 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00003234 if (sec < 0.0) {
3235 xmlSchemaFreeValue(p1);
3236 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003237 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003238 } else {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003239 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003240 /* normalize x + 14:00 */
3241 p2 = xmlSchemaDateNormalize(x, (14 * SECS_PER_HOUR));
3242 p2d = _xmlSchemaDateCastYMToDays(p2) + p2->value.date.day;
3243
Daniel Veillard6560a422003-03-27 21:25:38 +00003244 if (p2d > q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003245 ret = 1;
Daniel Veillard6560a422003-03-27 21:25:38 +00003246 } else if (p2d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003247 sec = TIME_TO_NUMBER(p2) - TIME_TO_NUMBER(q1);
3248 if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003249 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003250 else
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003251 ret = 2; /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00003252 }
Daniel Veillard6560a422003-03-27 21:25:38 +00003253 xmlSchemaFreeValue(p1);
3254 xmlSchemaFreeValue(q1);
3255 xmlSchemaFreeValue(p2);
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003256 if (ret != 0)
3257 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003258 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00003259 } else {
3260 xmlSchemaFreeValue(p1);
3261 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003262 }
3263 }
3264
3265 /*
3266 * if the same type then calculate the difference
3267 */
3268 if (x->type == y->type) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003269 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003270 q1 = xmlSchemaDateNormalize(y, 0);
3271 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
3272
3273 p1 = xmlSchemaDateNormalize(x, 0);
3274 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3275
Daniel Veillardfdc91562002-07-01 21:52:03 +00003276 if (p1d < q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003277 ret = -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003278 } else if (p1d > q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003279 ret = 1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003280 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00003281 double sec;
3282
3283 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
3284 if (sec < 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003285 ret = -1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003286 else if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003287 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003288
3289 }
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003290 xmlSchemaFreeValue(p1);
3291 xmlSchemaFreeValue(q1);
3292 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003293 }
3294
3295 switch (x->type) {
3296 case XML_SCHEMAS_DATETIME:
3297 xmask = 0xf;
3298 break;
3299 case XML_SCHEMAS_DATE:
3300 xmask = 0x7;
3301 break;
3302 case XML_SCHEMAS_GYEAR:
3303 xmask = 0x1;
3304 break;
3305 case XML_SCHEMAS_GMONTH:
3306 xmask = 0x2;
3307 break;
3308 case XML_SCHEMAS_GDAY:
3309 xmask = 0x3;
3310 break;
3311 case XML_SCHEMAS_GYEARMONTH:
3312 xmask = 0x3;
3313 break;
3314 case XML_SCHEMAS_GMONTHDAY:
3315 xmask = 0x6;
3316 break;
3317 case XML_SCHEMAS_TIME:
3318 xmask = 0x8;
3319 break;
3320 default:
3321 xmask = 0;
3322 break;
3323 }
3324
3325 switch (y->type) {
3326 case XML_SCHEMAS_DATETIME:
3327 ymask = 0xf;
3328 break;
3329 case XML_SCHEMAS_DATE:
3330 ymask = 0x7;
3331 break;
3332 case XML_SCHEMAS_GYEAR:
3333 ymask = 0x1;
3334 break;
3335 case XML_SCHEMAS_GMONTH:
3336 ymask = 0x2;
3337 break;
3338 case XML_SCHEMAS_GDAY:
3339 ymask = 0x3;
3340 break;
3341 case XML_SCHEMAS_GYEARMONTH:
3342 ymask = 0x3;
3343 break;
3344 case XML_SCHEMAS_GMONTHDAY:
3345 ymask = 0x6;
3346 break;
3347 case XML_SCHEMAS_TIME:
3348 ymask = 0x8;
3349 break;
3350 default:
3351 ymask = 0;
3352 break;
3353 }
3354
3355 xor_mask = xmask ^ ymask; /* mark type differences */
3356 and_mask = xmask & ymask; /* mark field specification */
3357
3358 /* year */
3359 if (xor_mask & 1)
3360 return 2; /* indeterminate */
3361 else if (and_mask & 1) {
3362 if (x->value.date.year < y->value.date.year)
3363 return -1;
3364 else if (x->value.date.year > y->value.date.year)
3365 return 1;
3366 }
3367
3368 /* month */
3369 if (xor_mask & 2)
3370 return 2; /* indeterminate */
3371 else if (and_mask & 2) {
3372 if (x->value.date.mon < y->value.date.mon)
3373 return -1;
3374 else if (x->value.date.mon > y->value.date.mon)
3375 return 1;
3376 }
3377
3378 /* day */
3379 if (xor_mask & 4)
3380 return 2; /* indeterminate */
3381 else if (and_mask & 4) {
3382 if (x->value.date.day < y->value.date.day)
3383 return -1;
3384 else if (x->value.date.day > y->value.date.day)
3385 return 1;
3386 }
3387
3388 /* time */
3389 if (xor_mask & 8)
3390 return 2; /* indeterminate */
3391 else if (and_mask & 8) {
3392 if (x->value.date.hour < y->value.date.hour)
3393 return -1;
3394 else if (x->value.date.hour > y->value.date.hour)
3395 return 1;
3396 else if (x->value.date.min < y->value.date.min)
3397 return -1;
3398 else if (x->value.date.min > y->value.date.min)
3399 return 1;
3400 else if (x->value.date.sec < y->value.date.sec)
3401 return -1;
3402 else if (x->value.date.sec > y->value.date.sec)
3403 return 1;
3404 }
3405
Daniel Veillard070803b2002-05-03 07:29:38 +00003406 return 0;
3407}
3408
3409/**
Daniel Veillardc4c21552003-03-29 10:53:38 +00003410 * xmlSchemaCompareNormStrings:
3411 * @x: a first string value
3412 * @y: a second string value
3413 *
3414 * Compare 2 string for their normalized values.
3415 *
3416 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
3417 * case of error
3418 */
3419static int
3420xmlSchemaCompareNormStrings(xmlSchemaValPtr x, xmlSchemaValPtr y) {
3421 const xmlChar *utf1;
3422 const xmlChar *utf2;
3423 int tmp;
3424
3425 if ((x == NULL) || (y == NULL))
3426 return(-2);
3427 utf1 = x->value.str;
3428 utf2 = y->value.str;
3429
William M. Brack76e95df2003-10-18 16:20:14 +00003430 while (IS_BLANK_CH(*utf1)) utf1++;
3431 while (IS_BLANK_CH(*utf2)) utf2++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003432 while ((*utf1 != 0) && (*utf2 != 0)) {
William M. Brack76e95df2003-10-18 16:20:14 +00003433 if (IS_BLANK_CH(*utf1)) {
3434 if (!IS_BLANK_CH(*utf2)) {
Daniel Veillardc4c21552003-03-29 10:53:38 +00003435 tmp = *utf1 - *utf2;
3436 return(tmp);
3437 }
William M. Brack76e95df2003-10-18 16:20:14 +00003438 while (IS_BLANK_CH(*utf1)) utf1++;
3439 while (IS_BLANK_CH(*utf2)) utf2++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003440 } else {
3441 tmp = *utf1++ - *utf2++;
3442 if (tmp < 0)
3443 return(-1);
3444 if (tmp > 0)
3445 return(1);
3446 }
3447 }
3448 if (*utf1 != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00003449 while (IS_BLANK_CH(*utf1)) utf1++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003450 if (*utf1 != 0)
3451 return(1);
3452 }
3453 if (*utf2 != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00003454 while (IS_BLANK_CH(*utf2)) utf2++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003455 if (*utf2 != 0)
3456 return(-1);
3457 }
3458 return(0);
3459}
3460
3461/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003462 * xmlSchemaCompareFloats:
3463 * @x: a first float or double value
3464 * @y: a second float or double value
3465 *
3466 * Compare 2 values
3467 *
3468 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3469 * case of error
3470 */
3471static int
3472xmlSchemaCompareFloats(xmlSchemaValPtr x, xmlSchemaValPtr y) {
3473 double d1, d2;
3474
3475 if ((x == NULL) || (y == NULL))
3476 return(-2);
3477
3478 /*
3479 * Cast everything to doubles.
3480 */
3481 if (x->type == XML_SCHEMAS_DOUBLE)
3482 d1 = x->value.d;
3483 else if (x->type == XML_SCHEMAS_FLOAT)
3484 d1 = x->value.f;
3485 else
3486 return(-2);
3487
3488 if (y->type == XML_SCHEMAS_DOUBLE)
3489 d2 = y->value.d;
3490 else if (y->type == XML_SCHEMAS_FLOAT)
3491 d2 = y->value.f;
3492 else
3493 return(-2);
3494
3495 /*
3496 * Check for special cases.
3497 */
3498 if (xmlXPathIsNaN(d1)) {
3499 if (xmlXPathIsNaN(d2))
3500 return(0);
3501 return(1);
3502 }
3503 if (xmlXPathIsNaN(d2))
3504 return(-1);
3505 if (d1 == xmlXPathPINF) {
3506 if (d2 == xmlXPathPINF)
3507 return(0);
3508 return(1);
3509 }
3510 if (d2 == xmlXPathPINF)
3511 return(-1);
3512 if (d1 == xmlXPathNINF) {
3513 if (d2 == xmlXPathNINF)
3514 return(0);
3515 return(-1);
3516 }
3517 if (d2 == xmlXPathNINF)
3518 return(1);
3519
3520 /*
3521 * basic tests, the last one we should have equality, but
3522 * portability is more important than speed and handling
3523 * NaN or Inf in a portable way is always a challenge, so ...
3524 */
3525 if (d1 < d2)
3526 return(-1);
3527 if (d1 > d2)
3528 return(1);
3529 if (d1 == d2)
3530 return(0);
3531 return(2);
3532}
3533
3534/**
Daniel Veillard4255d502002-04-16 15:50:10 +00003535 * xmlSchemaCompareValues:
3536 * @x: a first value
3537 * @y: a second value
3538 *
3539 * Compare 2 values
3540 *
Daniel Veillard5a872412002-05-22 06:40:27 +00003541 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3542 * case of error
Daniel Veillard4255d502002-04-16 15:50:10 +00003543 */
Daniel Veillard80b19092003-03-28 13:29:53 +00003544int
Daniel Veillard4255d502002-04-16 15:50:10 +00003545xmlSchemaCompareValues(xmlSchemaValPtr x, xmlSchemaValPtr y) {
3546 if ((x == NULL) || (y == NULL))
3547 return(-2);
3548
3549 switch (x->type) {
Daniel Veillard80b19092003-03-28 13:29:53 +00003550 case XML_SCHEMAS_UNKNOWN:
3551 return(-2);
3552 case XML_SCHEMAS_INTEGER:
3553 case XML_SCHEMAS_NPINTEGER:
3554 case XML_SCHEMAS_NINTEGER:
3555 case XML_SCHEMAS_NNINTEGER:
3556 case XML_SCHEMAS_PINTEGER:
3557 case XML_SCHEMAS_INT:
3558 case XML_SCHEMAS_UINT:
3559 case XML_SCHEMAS_LONG:
3560 case XML_SCHEMAS_ULONG:
3561 case XML_SCHEMAS_SHORT:
3562 case XML_SCHEMAS_USHORT:
3563 case XML_SCHEMAS_BYTE:
3564 case XML_SCHEMAS_UBYTE:
Daniel Veillard4255d502002-04-16 15:50:10 +00003565 case XML_SCHEMAS_DECIMAL:
Daniel Veillard80b19092003-03-28 13:29:53 +00003566 if (y->type == x->type)
3567 return(xmlSchemaCompareDecimals(x, y));
3568 if ((y->type == XML_SCHEMAS_DECIMAL) ||
3569 (y->type == XML_SCHEMAS_INTEGER) ||
3570 (y->type == XML_SCHEMAS_NPINTEGER) ||
3571 (y->type == XML_SCHEMAS_NINTEGER) ||
3572 (y->type == XML_SCHEMAS_NNINTEGER) ||
3573 (y->type == XML_SCHEMAS_PINTEGER) ||
3574 (y->type == XML_SCHEMAS_INT) ||
3575 (y->type == XML_SCHEMAS_UINT) ||
3576 (y->type == XML_SCHEMAS_LONG) ||
3577 (y->type == XML_SCHEMAS_ULONG) ||
3578 (y->type == XML_SCHEMAS_SHORT) ||
3579 (y->type == XML_SCHEMAS_USHORT) ||
3580 (y->type == XML_SCHEMAS_BYTE) ||
3581 (y->type == XML_SCHEMAS_UBYTE))
Daniel Veillard4255d502002-04-16 15:50:10 +00003582 return(xmlSchemaCompareDecimals(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00003583 return(-2);
Daniel Veillard070803b2002-05-03 07:29:38 +00003584 case XML_SCHEMAS_DURATION:
3585 if (y->type == XML_SCHEMAS_DURATION)
3586 return(xmlSchemaCompareDurations(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00003587 return(-2);
3588 case XML_SCHEMAS_TIME:
3589 case XML_SCHEMAS_GDAY:
3590 case XML_SCHEMAS_GMONTH:
3591 case XML_SCHEMAS_GMONTHDAY:
3592 case XML_SCHEMAS_GYEAR:
3593 case XML_SCHEMAS_GYEARMONTH:
3594 case XML_SCHEMAS_DATE:
3595 case XML_SCHEMAS_DATETIME:
3596 if ((y->type == XML_SCHEMAS_DATETIME) ||
3597 (y->type == XML_SCHEMAS_TIME) ||
3598 (y->type == XML_SCHEMAS_GDAY) ||
3599 (y->type == XML_SCHEMAS_GMONTH) ||
3600 (y->type == XML_SCHEMAS_GMONTHDAY) ||
3601 (y->type == XML_SCHEMAS_GYEAR) ||
3602 (y->type == XML_SCHEMAS_DATE) ||
3603 (y->type == XML_SCHEMAS_GYEARMONTH))
3604 return (xmlSchemaCompareDates(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00003605 return (-2);
Daniel Veillard80b19092003-03-28 13:29:53 +00003606 case XML_SCHEMAS_NORMSTRING:
Daniel Veillard80b19092003-03-28 13:29:53 +00003607 case XML_SCHEMAS_TOKEN:
3608 case XML_SCHEMAS_LANGUAGE:
3609 case XML_SCHEMAS_NMTOKEN:
Daniel Veillard80b19092003-03-28 13:29:53 +00003610 case XML_SCHEMAS_NAME:
Daniel Veillard80b19092003-03-28 13:29:53 +00003611 case XML_SCHEMAS_NCNAME:
3612 case XML_SCHEMAS_ID:
3613 case XML_SCHEMAS_IDREF:
Daniel Veillard80b19092003-03-28 13:29:53 +00003614 case XML_SCHEMAS_ENTITY:
Daniel Veillard80b19092003-03-28 13:29:53 +00003615 case XML_SCHEMAS_NOTATION:
3616 case XML_SCHEMAS_ANYURI:
Daniel Veillardc4c21552003-03-29 10:53:38 +00003617 if ((y->type == XML_SCHEMAS_NORMSTRING) ||
3618 (y->type == XML_SCHEMAS_TOKEN) ||
3619 (y->type == XML_SCHEMAS_LANGUAGE) ||
3620 (y->type == XML_SCHEMAS_NMTOKEN) ||
3621 (y->type == XML_SCHEMAS_NAME) ||
3622 (y->type == XML_SCHEMAS_QNAME) ||
3623 (y->type == XML_SCHEMAS_NCNAME) ||
3624 (y->type == XML_SCHEMAS_ID) ||
3625 (y->type == XML_SCHEMAS_IDREF) ||
3626 (y->type == XML_SCHEMAS_ENTITY) ||
3627 (y->type == XML_SCHEMAS_NOTATION) ||
3628 (y->type == XML_SCHEMAS_ANYURI))
3629 return (xmlSchemaCompareNormStrings(x, y));
3630 return (-2);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003631 case XML_SCHEMAS_QNAME:
3632 if (y->type == XML_SCHEMAS_QNAME) {
3633 if ((xmlStrEqual(x->value.qname.name, y->value.qname.name)) &&
3634 (xmlStrEqual(x->value.qname.uri, y->value.qname.uri)))
3635 return(0);
3636 return(2);
3637 }
3638 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00003639 case XML_SCHEMAS_FLOAT:
3640 case XML_SCHEMAS_DOUBLE:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003641 if ((y->type == XML_SCHEMAS_FLOAT) ||
3642 (y->type == XML_SCHEMAS_DOUBLE))
3643 return (xmlSchemaCompareFloats(x, y));
3644 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00003645 case XML_SCHEMAS_BOOLEAN:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003646 if (y->type == XML_SCHEMAS_BOOLEAN) {
3647 if (x->value.b == y->value.b)
3648 return(0);
3649 if (x->value.b == 0)
3650 return(-1);
3651 return(1);
3652 }
3653 return (-2);
Daniel Veillard560c2a42003-07-06 21:13:49 +00003654 case XML_SCHEMAS_HEXBINARY:
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00003655 if (y->type == XML_SCHEMAS_HEXBINARY) {
3656 if (x->value.hex.total == y->value.hex.total) {
3657 int ret = xmlStrcmp(x->value.hex.str, y->value.hex.str);
3658 if (ret > 0)
3659 return(1);
3660 else if (ret == 0)
3661 return(0);
3662 }
3663 else if (x->value.hex.total > y->value.hex.total)
3664 return(1);
3665
3666 return(-1);
3667 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00003668 return (-2);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003669 case XML_SCHEMAS_BASE64BINARY:
3670 if (y->type == XML_SCHEMAS_BASE64BINARY) {
3671 if (x->value.base64.total == y->value.base64.total) {
3672 int ret = xmlStrcmp(x->value.base64.str,
3673 y->value.base64.str);
3674 if (ret > 0)
3675 return(1);
3676 else if (ret == 0)
3677 return(0);
3678 }
3679 else if (x->value.base64.total > y->value.base64.total)
3680 return(1);
3681 else
3682 return(-1);
3683 }
3684 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00003685 case XML_SCHEMAS_STRING:
3686 case XML_SCHEMAS_IDREFS:
3687 case XML_SCHEMAS_ENTITIES:
3688 case XML_SCHEMAS_NMTOKENS:
3689 TODO
3690 break;
William M. Brack96d2eff2004-06-30 11:48:47 +00003691 case XML_SCHEMAS_ANYTYPE:
3692 case XML_SCHEMAS_ANYSIMPLETYPE:
3693 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00003694 }
Daniel Veillard5a872412002-05-22 06:40:27 +00003695 return -2;
Daniel Veillard4255d502002-04-16 15:50:10 +00003696}
3697
3698/**
Daniel Veillardc4c21552003-03-29 10:53:38 +00003699 * xmlSchemaNormLen:
3700 * @value: a string
3701 *
3702 * Computes the UTF8 length of the normalized value of the string
3703 *
3704 * Returns the length or -1 in case of error.
3705 */
3706static int
3707xmlSchemaNormLen(const xmlChar *value) {
3708 const xmlChar *utf;
3709 int ret = 0;
3710
3711 if (value == NULL)
3712 return(-1);
3713 utf = value;
William M. Brack76e95df2003-10-18 16:20:14 +00003714 while (IS_BLANK_CH(*utf)) utf++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003715 while (*utf != 0) {
3716 if (utf[0] & 0x80) {
3717 if ((utf[1] & 0xc0) != 0x80)
3718 return(-1);
3719 if ((utf[0] & 0xe0) == 0xe0) {
3720 if ((utf[2] & 0xc0) != 0x80)
3721 return(-1);
3722 if ((utf[0] & 0xf0) == 0xf0) {
3723 if ((utf[0] & 0xf8) != 0xf0 || (utf[3] & 0xc0) != 0x80)
3724 return(-1);
3725 utf += 4;
3726 } else {
3727 utf += 3;
3728 }
3729 } else {
3730 utf += 2;
3731 }
William M. Brack76e95df2003-10-18 16:20:14 +00003732 } else if (IS_BLANK_CH(*utf)) {
3733 while (IS_BLANK_CH(*utf)) utf++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003734 if (*utf == 0)
3735 break;
3736 } else {
3737 utf++;
3738 }
3739 ret++;
3740 }
3741 return(ret);
3742}
3743
Daniel Veillardc0826a72004-08-10 14:17:33 +00003744unsigned long
3745xmlSchemaGetFacetValueAsULong(xmlSchemaFacetPtr facet)
3746{
3747 /*
3748 * TODO: Check if this is a decimal.
3749 */
3750 return ((unsigned long) facet->val->value.decimal.lo);
3751}
3752
Daniel Veillardc4c21552003-03-29 10:53:38 +00003753/**
Daniel Veillard01fa6152004-06-29 17:04:39 +00003754 * xmlSchemaValidateListSimpleTypeFacet:
3755 * @facet: the facet to check
3756 * @value: the lexical repr of the value to validate
3757 * @actualLen: the number of list items
3758 * @expectedLen: the resulting expected number of list items
3759 *
3760 * Checks the value of a list simple type against a facet.
3761 *
3762 * Returns 0 if the value is valid, a positive error code
3763 * number otherwise and -1 in case of an internal error.
3764 */
3765int
3766xmlSchemaValidateListSimpleTypeFacet(xmlSchemaFacetPtr facet,
3767 const xmlChar *value,
3768 unsigned long actualLen,
3769 unsigned long *expectedLen)
3770{
3771 /*
3772 * TODO: Check if this will work with large numbers.
3773 * (compare value.decimal.mi and value.decimal.hi as well?).
3774 */
3775 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
3776 if (actualLen != facet->val->value.decimal.lo) {
Daniel Veillardc0826a72004-08-10 14:17:33 +00003777 if (expectedLen != 0)
3778 *expectedLen = facet->val->value.decimal.lo;
Daniel Veillard01fa6152004-06-29 17:04:39 +00003779 return (XML_SCHEMAV_CVC_LENGTH_VALID);
3780 }
3781 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
3782 if (actualLen < facet->val->value.decimal.lo) {
Daniel Veillardc0826a72004-08-10 14:17:33 +00003783 if (expectedLen != 0)
3784 *expectedLen = facet->val->value.decimal.lo;
Daniel Veillard01fa6152004-06-29 17:04:39 +00003785 return (XML_SCHEMAV_CVC_MINLENGTH_VALID);
3786 }
3787 } else if (facet->type == XML_SCHEMA_FACET_MAXLENGTH) {
3788 if (actualLen > facet->val->value.decimal.lo) {
Daniel Veillardc0826a72004-08-10 14:17:33 +00003789 if (expectedLen != 0)
3790 *expectedLen = facet->val->value.decimal.lo;
Daniel Veillard01fa6152004-06-29 17:04:39 +00003791 return (XML_SCHEMAV_CVC_MAXLENGTH_VALID);
3792 }
3793 } else
3794 /*
3795 * NOTE: That we can pass NULL as xmlSchemaValPtr to
3796 * xmlSchemaValidateFacet, since the remaining facet types
3797 * are: XML_SCHEMA_FACET_PATTERN, XML_SCHEMA_FACET_ENUMERATION.
3798 */
3799 return(xmlSchemaValidateFacet(NULL, facet, value, NULL));
3800 return (0);
3801}
3802
3803/**
Daniel Veillard4255d502002-04-16 15:50:10 +00003804 * xmlSchemaValidateFacet:
Daniel Veillardc0826a72004-08-10 14:17:33 +00003805 * @type: the built-in type
3806 * @facet: the facet to check
3807 * @value: the lexical repr. of the value to be validated
3808 * @val: the precomputed value
3809 * @length: the actual length of the value
3810 *
3811 * Checka a value against a "length", "minLength" and "maxLength"
3812 * facet; sets @length to the computed length of @value.
3813 *
3814 * Returns 0 if the value is valid, a positive error code
3815 * otherwise and -1 in case of an internal or API error.
3816 */
3817int
3818xmlSchemaValidateLengthFacet(xmlSchemaTypePtr type,
3819 xmlSchemaFacetPtr facet,
3820 const xmlChar *value,
3821 xmlSchemaValPtr val,
3822 unsigned long *length)
3823{
3824 unsigned int len = 0;
3825
3826 *length = 0;
3827 if ((facet->type != XML_SCHEMA_FACET_LENGTH) &&
3828 (facet->type != XML_SCHEMA_FACET_MAXLENGTH) &&
3829 (facet->type != XML_SCHEMA_FACET_MINLENGTH))
3830 return (-1);
3831
3832 if ((facet->val == NULL) ||
3833 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
3834 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
3835 (facet->val->value.decimal.frac != 0)) {
3836 return(-1);
3837 }
3838 if ((val != NULL) && (val->type == XML_SCHEMAS_HEXBINARY))
3839 len = val->value.hex.total;
3840 else if ((val != NULL) && (val->type == XML_SCHEMAS_BASE64BINARY))
3841 len = val->value.base64.total;
3842 else {
3843 switch (type->builtInType) {
3844 case XML_SCHEMAS_IDREF:
3845 case XML_SCHEMAS_NORMSTRING:
3846 case XML_SCHEMAS_TOKEN:
3847 case XML_SCHEMAS_LANGUAGE:
3848 case XML_SCHEMAS_NMTOKEN:
3849 case XML_SCHEMAS_NAME:
3850 case XML_SCHEMAS_NCNAME:
3851 case XML_SCHEMAS_ID:
3852 len = xmlSchemaNormLen(value);
3853 break;
3854 case XML_SCHEMAS_STRING:
3855 /*
3856 * FIXME: What exactly to do with anyURI?
3857 */
3858 case XML_SCHEMAS_ANYURI:
3859 if (value != NULL)
3860 len = xmlUTF8Strlen(value);
3861 break;
3862 default:
3863 TODO
3864 }
3865 }
3866 *length = (unsigned long) len;
3867 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
3868 if (len != facet->val->value.decimal.lo)
3869 return(XML_SCHEMAV_CVC_LENGTH_VALID);
3870 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
3871 if (len < facet->val->value.decimal.lo)
3872 return(XML_SCHEMAV_CVC_MINLENGTH_VALID);
3873 } else {
3874 if (len > facet->val->value.decimal.lo)
3875 return(XML_SCHEMAV_CVC_MAXLENGTH_VALID);
3876 }
3877
3878 return (0);
3879}
3880
3881/**
3882 * xmlSchemaValidateFacet:
Daniel Veillard01c13b52002-12-10 15:19:08 +00003883 * @base: the base type
Daniel Veillard4255d502002-04-16 15:50:10 +00003884 * @facet: the facet to check
3885 * @value: the lexical repr of the value to validate
3886 * @val: the precomputed value
3887 *
3888 * Check a value against a facet condition
3889 *
3890 * Returns 0 if the element is schemas valid, a positive error code
3891 * number otherwise and -1 in case of internal or API error.
3892 */
3893int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00003894xmlSchemaValidateFacet(xmlSchemaTypePtr base ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +00003895 xmlSchemaFacetPtr facet,
Daniel Veillard4255d502002-04-16 15:50:10 +00003896 const xmlChar *value, xmlSchemaValPtr val)
3897{
3898 int ret;
3899
3900 switch (facet->type) {
3901 case XML_SCHEMA_FACET_PATTERN:
3902 ret = xmlRegexpExec(facet->regexp, value);
3903 if (ret == 1)
3904 return(0);
3905 if (ret == 0) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00003906 return(XML_SCHEMAV_CVC_PATTERN_VALID);
Daniel Veillard4255d502002-04-16 15:50:10 +00003907 }
3908 return(ret);
3909 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
3910 ret = xmlSchemaCompareValues(val, facet->val);
3911 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003912 /* TODO error code */
Daniel Veillard4255d502002-04-16 15:50:10 +00003913 return(-1);
3914 }
3915 if (ret == -1)
3916 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00003917 /* error code */
Daniel Veillard01fa6152004-06-29 17:04:39 +00003918 return(XML_SCHEMAV_CVC_MAXEXCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00003919 case XML_SCHEMA_FACET_MAXINCLUSIVE:
3920 ret = xmlSchemaCompareValues(val, facet->val);
3921 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003922 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00003923 return(-1);
3924 }
3925 if ((ret == -1) || (ret == 0))
3926 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00003927 /* error code */
Daniel Veillard01fa6152004-06-29 17:04:39 +00003928 return(XML_SCHEMAV_CVC_MAXINCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00003929 case XML_SCHEMA_FACET_MINEXCLUSIVE:
3930 ret = xmlSchemaCompareValues(val, facet->val);
3931 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003932 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00003933 return(-1);
3934 }
3935 if (ret == 1)
3936 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00003937 /* error code */
Daniel Veillard01fa6152004-06-29 17:04:39 +00003938 return(XML_SCHEMAV_CVC_MINEXCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00003939 case XML_SCHEMA_FACET_MININCLUSIVE:
3940 ret = xmlSchemaCompareValues(val, facet->val);
3941 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003942 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00003943 return(-1);
3944 }
3945 if ((ret == 1) || (ret == 0))
3946 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00003947 /* error code */
Daniel Veillard01fa6152004-06-29 17:04:39 +00003948 return(XML_SCHEMAV_CVC_MININCLUSIVE_VALID);
Daniel Veillard8651f532002-04-17 09:06:27 +00003949 case XML_SCHEMA_FACET_WHITESPACE:
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003950 /* TODO whitespaces */
Daniel Veillard01fa6152004-06-29 17:04:39 +00003951 /*
3952 * NOTE: Whitespace should be handled to normalize
3953 * the value to be validated against a the facets;
3954 * not to normalize the value in-between.
3955 */
Daniel Veillard8651f532002-04-17 09:06:27 +00003956 return(0);
Daniel Veillard88c58912002-04-23 07:12:20 +00003957 case XML_SCHEMA_FACET_ENUMERATION:
3958 if ((facet->value != NULL) &&
3959 (xmlStrEqual(facet->value, value)))
3960 return(0);
Daniel Veillard01fa6152004-06-29 17:04:39 +00003961 return(XML_SCHEMAV_CVC_ENUMERATION_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003962 case XML_SCHEMA_FACET_LENGTH:
3963 case XML_SCHEMA_FACET_MAXLENGTH:
3964 case XML_SCHEMA_FACET_MINLENGTH: {
3965 unsigned int len = 0;
3966
3967 if ((facet->val == NULL) ||
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003968 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
3969 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003970 (facet->val->value.decimal.frac != 0)) {
3971 return(-1);
3972 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00003973 if ((val != NULL) && (val->type == XML_SCHEMAS_HEXBINARY))
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00003974 len = val->value.hex.total;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003975 else if ((val != NULL) && (val->type == XML_SCHEMAS_BASE64BINARY))
3976 len = val->value.base64.total;
3977 else {
Daniel Veillard01fa6152004-06-29 17:04:39 +00003978 switch (base->builtInType) {
Daniel Veillard560c2a42003-07-06 21:13:49 +00003979 case XML_SCHEMAS_IDREF:
3980 case XML_SCHEMAS_NORMSTRING:
3981 case XML_SCHEMAS_TOKEN:
3982 case XML_SCHEMAS_LANGUAGE:
3983 case XML_SCHEMAS_NMTOKEN:
3984 case XML_SCHEMAS_NAME:
3985 case XML_SCHEMAS_NCNAME:
3986 case XML_SCHEMAS_ID:
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00003987 len = xmlSchemaNormLen(value);
3988 break;
Daniel Veillard560c2a42003-07-06 21:13:49 +00003989 case XML_SCHEMAS_STRING:
Daniel Veillard01fa6152004-06-29 17:04:39 +00003990 /*
3991 * FIXME: What exactly to do with anyURI?
3992 */
3993 case XML_SCHEMAS_ANYURI:
William M. Brackfbf2c5e2004-02-03 17:55:56 +00003994 if (value != NULL)
3995 len = xmlUTF8Strlen(value);
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00003996 break;
Daniel Veillard560c2a42003-07-06 21:13:49 +00003997 default:
3998 TODO
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00003999 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004000 }
4001 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004002 if (len != facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004003 return(XML_SCHEMAV_CVC_LENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004004 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004005 if (len < facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004006 return(XML_SCHEMAV_CVC_MINLENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004007 } else {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004008 if (len > facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004009 return(XML_SCHEMAV_CVC_MAXLENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004010 }
4011 break;
4012 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00004013 case XML_SCHEMA_FACET_TOTALDIGITS:
4014 case XML_SCHEMA_FACET_FRACTIONDIGITS:
4015
4016 if ((facet->val == NULL) ||
4017 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
4018 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
4019 (facet->val->value.decimal.frac != 0)) {
4020 return(-1);
4021 }
4022 if ((val == NULL) ||
4023 ((val->type != XML_SCHEMAS_DECIMAL) &&
4024 (val->type != XML_SCHEMAS_INTEGER) &&
4025 (val->type != XML_SCHEMAS_NPINTEGER) &&
4026 (val->type != XML_SCHEMAS_NINTEGER) &&
4027 (val->type != XML_SCHEMAS_NNINTEGER) &&
4028 (val->type != XML_SCHEMAS_PINTEGER) &&
4029 (val->type != XML_SCHEMAS_INT) &&
4030 (val->type != XML_SCHEMAS_UINT) &&
4031 (val->type != XML_SCHEMAS_LONG) &&
4032 (val->type != XML_SCHEMAS_ULONG) &&
4033 (val->type != XML_SCHEMAS_SHORT) &&
4034 (val->type != XML_SCHEMAS_USHORT) &&
4035 (val->type != XML_SCHEMAS_BYTE) &&
4036 (val->type != XML_SCHEMAS_UBYTE))) {
4037 return(-1);
4038 }
4039 if (facet->type == XML_SCHEMA_FACET_TOTALDIGITS) {
4040 if (val->value.decimal.total > facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004041 return(XML_SCHEMAV_CVC_TOTALDIGITS_VALID);
Daniel Veillard560c2a42003-07-06 21:13:49 +00004042
4043 } else if (facet->type == XML_SCHEMA_FACET_FRACTIONDIGITS) {
4044 if (val->value.decimal.frac > facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004045 return(XML_SCHEMAV_CVC_FRACTIONDIGITS_VALID);
Daniel Veillard560c2a42003-07-06 21:13:49 +00004046 }
4047 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00004048 default:
4049 TODO
4050 }
4051 return(0);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00004052
Daniel Veillard4255d502002-04-16 15:50:10 +00004053}
4054
4055#endif /* LIBXML_SCHEMAS_ENABLED */