blob: 7214adb924fa58864faa11330557db3f7ce9f8aa [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;
253 }
254
Daniel Veillard4255d502002-04-16 15:50:10 +0000255 xmlHashAddEntry2(xmlSchemaTypesBank, ret->name,
256 XML_SCHEMAS_NAMESPACE_NAME, ret);
Daniel Veillard01fa6152004-06-29 17:04:39 +0000257 ret->builtInType = type;
Daniel Veillard4255d502002-04-16 15:50:10 +0000258 return(ret);
259}
260
261/*
262 * xmlSchemaInitTypes:
263 *
264 * Initialize the default XML Schemas type library
265 */
266void
Daniel Veillard6560a422003-03-27 21:25:38 +0000267xmlSchemaInitTypes(void)
268{
Daniel Veillard4255d502002-04-16 15:50:10 +0000269 if (xmlSchemaTypesInitialized != 0)
Daniel Veillard6560a422003-03-27 21:25:38 +0000270 return;
Daniel Veillard4255d502002-04-16 15:50:10 +0000271 xmlSchemaTypesBank = xmlHashCreate(40);
Daniel Veillard6560a422003-03-27 21:25:38 +0000272
Daniel Veillard01fa6152004-06-29 17:04:39 +0000273
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000274 /*
Daniel Veillard01fa6152004-06-29 17:04:39 +0000275 * 3.4.7 Built-in Complex Type Definition
276 */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000277 xmlSchemaTypeAnyTypeDef = xmlSchemaInitBasicType("anyType",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000278 XML_SCHEMAS_UNKNOWN,
279 NULL);
280 xmlSchemaTypeAnyTypeDef->baseType = xmlSchemaTypeAnyTypeDef;
281 xmlSchemaTypeAnyTypeDef->contentType = XML_SCHEMA_CONTENT_MIXED;
282 {
283 xmlSchemaWildcardPtr wild;
284
285 wild = (xmlSchemaWildcardPtr) xmlMalloc(sizeof(xmlSchemaWildcard));
286 if (wild == NULL) {
287 xmlSchemaTypeErrMemory(NULL, "could not create a wildcard on anyType");
288 return;
289 }
290 memset(wild, 0, sizeof(xmlSchemaWildcard));
291 wild->any = 1;
292 wild->processContents = XML_SCHEMAS_ANY_LAX;
293 wild->minOccurs = 1;
294 wild->maxOccurs = 1;
295 xmlSchemaTypeAnyTypeDef->attributeWildcard = wild;
296 }
297 xmlSchemaTypeAnySimpleTypeDef = xmlSchemaInitBasicType("anySimpleType",
298 XML_SCHEMAS_UNKNOWN,
299 xmlSchemaTypeAnyTypeDef);
300 /*
301 * primitive datatypes
302 */
303 xmlSchemaTypeStringDef = xmlSchemaInitBasicType("string",
304 XML_SCHEMAS_STRING,
305 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000306 xmlSchemaTypeDecimalDef = xmlSchemaInitBasicType("decimal",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000307 XML_SCHEMAS_DECIMAL,
308 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000309 xmlSchemaTypeDateDef = xmlSchemaInitBasicType("date",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000310 XML_SCHEMAS_DATE,
311 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000312 xmlSchemaTypeDatetimeDef = xmlSchemaInitBasicType("dateTime",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000313 XML_SCHEMAS_DATETIME,
314 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000315 xmlSchemaTypeTimeDef = xmlSchemaInitBasicType("time",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000316 XML_SCHEMAS_TIME,
317 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000318 xmlSchemaTypeGYearDef = xmlSchemaInitBasicType("gYear",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000319 XML_SCHEMAS_GYEAR,
320 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000321 xmlSchemaTypeGYearMonthDef = xmlSchemaInitBasicType("gYearMonth",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000322 XML_SCHEMAS_GYEARMONTH,
323 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000324 xmlSchemaTypeGMonthDef = xmlSchemaInitBasicType("gMonth",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000325 XML_SCHEMAS_GMONTH,
326 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000327 xmlSchemaTypeGMonthDayDef = xmlSchemaInitBasicType("gMonthDay",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000328 XML_SCHEMAS_GMONTHDAY,
329 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000330 xmlSchemaTypeGDayDef = xmlSchemaInitBasicType("gDay",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000331 XML_SCHEMAS_GDAY,
332 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000333 xmlSchemaTypeDurationDef = xmlSchemaInitBasicType("duration",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000334 XML_SCHEMAS_DURATION,
335 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000336 xmlSchemaTypeFloatDef = xmlSchemaInitBasicType("float",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000337 XML_SCHEMAS_FLOAT,
338 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000339 xmlSchemaTypeDoubleDef = xmlSchemaInitBasicType("double",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000340 XML_SCHEMAS_DOUBLE,
341 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000342 xmlSchemaTypeBooleanDef = xmlSchemaInitBasicType("boolean",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000343 XML_SCHEMAS_BOOLEAN,
344 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000345 xmlSchemaTypeAnyURIDef = xmlSchemaInitBasicType("anyURI",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000346 XML_SCHEMAS_ANYURI,
347 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard560c2a42003-07-06 21:13:49 +0000348 xmlSchemaTypeHexBinaryDef = xmlSchemaInitBasicType("hexBinary",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000349 XML_SCHEMAS_HEXBINARY,
350 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard1ac24d32003-08-27 14:15:15 +0000351 xmlSchemaTypeBase64BinaryDef
Daniel Veillard01fa6152004-06-29 17:04:39 +0000352 = xmlSchemaInitBasicType("base64Binary", XML_SCHEMAS_BASE64BINARY,
353 xmlSchemaTypeAnySimpleTypeDef);
354 xmlSchemaTypeNotationDef = xmlSchemaInitBasicType("NOTATION",
355 XML_SCHEMAS_NOTATION,
356 xmlSchemaTypeAnySimpleTypeDef);
357 xmlSchemaTypeQNameDef = xmlSchemaInitBasicType("QName",
358 XML_SCHEMAS_QNAME,
359 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard4255d502002-04-16 15:50:10 +0000360
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000361 /*
362 * derived datatypes
363 */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000364 xmlSchemaTypeIntegerDef = xmlSchemaInitBasicType("integer",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000365 XML_SCHEMAS_INTEGER,
366 xmlSchemaTypeDecimalDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000367 xmlSchemaTypeNonPositiveIntegerDef =
368 xmlSchemaInitBasicType("nonPositiveInteger",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000369 XML_SCHEMAS_NPINTEGER,
370 xmlSchemaTypeIntegerDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000371 xmlSchemaTypeNegativeIntegerDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000372 xmlSchemaInitBasicType("negativeInteger", XML_SCHEMAS_NINTEGER,
373 xmlSchemaTypeNonPositiveIntegerDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000374 xmlSchemaTypeLongDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000375 xmlSchemaInitBasicType("long", XML_SCHEMAS_LONG,
376 xmlSchemaTypeIntegerDef);
377 xmlSchemaTypeIntDef = xmlSchemaInitBasicType("int", XML_SCHEMAS_INT,
378 xmlSchemaTypeLongDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000379 xmlSchemaTypeShortDef = xmlSchemaInitBasicType("short",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000380 XML_SCHEMAS_SHORT,
381 xmlSchemaTypeIntDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000382 xmlSchemaTypeByteDef = xmlSchemaInitBasicType("byte",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000383 XML_SCHEMAS_BYTE,
384 xmlSchemaTypeShortDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000385 xmlSchemaTypeNonNegativeIntegerDef =
386 xmlSchemaInitBasicType("nonNegativeInteger",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000387 XML_SCHEMAS_NNINTEGER,
388 xmlSchemaTypeIntegerDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000389 xmlSchemaTypeUnsignedLongDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000390 xmlSchemaInitBasicType("unsignedLong", XML_SCHEMAS_ULONG,
391 xmlSchemaTypeNonNegativeIntegerDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000392 xmlSchemaTypeUnsignedIntDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000393 xmlSchemaInitBasicType("unsignedInt", XML_SCHEMAS_UINT,
394 xmlSchemaTypeUnsignedLongDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000395 xmlSchemaTypeUnsignedShortDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000396 xmlSchemaInitBasicType("unsignedShort", XML_SCHEMAS_USHORT,
397 xmlSchemaTypeUnsignedIntDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000398 xmlSchemaTypeUnsignedByteDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000399 xmlSchemaInitBasicType("unsignedByte", XML_SCHEMAS_UBYTE,
400 xmlSchemaTypeUnsignedShortDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000401 xmlSchemaTypePositiveIntegerDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000402 xmlSchemaInitBasicType("positiveInteger", XML_SCHEMAS_PINTEGER,
403 xmlSchemaTypeNonNegativeIntegerDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000404 xmlSchemaTypeNormStringDef = xmlSchemaInitBasicType("normalizedString",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000405 XML_SCHEMAS_NORMSTRING,
406 xmlSchemaTypeStringDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000407 xmlSchemaTypeTokenDef = xmlSchemaInitBasicType("token",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000408 XML_SCHEMAS_TOKEN,
409 xmlSchemaTypeNormStringDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000410 xmlSchemaTypeLanguageDef = xmlSchemaInitBasicType("language",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000411 XML_SCHEMAS_LANGUAGE,
412 xmlSchemaTypeTokenDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000413 xmlSchemaTypeNameDef = xmlSchemaInitBasicType("Name",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000414 XML_SCHEMAS_NAME,
415 xmlSchemaTypeTokenDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000416 xmlSchemaTypeNmtokenDef = xmlSchemaInitBasicType("NMTOKEN",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000417 XML_SCHEMAS_NMTOKEN,
418 xmlSchemaTypeTokenDef);
419 xmlSchemaTypeNCNameDef = xmlSchemaInitBasicType("NCName",
420 XML_SCHEMAS_NCNAME,
421 xmlSchemaTypeNameDef);
422 xmlSchemaTypeIdDef = xmlSchemaInitBasicType("ID", XML_SCHEMAS_ID,
423 xmlSchemaTypeNCNameDef);
424 xmlSchemaTypeIdrefDef = xmlSchemaInitBasicType("IDREF",
425 XML_SCHEMAS_IDREF,
426 xmlSchemaTypeNCNameDef);
427 xmlSchemaTypeIdrefsDef = xmlSchemaInitBasicType("IDREFS",
428 XML_SCHEMAS_IDREFS,
429 xmlSchemaTypeIdrefDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000430 xmlSchemaTypeNmtokensDef = xmlSchemaInitBasicType("NMTOKENS",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000431 XML_SCHEMAS_NMTOKENS,
432 xmlSchemaTypeNmtokenDef);
433 xmlSchemaTypeEntityDef = xmlSchemaInitBasicType("ENTITY",
434 XML_SCHEMAS_ENTITY,
435 xmlSchemaTypeNCNameDef);
436 xmlSchemaTypeEntitiesDef = xmlSchemaInitBasicType("ENTITIES",
437 XML_SCHEMAS_ENTITIES,
438 xmlSchemaTypeNCNameDef);
Daniel Veillard4255d502002-04-16 15:50:10 +0000439 xmlSchemaTypesInitialized = 1;
440}
441
442/**
443 * xmlSchemaCleanupTypes:
444 *
445 * Cleanup the default XML Schemas type library
446 */
447void
448xmlSchemaCleanupTypes(void) {
449 if (xmlSchemaTypesInitialized == 0)
450 return;
Daniel Veillard01fa6152004-06-29 17:04:39 +0000451 xmlSchemaFreeWildcard(xmlSchemaTypeAnyTypeDef->attributeWildcard);
Daniel Veillard4255d502002-04-16 15:50:10 +0000452 xmlHashFree(xmlSchemaTypesBank, (xmlHashDeallocator) xmlSchemaFreeType);
453 xmlSchemaTypesInitialized = 0;
454}
455
456/**
Daniel Veillard01fa6152004-06-29 17:04:39 +0000457 * xmlSchemaGetBuiltInType:
458 * @type: the built-in type
459 * @facetType: the facet type
460 *
461 * Evaluates if a specific facet can be
462 * used in conjunction with a type.
463 *
464 * Returns 1 if the facet can be used with the given built-in type,
465 * 0 otherwise and -1 in case the type is not a built-in type.
466 */
467int
468xmlSchemaIsBuiltInTypeFacet(xmlSchemaTypePtr type, int facetType)
469{
470 if (type->type != XML_SCHEMA_TYPE_BASIC)
471 return (-1);
472 switch (type->builtInType) {
473 case XML_SCHEMAS_BOOLEAN:
474 if ((facetType == XML_SCHEMA_FACET_PATTERN) ||
475 (facetType == XML_SCHEMA_FACET_WHITESPACE))
476 return (1);
477 else
478 return (0);
479 case XML_SCHEMAS_STRING:
480 case XML_SCHEMAS_NOTATION:
481 case XML_SCHEMAS_QNAME:
482 case XML_SCHEMAS_ANYURI:
483 case XML_SCHEMAS_BASE64BINARY:
484 case XML_SCHEMAS_HEXBINARY:
485 if ((facetType == XML_SCHEMA_FACET_LENGTH) ||
486 (facetType == XML_SCHEMA_FACET_MINLENGTH) ||
487 (facetType == XML_SCHEMA_FACET_MAXLENGTH) ||
488 (facetType == XML_SCHEMA_FACET_PATTERN) ||
489 (facetType == XML_SCHEMA_FACET_ENUMERATION) ||
490 (facetType == XML_SCHEMA_FACET_WHITESPACE))
491 return (1);
492 else
493 return (0);
494 case XML_SCHEMAS_DECIMAL:
495 if ((facetType == XML_SCHEMA_FACET_TOTALDIGITS) ||
496 (facetType == XML_SCHEMA_FACET_FRACTIONDIGITS) ||
497 (facetType == XML_SCHEMA_FACET_PATTERN) ||
498 (facetType == XML_SCHEMA_FACET_WHITESPACE) ||
499 (facetType == XML_SCHEMA_FACET_ENUMERATION) ||
500 (facetType == XML_SCHEMA_FACET_MAXINCLUSIVE) ||
501 (facetType == XML_SCHEMA_FACET_MAXEXCLUSIVE) ||
502 (facetType == XML_SCHEMA_FACET_MININCLUSIVE) ||
503 (facetType == XML_SCHEMA_FACET_MINEXCLUSIVE))
504 return (1);
505 else
506 return (0);
507 case XML_SCHEMAS_TIME:
508 case XML_SCHEMAS_GDAY:
509 case XML_SCHEMAS_GMONTH:
510 case XML_SCHEMAS_GMONTHDAY:
511 case XML_SCHEMAS_GYEAR:
512 case XML_SCHEMAS_GYEARMONTH:
513 case XML_SCHEMAS_DATE:
514 case XML_SCHEMAS_DATETIME:
515 case XML_SCHEMAS_DURATION:
516 case XML_SCHEMAS_FLOAT:
517 case XML_SCHEMAS_DOUBLE:
518 if ((facetType == XML_SCHEMA_FACET_PATTERN) ||
519 (facetType == XML_SCHEMA_FACET_ENUMERATION) ||
520 (facetType == XML_SCHEMA_FACET_WHITESPACE) ||
521 (facetType == XML_SCHEMA_FACET_MAXINCLUSIVE) ||
522 (facetType == XML_SCHEMA_FACET_MAXEXCLUSIVE) ||
523 (facetType == XML_SCHEMA_FACET_MININCLUSIVE) ||
524 (facetType == XML_SCHEMA_FACET_MINEXCLUSIVE))
525 return (1);
526 else
527 return (0);
528 default:
529 return (0);
530 }
531 return (0);
532}
533
534/**
535 * xmlSchemaGetBuiltInType:
536 * @type: the type of the built in type
537 *
538 * Gives you the type struct for a built-in
539 * type by its type id.
540 *
541 * Returns the type if found, NULL otherwise.
542 */
543xmlSchemaTypePtr
544xmlSchemaGetBuiltInType(xmlSchemaValType type)
545{
546 if (xmlSchemaTypesInitialized == 0)
547 xmlSchemaInitTypes();
548 switch (type) {
549
550 case XML_SCHEMAS_ANYSIMPLETYPE:
551 return (xmlSchemaTypeAnySimpleTypeDef);
552 case XML_SCHEMAS_STRING:
553 return (xmlSchemaTypeStringDef);
554 case XML_SCHEMAS_NORMSTRING:
555 return (xmlSchemaTypeNormStringDef);
556 case XML_SCHEMAS_DECIMAL:
557 return (xmlSchemaTypeDecimalDef);
558 case XML_SCHEMAS_TIME:
559 return (xmlSchemaTypeTimeDef);
560 case XML_SCHEMAS_GDAY:
561 return (xmlSchemaTypeGDayDef);
562 case XML_SCHEMAS_GMONTH:
563 return (xmlSchemaTypeGMonthDef);
564 case XML_SCHEMAS_GMONTHDAY:
565 return (xmlSchemaTypeGMonthDayDef);
566 case XML_SCHEMAS_GYEAR:
567 return (xmlSchemaTypeGYearDef);
568 case XML_SCHEMAS_GYEARMONTH:
569 return (xmlSchemaTypeGYearMonthDef);
570 case XML_SCHEMAS_DATE:
571 return (xmlSchemaTypeDateDef);
572 case XML_SCHEMAS_DATETIME:
573 return (xmlSchemaTypeDatetimeDef);
574 case XML_SCHEMAS_DURATION:
575 return (xmlSchemaTypeDurationDef);
576 case XML_SCHEMAS_FLOAT:
577 return (xmlSchemaTypeFloatDef);
578 case XML_SCHEMAS_DOUBLE:
579 return (xmlSchemaTypeDoubleDef);
580 case XML_SCHEMAS_BOOLEAN:
581 return (xmlSchemaTypeBooleanDef);
582 case XML_SCHEMAS_TOKEN:
583 return (xmlSchemaTypeTokenDef);
584 case XML_SCHEMAS_LANGUAGE:
585 return (xmlSchemaTypeLanguageDef);
586 case XML_SCHEMAS_NMTOKEN:
587 return (xmlSchemaTypeNmtokenDef);
588 case XML_SCHEMAS_NMTOKENS:
589 return (xmlSchemaTypeNmtokensDef);
590 case XML_SCHEMAS_NAME:
591 return (xmlSchemaTypeNameDef);
592 case XML_SCHEMAS_QNAME:
593 return (xmlSchemaTypeQNameDef);
594 case XML_SCHEMAS_NCNAME:
595 return (xmlSchemaTypeNCNameDef);
596 case XML_SCHEMAS_ID:
597 return (xmlSchemaTypeIdDef);
598 case XML_SCHEMAS_IDREF:
599 return (xmlSchemaTypeIdrefDef);
600 case XML_SCHEMAS_IDREFS:
601 return (xmlSchemaTypeIdrefsDef);
602 case XML_SCHEMAS_ENTITY:
603 return (xmlSchemaTypeEntityDef);
604 case XML_SCHEMAS_ENTITIES:
605 return (xmlSchemaTypeEntitiesDef);
606 case XML_SCHEMAS_NOTATION:
607 return (xmlSchemaTypeNotationDef);
608 case XML_SCHEMAS_ANYURI:
609 return (xmlSchemaTypeAnyURIDef);
610 case XML_SCHEMAS_INTEGER:
611 return (xmlSchemaTypeIntegerDef);
612 case XML_SCHEMAS_NPINTEGER:
613 return (xmlSchemaTypeNonPositiveIntegerDef);
614 case XML_SCHEMAS_NINTEGER:
615 return (xmlSchemaTypeNegativeIntegerDef);
616 case XML_SCHEMAS_NNINTEGER:
617 return (xmlSchemaTypeNonNegativeIntegerDef);
618 case XML_SCHEMAS_PINTEGER:
619 return (xmlSchemaTypePositiveIntegerDef);
620 case XML_SCHEMAS_INT:
621 return (xmlSchemaTypeIntDef);
622 case XML_SCHEMAS_UINT:
623 return (xmlSchemaTypeUnsignedIntDef);
624 case XML_SCHEMAS_LONG:
625 return (xmlSchemaTypeLongDef);
626 case XML_SCHEMAS_ULONG:
627 return (xmlSchemaTypeUnsignedLongDef);
628 case XML_SCHEMAS_SHORT:
629 return (xmlSchemaTypeShortDef);
630 case XML_SCHEMAS_USHORT:
631 return (xmlSchemaTypeUnsignedShortDef);
632 case XML_SCHEMAS_BYTE:
633 return (xmlSchemaTypeByteDef);
634 case XML_SCHEMAS_UBYTE:
635 return (xmlSchemaTypeUnsignedByteDef);
636 case XML_SCHEMAS_HEXBINARY:
637 return (xmlSchemaTypeHexBinaryDef);
638 case XML_SCHEMAS_BASE64BINARY:
639 return (xmlSchemaTypeBase64BinaryDef);
640 case XML_SCHEMAS_ANYTYPE:
641 return (xmlSchemaTypeAnyTypeDef);
642 default:
643 return (NULL);
644 }
645}
646
647/**
Daniel Veillard4255d502002-04-16 15:50:10 +0000648 * xmlSchemaNewValue:
649 * @type: the value type
650 *
651 * Allocate a new simple type value
652 *
653 * Returns a pointer to the new value or NULL in case of error
654 */
655static xmlSchemaValPtr
656xmlSchemaNewValue(xmlSchemaValType type) {
657 xmlSchemaValPtr value;
658
659 value = (xmlSchemaValPtr) xmlMalloc(sizeof(xmlSchemaVal));
660 if (value == NULL) {
661 return(NULL);
662 }
663 memset(value, 0, sizeof(xmlSchemaVal));
664 value->type = type;
665 return(value);
666}
667
668/**
669 * xmlSchemaFreeValue:
670 * @value: the value to free
671 *
672 * Cleanup the default XML Schemas type library
673 */
674void
675xmlSchemaFreeValue(xmlSchemaValPtr value) {
676 if (value == NULL)
677 return;
Daniel Veillardc4c21552003-03-29 10:53:38 +0000678 switch (value->type) {
679 case XML_SCHEMAS_STRING:
680 case XML_SCHEMAS_NORMSTRING:
681 case XML_SCHEMAS_TOKEN:
682 case XML_SCHEMAS_LANGUAGE:
683 case XML_SCHEMAS_NMTOKEN:
684 case XML_SCHEMAS_NMTOKENS:
685 case XML_SCHEMAS_NAME:
Daniel Veillardc4c21552003-03-29 10:53:38 +0000686 case XML_SCHEMAS_NCNAME:
687 case XML_SCHEMAS_ID:
688 case XML_SCHEMAS_IDREF:
689 case XML_SCHEMAS_IDREFS:
690 case XML_SCHEMAS_ENTITY:
691 case XML_SCHEMAS_ENTITIES:
692 case XML_SCHEMAS_NOTATION:
693 case XML_SCHEMAS_ANYURI:
694 if (value->value.str != NULL)
695 xmlFree(value->value.str);
696 break;
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000697 case XML_SCHEMAS_QNAME:
698 if (value->value.qname.uri != NULL)
699 xmlFree(value->value.qname.uri);
700 if (value->value.qname.name != NULL)
701 xmlFree(value->value.qname.name);
702 break;
Daniel Veillard70bcb0e2003-08-08 14:00:28 +0000703 case XML_SCHEMAS_HEXBINARY:
704 if (value->value.hex.str != NULL)
705 xmlFree(value->value.hex.str);
706 break;
Daniel Veillard1ac24d32003-08-27 14:15:15 +0000707 case XML_SCHEMAS_BASE64BINARY:
708 if (value->value.base64.str != NULL)
709 xmlFree(value->value.base64.str);
710 break;
Daniel Veillardc4c21552003-03-29 10:53:38 +0000711 default:
712 break;
713 }
Daniel Veillard4255d502002-04-16 15:50:10 +0000714 xmlFree(value);
715}
716
717/**
718 * xmlSchemaGetPredefinedType:
719 * @name: the type name
720 * @ns: the URI of the namespace usually "http://www.w3.org/2001/XMLSchema"
721 *
722 * Lookup a type in the default XML Schemas type library
723 *
724 * Returns the type if found, NULL otherwise
725 */
726xmlSchemaTypePtr
727xmlSchemaGetPredefinedType(const xmlChar *name, const xmlChar *ns) {
728 if (xmlSchemaTypesInitialized == 0)
729 xmlSchemaInitTypes();
730 if (name == NULL)
731 return(NULL);
732 return((xmlSchemaTypePtr) xmlHashLookup2(xmlSchemaTypesBank, name, ns));
733}
Daniel Veillard070803b2002-05-03 07:29:38 +0000734
Daniel Veillard01fa6152004-06-29 17:04:39 +0000735/**
736 * xmlSchemaGetBuiltInListSimpleTypeItemType:
737 * @type: the built-in simple type.
738 *
739 * Returns the item type of @type as defined by the built-in datatype
740 * hierarchy of XML Schema Part 2: Datatypes, or NULL in case of an error.
741 */
742xmlSchemaTypePtr
743xmlSchemaGetBuiltInListSimpleTypeItemType(xmlSchemaTypePtr type)
744{
745 if (type->type != XML_SCHEMA_TYPE_BASIC)
746 return (NULL);
747 switch (type->builtInType) {
748 case XML_SCHEMAS_NMTOKENS:
749 return (xmlSchemaTypeNmtokenDef );
750 case XML_SCHEMAS_IDREFS:
751 return (xmlSchemaTypeIdrefDef);
752 case XML_SCHEMAS_ENTITIES:
753 return (xmlSchemaTypeEntityDef);
754 default:
755 return (NULL);
756 }
757}
758
Daniel Veillard070803b2002-05-03 07:29:38 +0000759/****************************************************************
760 * *
761 * Convenience macros and functions *
762 * *
763 ****************************************************************/
764
765#define IS_TZO_CHAR(c) \
766 ((c == 0) || (c == 'Z') || (c == '+') || (c == '-'))
767
768#define VALID_YEAR(yr) (yr != 0)
769#define VALID_MONTH(mon) ((mon >= 1) && (mon <= 12))
770/* VALID_DAY should only be used when month is unknown */
771#define VALID_DAY(day) ((day >= 1) && (day <= 31))
772#define VALID_HOUR(hr) ((hr >= 0) && (hr <= 23))
773#define VALID_MIN(min) ((min >= 0) && (min <= 59))
774#define VALID_SEC(sec) ((sec >= 0) && (sec < 60))
775#define VALID_TZO(tzo) ((tzo > -1440) && (tzo < 1440))
776#define IS_LEAP(y) \
777 (((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0))
778
Daniel Veillardebe25d42004-03-25 09:35:49 +0000779static const unsigned int daysInMonth[12] =
Daniel Veillard070803b2002-05-03 07:29:38 +0000780 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
Daniel Veillardebe25d42004-03-25 09:35:49 +0000781static const unsigned int daysInMonthLeap[12] =
Daniel Veillard070803b2002-05-03 07:29:38 +0000782 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
783
Daniel Veillard5a872412002-05-22 06:40:27 +0000784#define MAX_DAYINMONTH(yr,mon) \
785 (IS_LEAP(yr) ? daysInMonthLeap[mon - 1] : daysInMonth[mon - 1])
786
Daniel Veillard070803b2002-05-03 07:29:38 +0000787#define VALID_MDAY(dt) \
788 (IS_LEAP(dt->year) ? \
789 (dt->day <= daysInMonthLeap[dt->mon - 1]) : \
790 (dt->day <= daysInMonth[dt->mon - 1]))
791
792#define VALID_DATE(dt) \
793 (VALID_YEAR(dt->year) && VALID_MONTH(dt->mon) && VALID_MDAY(dt))
794
795#define VALID_TIME(dt) \
796 (VALID_HOUR(dt->hour) && VALID_MIN(dt->min) && \
797 VALID_SEC(dt->sec) && VALID_TZO(dt->tzo))
798
799#define VALID_DATETIME(dt) \
800 (VALID_DATE(dt) && VALID_TIME(dt))
801
802#define SECS_PER_MIN (60)
803#define SECS_PER_HOUR (60 * SECS_PER_MIN)
804#define SECS_PER_DAY (24 * SECS_PER_HOUR)
805
Daniel Veillard5a872412002-05-22 06:40:27 +0000806static const long dayInYearByMonth[12] =
807 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
808static const long dayInLeapYearByMonth[12] =
809 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 };
810
811#define DAY_IN_YEAR(day, month, year) \
812 ((IS_LEAP(year) ? \
813 dayInLeapYearByMonth[month - 1] : \
814 dayInYearByMonth[month - 1]) + day)
815
816#ifdef DEBUG
817#define DEBUG_DATE(dt) \
818 xmlGenericError(xmlGenericErrorContext, \
819 "type=%o %04ld-%02u-%02uT%02u:%02u:%03f", \
820 dt->type,dt->value.date.year,dt->value.date.mon, \
821 dt->value.date.day,dt->value.date.hour,dt->value.date.min, \
822 dt->value.date.sec); \
823 if (dt->value.date.tz_flag) \
824 if (dt->value.date.tzo != 0) \
825 xmlGenericError(xmlGenericErrorContext, \
826 "%+05d\n",dt->value.date.tzo); \
827 else \
828 xmlGenericError(xmlGenericErrorContext, "Z\n"); \
829 else \
830 xmlGenericError(xmlGenericErrorContext,"\n")
831#else
832#define DEBUG_DATE(dt)
833#endif
834
Daniel Veillard070803b2002-05-03 07:29:38 +0000835/**
836 * _xmlSchemaParseGYear:
837 * @dt: pointer to a date structure
838 * @str: pointer to the string to analyze
839 *
840 * Parses a xs:gYear without time zone and fills in the appropriate
841 * field of the @dt structure. @str is updated to point just after the
842 * xs:gYear. It is supposed that @dt->year is big enough to contain
843 * the year.
844 *
845 * Returns 0 or the error code
846 */
847static int
848_xmlSchemaParseGYear (xmlSchemaValDatePtr dt, const xmlChar **str) {
849 const xmlChar *cur = *str, *firstChar;
850 int isneg = 0, digcnt = 0;
851
852 if (((*cur < '0') || (*cur > '9')) &&
853 (*cur != '-') && (*cur != '+'))
854 return -1;
855
856 if (*cur == '-') {
857 isneg = 1;
858 cur++;
859 }
860
861 firstChar = cur;
862
863 while ((*cur >= '0') && (*cur <= '9')) {
864 dt->year = dt->year * 10 + (*cur - '0');
865 cur++;
866 digcnt++;
867 }
868
869 /* year must be at least 4 digits (CCYY); over 4
870 * digits cannot have a leading zero. */
871 if ((digcnt < 4) || ((digcnt > 4) && (*firstChar == '0')))
872 return 1;
873
874 if (isneg)
875 dt->year = - dt->year;
876
877 if (!VALID_YEAR(dt->year))
878 return 2;
879
880 *str = cur;
881 return 0;
882}
883
884/**
885 * PARSE_2_DIGITS:
886 * @num: the integer to fill in
887 * @cur: an #xmlChar *
888 * @invalid: an integer
889 *
890 * Parses a 2-digits integer and updates @num with the value. @cur is
891 * updated to point just after the integer.
892 * In case of error, @invalid is set to %TRUE, values of @num and
893 * @cur are undefined.
894 */
895#define PARSE_2_DIGITS(num, cur, invalid) \
896 if ((cur[0] < '0') || (cur[0] > '9') || \
897 (cur[1] < '0') || (cur[1] > '9')) \
898 invalid = 1; \
899 else \
900 num = (cur[0] - '0') * 10 + (cur[1] - '0'); \
901 cur += 2;
902
903/**
904 * PARSE_FLOAT:
905 * @num: the double to fill in
906 * @cur: an #xmlChar *
907 * @invalid: an integer
908 *
909 * Parses a float and updates @num with the value. @cur is
910 * updated to point just after the float. The float must have a
911 * 2-digits integer part and may or may not have a decimal part.
912 * In case of error, @invalid is set to %TRUE, values of @num and
913 * @cur are undefined.
914 */
915#define PARSE_FLOAT(num, cur, invalid) \
916 PARSE_2_DIGITS(num, cur, invalid); \
917 if (!invalid && (*cur == '.')) { \
918 double mult = 1; \
919 cur++; \
920 if ((*cur < '0') || (*cur > '9')) \
921 invalid = 1; \
922 while ((*cur >= '0') && (*cur <= '9')) { \
923 mult /= 10; \
924 num += (*cur - '0') * mult; \
925 cur++; \
926 } \
927 }
928
929/**
930 * _xmlSchemaParseGMonth:
931 * @dt: pointer to a date structure
932 * @str: pointer to the string to analyze
933 *
934 * Parses a xs:gMonth without time zone and fills in the appropriate
935 * field of the @dt structure. @str is updated to point just after the
936 * xs:gMonth.
937 *
938 * Returns 0 or the error code
939 */
940static int
941_xmlSchemaParseGMonth (xmlSchemaValDatePtr dt, const xmlChar **str) {
942 const xmlChar *cur = *str;
943 int ret = 0;
944
945 PARSE_2_DIGITS(dt->mon, cur, ret);
946 if (ret != 0)
947 return ret;
948
949 if (!VALID_MONTH(dt->mon))
950 return 2;
951
952 *str = cur;
953 return 0;
954}
955
956/**
957 * _xmlSchemaParseGDay:
958 * @dt: pointer to a date structure
959 * @str: pointer to the string to analyze
960 *
961 * Parses a xs:gDay without time zone and fills in the appropriate
962 * field of the @dt structure. @str is updated to point just after the
963 * xs:gDay.
964 *
965 * Returns 0 or the error code
966 */
967static int
968_xmlSchemaParseGDay (xmlSchemaValDatePtr dt, const xmlChar **str) {
969 const xmlChar *cur = *str;
970 int ret = 0;
971
972 PARSE_2_DIGITS(dt->day, cur, ret);
973 if (ret != 0)
974 return ret;
975
976 if (!VALID_DAY(dt->day))
977 return 2;
978
979 *str = cur;
980 return 0;
981}
982
983/**
984 * _xmlSchemaParseTime:
985 * @dt: pointer to a date structure
986 * @str: pointer to the string to analyze
987 *
988 * Parses a xs:time without time zone and fills in the appropriate
989 * fields of the @dt structure. @str is updated to point just after the
990 * xs:time.
991 * In case of error, values of @dt fields are undefined.
992 *
993 * Returns 0 or the error code
994 */
995static int
996_xmlSchemaParseTime (xmlSchemaValDatePtr dt, const xmlChar **str) {
997 const xmlChar *cur = *str;
998 unsigned int hour = 0; /* use temp var in case str is not xs:time */
999 int ret = 0;
1000
1001 PARSE_2_DIGITS(hour, cur, ret);
1002 if (ret != 0)
1003 return ret;
1004
1005 if (*cur != ':')
1006 return 1;
1007 cur++;
1008
1009 /* the ':' insures this string is xs:time */
1010 dt->hour = hour;
1011
1012 PARSE_2_DIGITS(dt->min, cur, ret);
1013 if (ret != 0)
1014 return ret;
1015
1016 if (*cur != ':')
1017 return 1;
1018 cur++;
1019
1020 PARSE_FLOAT(dt->sec, cur, ret);
1021 if (ret != 0)
1022 return ret;
1023
1024 if (!VALID_TIME(dt))
1025 return 2;
1026
1027 *str = cur;
1028 return 0;
1029}
1030
1031/**
1032 * _xmlSchemaParseTimeZone:
1033 * @dt: pointer to a date structure
1034 * @str: pointer to the string to analyze
1035 *
1036 * Parses a time zone without time zone and fills in the appropriate
1037 * field of the @dt structure. @str is updated to point just after the
1038 * time zone.
1039 *
1040 * Returns 0 or the error code
1041 */
1042static int
1043_xmlSchemaParseTimeZone (xmlSchemaValDatePtr dt, const xmlChar **str) {
1044 const xmlChar *cur = *str;
1045 int ret = 0;
1046
1047 if (str == NULL)
1048 return -1;
1049
1050 switch (*cur) {
1051 case 0:
1052 dt->tz_flag = 0;
1053 dt->tzo = 0;
1054 break;
1055
1056 case 'Z':
1057 dt->tz_flag = 1;
1058 dt->tzo = 0;
1059 cur++;
1060 break;
1061
1062 case '+':
1063 case '-': {
1064 int isneg = 0, tmp = 0;
1065 isneg = (*cur == '-');
1066
1067 cur++;
1068
1069 PARSE_2_DIGITS(tmp, cur, ret);
1070 if (ret != 0)
1071 return ret;
1072 if (!VALID_HOUR(tmp))
1073 return 2;
1074
1075 if (*cur != ':')
1076 return 1;
1077 cur++;
1078
1079 dt->tzo = tmp * 60;
1080
1081 PARSE_2_DIGITS(tmp, cur, ret);
1082 if (ret != 0)
1083 return ret;
1084 if (!VALID_MIN(tmp))
1085 return 2;
1086
1087 dt->tzo += tmp;
1088 if (isneg)
1089 dt->tzo = - dt->tzo;
1090
1091 if (!VALID_TZO(dt->tzo))
1092 return 2;
1093
Daniel Veillard5a872412002-05-22 06:40:27 +00001094 dt->tz_flag = 1;
Daniel Veillard070803b2002-05-03 07:29:38 +00001095 break;
1096 }
1097 default:
1098 return 1;
1099 }
1100
1101 *str = cur;
1102 return 0;
1103}
1104
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001105/**
1106 * _xmlSchemaBase64Decode:
1107 * @ch: a character
1108 *
1109 * Converts a base64 encoded character to its base 64 value.
1110 *
1111 * Returns 0-63 (value), 64 (pad), or -1 (not recognized)
1112 */
1113static int
1114_xmlSchemaBase64Decode (const xmlChar ch) {
1115 if (('A' <= ch) && (ch <= 'Z')) return ch - 'A';
1116 if (('a' <= ch) && (ch <= 'z')) return ch - 'a' + 26;
1117 if (('0' <= ch) && (ch <= '9')) return ch - '0' + 52;
1118 if ('+' == ch) return 62;
1119 if ('/' == ch) return 63;
1120 if ('=' == ch) return 64;
1121 return -1;
1122}
1123
Daniel Veillard070803b2002-05-03 07:29:38 +00001124/****************************************************************
1125 * *
1126 * XML Schema Dates/Times Datatypes Handling *
1127 * *
1128 ****************************************************************/
1129
1130/**
1131 * PARSE_DIGITS:
1132 * @num: the integer to fill in
1133 * @cur: an #xmlChar *
1134 * @num_type: an integer flag
1135 *
1136 * Parses a digits integer and updates @num with the value. @cur is
1137 * updated to point just after the integer.
1138 * In case of error, @num_type is set to -1, values of @num and
1139 * @cur are undefined.
1140 */
1141#define PARSE_DIGITS(num, cur, num_type) \
1142 if ((*cur < '0') || (*cur > '9')) \
1143 num_type = -1; \
1144 else \
1145 while ((*cur >= '0') && (*cur <= '9')) { \
1146 num = num * 10 + (*cur - '0'); \
1147 cur++; \
1148 }
1149
1150/**
1151 * PARSE_NUM:
1152 * @num: the double to fill in
1153 * @cur: an #xmlChar *
1154 * @num_type: an integer flag
1155 *
1156 * Parses a float or integer and updates @num with the value. @cur is
1157 * updated to point just after the number. If the number is a float,
1158 * then it must have an integer part and a decimal part; @num_type will
1159 * be set to 1. If there is no decimal part, @num_type is set to zero.
1160 * In case of error, @num_type is set to -1, values of @num and
1161 * @cur are undefined.
1162 */
1163#define PARSE_NUM(num, cur, num_type) \
1164 num = 0; \
1165 PARSE_DIGITS(num, cur, num_type); \
1166 if (!num_type && (*cur == '.')) { \
1167 double mult = 1; \
1168 cur++; \
1169 if ((*cur < '0') || (*cur > '9')) \
1170 num_type = -1; \
1171 else \
1172 num_type = 1; \
1173 while ((*cur >= '0') && (*cur <= '9')) { \
1174 mult /= 10; \
1175 num += (*cur - '0') * mult; \
1176 cur++; \
1177 } \
1178 }
1179
1180/**
Daniel Veillard5a872412002-05-22 06:40:27 +00001181 * xmlSchemaValidateDates:
Daniel Veillard455cc072003-03-31 10:13:23 +00001182 * @type: the expected type or XML_SCHEMAS_UNKNOWN
Daniel Veillard070803b2002-05-03 07:29:38 +00001183 * @dateTime: string to analyze
1184 * @val: the return computed value
1185 *
1186 * Check that @dateTime conforms to the lexical space of one of the date types.
1187 * if true a value is computed and returned in @val.
1188 *
1189 * Returns 0 if this validates, a positive error code number otherwise
1190 * and -1 in case of internal or API error.
1191 */
1192static int
Daniel Veillard455cc072003-03-31 10:13:23 +00001193xmlSchemaValidateDates (xmlSchemaValType type,
Daniel Veillard118aed72002-09-24 14:13:13 +00001194 const xmlChar *dateTime, xmlSchemaValPtr *val) {
Daniel Veillard070803b2002-05-03 07:29:38 +00001195 xmlSchemaValPtr dt;
1196 int ret;
1197 const xmlChar *cur = dateTime;
1198
1199#define RETURN_TYPE_IF_VALID(t) \
1200 if (IS_TZO_CHAR(*cur)) { \
1201 ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur); \
1202 if (ret == 0) { \
1203 if (*cur != 0) \
1204 goto error; \
1205 dt->type = t; \
Daniel Veillard455cc072003-03-31 10:13:23 +00001206 goto done; \
Daniel Veillard070803b2002-05-03 07:29:38 +00001207 } \
1208 }
1209
1210 if (dateTime == NULL)
1211 return -1;
1212
1213 if ((*cur != '-') && (*cur < '0') && (*cur > '9'))
1214 return 1;
1215
1216 dt = xmlSchemaNewValue(XML_SCHEMAS_UNKNOWN);
1217 if (dt == NULL)
1218 return -1;
1219
1220 if ((cur[0] == '-') && (cur[1] == '-')) {
1221 /*
1222 * It's an incomplete date (xs:gMonthDay, xs:gMonth or
1223 * xs:gDay)
1224 */
1225 cur += 2;
1226
1227 /* is it an xs:gDay? */
1228 if (*cur == '-') {
Daniel Veillard455cc072003-03-31 10:13:23 +00001229 if (type == XML_SCHEMAS_GMONTH)
1230 goto error;
Daniel Veillard070803b2002-05-03 07:29:38 +00001231 ++cur;
1232 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
1233 if (ret != 0)
1234 goto error;
1235
1236 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GDAY);
1237
1238 goto error;
1239 }
1240
1241 /*
1242 * it should be an xs:gMonthDay or xs:gMonth
1243 */
1244 ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
1245 if (ret != 0)
1246 goto error;
1247
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001248 /*
1249 * a '-' char could indicate this type is xs:gMonthDay or
1250 * a negative time zone offset. Check for xs:gMonthDay first.
1251 * Also the first three char's of a negative tzo (-MM:SS) can
1252 * appear to be a valid day; so even if the day portion
1253 * of the xs:gMonthDay verifies, we must insure it was not
1254 * a tzo.
1255 */
1256 if (*cur == '-') {
1257 const xmlChar *rewnd = cur;
1258 cur++;
Daniel Veillard070803b2002-05-03 07:29:38 +00001259
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001260 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
1261 if ((ret == 0) && ((*cur == 0) || (*cur != ':'))) {
1262
1263 /*
1264 * we can use the VALID_MDAY macro to validate the month
1265 * and day because the leap year test will flag year zero
1266 * as a leap year (even though zero is an invalid year).
1267 */
1268 if (VALID_MDAY((&(dt->value.date)))) {
1269
1270 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTHDAY);
1271
1272 goto error;
1273 }
1274 }
1275
1276 /*
1277 * not xs:gMonthDay so rewind and check if just xs:gMonth
1278 * with an optional time zone.
1279 */
1280 cur = rewnd;
1281 }
1282
1283 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTH);
Daniel Veillard070803b2002-05-03 07:29:38 +00001284
1285 goto error;
1286 }
1287
1288 /*
1289 * It's a right-truncated date or an xs:time.
1290 * Try to parse an xs:time then fallback on right-truncated dates.
1291 */
1292 if ((*cur >= '0') && (*cur <= '9')) {
1293 ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
1294 if (ret == 0) {
1295 /* it's an xs:time */
1296 RETURN_TYPE_IF_VALID(XML_SCHEMAS_TIME);
1297 }
1298 }
1299
1300 /* fallback on date parsing */
1301 cur = dateTime;
1302
1303 ret = _xmlSchemaParseGYear(&(dt->value.date), &cur);
1304 if (ret != 0)
1305 goto error;
1306
1307 /* is it an xs:gYear? */
1308 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEAR);
1309
1310 if (*cur != '-')
1311 goto error;
1312 cur++;
1313
1314 ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
1315 if (ret != 0)
1316 goto error;
1317
1318 /* is it an xs:gYearMonth? */
1319 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEARMONTH);
1320
1321 if (*cur != '-')
1322 goto error;
1323 cur++;
1324
1325 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
1326 if ((ret != 0) || !VALID_DATE((&(dt->value.date))))
1327 goto error;
1328
1329 /* is it an xs:date? */
1330 RETURN_TYPE_IF_VALID(XML_SCHEMAS_DATE);
1331
1332 if (*cur != 'T')
1333 goto error;
1334 cur++;
1335
1336 /* it should be an xs:dateTime */
1337 ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
1338 if (ret != 0)
1339 goto error;
1340
1341 ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur);
1342 if ((ret != 0) || (*cur != 0) || !VALID_DATETIME((&(dt->value.date))))
1343 goto error;
1344
Daniel Veillard455cc072003-03-31 10:13:23 +00001345
Daniel Veillard070803b2002-05-03 07:29:38 +00001346 dt->type = XML_SCHEMAS_DATETIME;
1347
Daniel Veillard455cc072003-03-31 10:13:23 +00001348done:
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001349#if 1
1350 if ((type != XML_SCHEMAS_UNKNOWN) && (type != dt->type))
1351 goto error;
1352#else
1353 /*
1354 * insure the parsed type is equal to or less significant (right
1355 * truncated) than the desired type.
1356 */
1357 if ((type != XML_SCHEMAS_UNKNOWN) && (type != dt->type)) {
1358
1359 /* time only matches time */
1360 if ((type == XML_SCHEMAS_TIME) && (dt->type == XML_SCHEMAS_TIME))
1361 goto error;
1362
1363 if ((type == XML_SCHEMAS_DATETIME) &&
1364 ((dt->type != XML_SCHEMAS_DATE) ||
1365 (dt->type != XML_SCHEMAS_GYEARMONTH) ||
1366 (dt->type != XML_SCHEMAS_GYEAR)))
1367 goto error;
1368
1369 if ((type == XML_SCHEMAS_DATE) &&
1370 ((dt->type != XML_SCHEMAS_GYEAR) ||
1371 (dt->type != XML_SCHEMAS_GYEARMONTH)))
1372 goto error;
1373
1374 if ((type == XML_SCHEMAS_GYEARMONTH) && (dt->type != XML_SCHEMAS_GYEAR))
1375 goto error;
1376
1377 if ((type == XML_SCHEMAS_GMONTHDAY) && (dt->type != XML_SCHEMAS_GMONTH))
1378 goto error;
1379 }
Daniel Veillard455cc072003-03-31 10:13:23 +00001380#endif
1381
Daniel Veillard070803b2002-05-03 07:29:38 +00001382 if (val != NULL)
1383 *val = dt;
Daniel Veillard80b19092003-03-28 13:29:53 +00001384 else
1385 xmlSchemaFreeValue(dt);
Daniel Veillard070803b2002-05-03 07:29:38 +00001386
1387 return 0;
1388
1389error:
1390 if (dt != NULL)
1391 xmlSchemaFreeValue(dt);
1392 return 1;
1393}
1394
1395/**
Daniel Veillard5a872412002-05-22 06:40:27 +00001396 * xmlSchemaValidateDuration:
Daniel Veillard070803b2002-05-03 07:29:38 +00001397 * @type: the predefined type
1398 * @duration: string to analyze
1399 * @val: the return computed value
1400 *
1401 * Check that @duration conforms to the lexical space of the duration type.
1402 * if true a value is computed and returned in @val.
1403 *
1404 * Returns 0 if this validates, a positive error code number otherwise
1405 * and -1 in case of internal or API error.
1406 */
1407static int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00001408xmlSchemaValidateDuration (xmlSchemaTypePtr type ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +00001409 const xmlChar *duration, xmlSchemaValPtr *val) {
Daniel Veillard070803b2002-05-03 07:29:38 +00001410 const xmlChar *cur = duration;
1411 xmlSchemaValPtr dur;
1412 int isneg = 0;
1413 unsigned int seq = 0;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001414 double num;
1415 int num_type = 0; /* -1 = invalid, 0 = int, 1 = floating */
1416 const xmlChar desig[] = {'Y', 'M', 'D', 'H', 'M', 'S'};
1417 const double multi[] = { 0.0, 0.0, 86400.0, 3600.0, 60.0, 1.0, 0.0};
Daniel Veillard070803b2002-05-03 07:29:38 +00001418
1419 if (duration == NULL)
1420 return -1;
1421
1422 if (*cur == '-') {
1423 isneg = 1;
1424 cur++;
1425 }
1426
1427 /* duration must start with 'P' (after sign) */
1428 if (*cur++ != 'P')
1429 return 1;
1430
Daniel Veillard80b19092003-03-28 13:29:53 +00001431 if (*cur == 0)
1432 return 1;
1433
Daniel Veillard070803b2002-05-03 07:29:38 +00001434 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
1435 if (dur == NULL)
1436 return -1;
1437
1438 while (*cur != 0) {
Daniel Veillard070803b2002-05-03 07:29:38 +00001439
1440 /* input string should be empty or invalid date/time item */
1441 if (seq >= sizeof(desig))
1442 goto error;
1443
1444 /* T designator must be present for time items */
1445 if (*cur == 'T') {
1446 if (seq <= 3) {
1447 seq = 3;
1448 cur++;
1449 } else
1450 return 1;
1451 } else if (seq == 3)
1452 goto error;
1453
1454 /* parse the number portion of the item */
1455 PARSE_NUM(num, cur, num_type);
1456
1457 if ((num_type == -1) || (*cur == 0))
1458 goto error;
1459
1460 /* update duration based on item type */
1461 while (seq < sizeof(desig)) {
1462 if (*cur == desig[seq]) {
1463
1464 /* verify numeric type; only seconds can be float */
1465 if ((num_type != 0) && (seq < (sizeof(desig)-1)))
1466 goto error;
1467
1468 switch (seq) {
1469 case 0:
1470 dur->value.dur.mon = (long)num * 12;
1471 break;
1472 case 1:
1473 dur->value.dur.mon += (long)num;
1474 break;
1475 default:
1476 /* convert to seconds using multiplier */
1477 dur->value.dur.sec += num * multi[seq];
1478 seq++;
1479 break;
1480 }
1481
1482 break; /* exit loop */
1483 }
1484 /* no date designators found? */
1485 if (++seq == 3)
1486 goto error;
1487 }
1488 cur++;
1489 }
1490
1491 if (isneg) {
1492 dur->value.dur.mon = -dur->value.dur.mon;
1493 dur->value.dur.day = -dur->value.dur.day;
1494 dur->value.dur.sec = -dur->value.dur.sec;
1495 }
1496
1497 if (val != NULL)
1498 *val = dur;
Daniel Veillard80b19092003-03-28 13:29:53 +00001499 else
1500 xmlSchemaFreeValue(dur);
Daniel Veillard070803b2002-05-03 07:29:38 +00001501
1502 return 0;
1503
1504error:
1505 if (dur != NULL)
1506 xmlSchemaFreeValue(dur);
1507 return 1;
1508}
1509
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001510/**
1511 * xmlSchemaStrip:
1512 * @value: a value
1513 *
1514 * Removes the leading and ending spaces of a string
1515 *
1516 * Returns the new string or NULL if no change was required.
1517 */
1518static xmlChar *
1519xmlSchemaStrip(const xmlChar *value) {
1520 const xmlChar *start = value, *end, *f;
1521
1522 if (value == NULL) return(NULL);
William M. Brack76e95df2003-10-18 16:20:14 +00001523 while ((*start != 0) && (IS_BLANK_CH(*start))) start++;
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001524 end = start;
1525 while (*end != 0) end++;
1526 f = end;
1527 end--;
William M. Brack76e95df2003-10-18 16:20:14 +00001528 while ((end > start) && (IS_BLANK_CH(*end))) end--;
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001529 end++;
1530 if ((start == value) && (f == end)) return(NULL);
1531 return(xmlStrndup(start, end - start));
1532}
Daniel Veillard96a4b252003-02-06 08:22:32 +00001533
1534/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001535 * xmlSchemaCollapseString:
1536 * @value: a value
1537 *
1538 * Removes and normalize white spaces in the string
1539 *
1540 * Returns the new string or NULL if no change was required.
1541 */
Daniel Veillard01fa6152004-06-29 17:04:39 +00001542xmlChar *
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001543xmlSchemaCollapseString(const xmlChar *value) {
1544 const xmlChar *start = value, *end, *f;
1545 xmlChar *g;
1546 int col = 0;
1547
1548 if (value == NULL) return(NULL);
William M. Brack76e95df2003-10-18 16:20:14 +00001549 while ((*start != 0) && (IS_BLANK_CH(*start))) start++;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001550 end = start;
1551 while (*end != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00001552 if ((*end == ' ') && (IS_BLANK_CH(end[1]))) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001553 col = end - start;
1554 break;
1555 } else if ((*end == 0xa) || (*end == 0x9) || (*end == 0xd)) {
1556 col = end - start;
1557 break;
1558 }
1559 end++;
1560 }
1561 if (col == 0) {
1562 f = end;
1563 end--;
William M. Brack76e95df2003-10-18 16:20:14 +00001564 while ((end > start) && (IS_BLANK_CH(*end))) end--;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001565 end++;
1566 if ((start == value) && (f == end)) return(NULL);
1567 return(xmlStrndup(start, end - start));
1568 }
1569 start = xmlStrdup(start);
1570 if (start == NULL) return(NULL);
1571 g = (xmlChar *) (start + col);
1572 end = g;
1573 while (*end != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00001574 if (IS_BLANK_CH(*end)) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001575 end++;
William M. Brack76e95df2003-10-18 16:20:14 +00001576 while (IS_BLANK_CH(*end)) end++;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001577 if (*end != 0)
1578 *g++ = ' ';
1579 } else
1580 *g++ = *end++;
1581 }
1582 *g = 0;
1583 return((xmlChar *) start);
1584}
1585
1586/**
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001587 * xmlSchemaValAtomicListNode:
1588 * @type: the predefined atomic type for a token in the list
1589 * @value: the list value to check
1590 * @ret: the return computed value
1591 * @node: the node containing the value
1592 *
1593 * Check that a value conforms to the lexical space of the predefined
1594 * list type. if true a value is computed and returned in @ret.
1595 *
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001596 * Returns the number of items if this validates, a negative error code
1597 * number otherwise
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001598 */
1599static int
1600xmlSchemaValAtomicListNode(xmlSchemaTypePtr type, const xmlChar *value,
1601 xmlSchemaValPtr *ret, xmlNodePtr node) {
1602 xmlChar *val, *cur, *endval;
1603 int nb_values = 0;
Daniel Veillard580ced82003-03-21 21:22:48 +00001604 int tmp = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001605
1606 if (value == NULL) {
1607 return(-1);
1608 }
1609 val = xmlStrdup(value);
1610 if (val == NULL) {
1611 return(-1);
1612 }
1613 cur = val;
1614 /*
1615 * Split the list
1616 */
William M. Brack76e95df2003-10-18 16:20:14 +00001617 while (IS_BLANK_CH(*cur)) *cur++ = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001618 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00001619 if (IS_BLANK_CH(*cur)) {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001620 *cur = 0;
1621 cur++;
William M. Brack76e95df2003-10-18 16:20:14 +00001622 while (IS_BLANK_CH(*cur)) *cur++ = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001623 } else {
1624 nb_values++;
1625 cur++;
William M. Brack76e95df2003-10-18 16:20:14 +00001626 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001627 }
1628 }
1629 if (nb_values == 0) {
1630 if (ret != NULL) {
1631 TODO
1632 }
1633 xmlFree(val);
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001634 return(nb_values);
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001635 }
1636 endval = cur;
1637 cur = val;
1638 while ((*cur == 0) && (cur != endval)) cur++;
1639 while (cur != endval) {
1640 tmp = xmlSchemaValPredefTypeNode(type, cur, NULL, node);
1641 if (tmp != 0)
1642 break;
1643 while (*cur != 0) cur++;
1644 while ((*cur == 0) && (cur != endval)) cur++;
1645 }
1646 xmlFree(val);
1647 if (ret != NULL) {
1648 TODO
1649 }
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001650 if (tmp == 0)
1651 return(nb_values);
1652 return(-1);
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001653}
1654
1655/**
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001656 * xmlSchemaParseUInt:
1657 * @str: pointer to the string R/W
1658 * @llo: pointer to the low result
1659 * @lmi: pointer to the mid result
1660 * @lhi: pointer to the high result
1661 *
1662 * Parse an unsigned long into 3 fields.
1663 *
1664 * Returns the number of chars parsed or -1 if overflow of the capacity
1665 */
1666static int
1667xmlSchemaParseUInt(const xmlChar **str, unsigned long *llo,
1668 unsigned long *lmi, unsigned long *lhi) {
1669 unsigned long lo = 0, mi = 0, hi = 0;
1670 const xmlChar *tmp, *cur = *str;
1671 int ret = 0, i = 0;
1672
1673 while (*cur == '0') {
1674 ret++;
1675 cur++;
1676 }
1677 tmp = cur;
1678 while ((*tmp != 0) && (*tmp >= '0') && (*tmp <= '9')) {
1679 i++;tmp++;ret++;
1680 }
1681 if (i > 24) {
1682 *str = tmp;
1683 return(-1);
1684 }
1685 while (i > 16) {
1686 hi = hi * 10 + (*cur++ - '0');
1687 i--;
1688 }
1689 while (i > 8) {
1690 mi = mi * 10 + (*cur++ - '0');
1691 i--;
1692 }
1693 while (i > 0) {
1694 lo = lo * 10 + (*cur++ - '0');
1695 i--;
1696 }
1697
1698 *str = cur;
1699 *llo = lo;
1700 *lmi = mi;
1701 *lhi = hi;
1702 return(ret);
1703}
1704
1705/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001706 * xmlSchemaValAtomicType:
1707 * @type: the predefined type
1708 * @value: the value to check
1709 * @val: the return computed value
1710 * @node: the node containing the value
1711 * flags: flags to control the vlidation
1712 *
1713 * Check that a value conforms to the lexical space of the atomic type.
1714 * if true a value is computed and returned in @val.
Daniel Veillard01fa6152004-06-29 17:04:39 +00001715 * This checks the value space for list types as well (IDREFS, NMTOKENS).
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001716 *
1717 * Returns 0 if this validates, a positive error code number otherwise
1718 * and -1 in case of internal or API error.
1719 */
1720static int
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001721xmlSchemaValAtomicType(xmlSchemaTypePtr type, const xmlChar * value,
1722 xmlSchemaValPtr * val, xmlNodePtr node, int flags)
1723{
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001724 xmlSchemaValPtr v;
1725 xmlChar *norm = NULL;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001726 int ret = 0;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001727
1728 if (xmlSchemaTypesInitialized == 0)
Daniel Veillard01fa6152004-06-29 17:04:39 +00001729 xmlSchemaInitTypes();
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001730 if (type == NULL)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001731 return (-1);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001732
1733 if (val != NULL)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001734 *val = NULL;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001735 if ((flags == 0) && (value != NULL)) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00001736 if ((type->builtInType != XML_SCHEMAS_STRING) &&
1737 (type->builtInType != XML_SCHEMAS_NORMSTRING)) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001738 norm = xmlSchemaCollapseString(value);
1739 if (norm != NULL)
1740 value = norm;
1741 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001742 }
1743
Daniel Veillard01fa6152004-06-29 17:04:39 +00001744 switch (type->builtInType) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001745 case XML_SCHEMAS_UNKNOWN:
Daniel Veillard01fa6152004-06-29 17:04:39 +00001746 if (type == xmlSchemaTypeAnySimpleTypeDef)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001747 goto return0;
1748 goto error;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001749 case XML_SCHEMAS_STRING:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001750 goto return0;
Daniel Veillard1516d5b2004-01-22 07:27:45 +00001751 case XML_SCHEMAS_NORMSTRING:{
1752 const xmlChar *cur = value;
1753
1754 while (*cur != 0) {
1755 if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) {
1756 goto return1;
1757 } else {
1758 cur++;
1759 }
1760 }
1761 if (val != NULL) {
1762 v = xmlSchemaNewValue(XML_SCHEMAS_NORMSTRING);
1763 if (v != NULL) {
1764 v->value.str = xmlStrdup(value);
1765 *val = v;
1766 } else {
1767 goto error;
1768 }
1769 }
1770 goto return0;
1771 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001772 case XML_SCHEMAS_DECIMAL:{
1773 const xmlChar *cur = value, *tmp;
1774 unsigned int frac = 0, len, neg = 0;
1775 unsigned long base = 0;
1776
1777 if (cur == NULL)
1778 goto return1;
1779 if (*cur == '+')
1780 cur++;
1781 else if (*cur == '-') {
1782 neg = 1;
1783 cur++;
1784 }
1785 tmp = cur;
1786 while ((*cur >= '0') && (*cur <= '9')) {
1787 base = base * 10 + (*cur - '0');
1788 cur++;
1789 }
1790 len = cur - tmp;
1791 if (*cur == '.') {
1792 cur++;
1793 tmp = cur;
1794 while ((*cur >= '0') && (*cur <= '9')) {
1795 base = base * 10 + (*cur - '0');
1796 cur++;
1797 }
1798 frac = cur - tmp;
1799 }
1800 if (*cur != 0)
1801 goto return1;
1802 if (val != NULL) {
1803 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
1804 if (v != NULL) {
1805 v->value.decimal.lo = base;
1806 v->value.decimal.sign = neg;
1807 v->value.decimal.frac = frac;
1808 v->value.decimal.total = frac + len;
1809 *val = v;
1810 }
1811 }
1812 goto return0;
1813 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001814 case XML_SCHEMAS_TIME:
1815 case XML_SCHEMAS_GDAY:
1816 case XML_SCHEMAS_GMONTH:
1817 case XML_SCHEMAS_GMONTHDAY:
1818 case XML_SCHEMAS_GYEAR:
1819 case XML_SCHEMAS_GYEARMONTH:
1820 case XML_SCHEMAS_DATE:
1821 case XML_SCHEMAS_DATETIME:
Daniel Veillard01fa6152004-06-29 17:04:39 +00001822 ret = xmlSchemaValidateDates(type->builtInType, value, val);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001823 break;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001824 case XML_SCHEMAS_DURATION:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001825 ret = xmlSchemaValidateDuration(type, value, val);
1826 break;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001827 case XML_SCHEMAS_FLOAT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001828 case XML_SCHEMAS_DOUBLE:{
1829 const xmlChar *cur = value;
1830 int neg = 0;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001831
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001832 if (cur == NULL)
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00001833 goto return1;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001834 if ((cur[0] == 'N') && (cur[1] == 'a') && (cur[2] == 'N')) {
1835 cur += 3;
1836 if (*cur != 0)
1837 goto return1;
1838 if (val != NULL) {
1839 if (type == xmlSchemaTypeFloatDef) {
1840 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1841 if (v != NULL) {
1842 v->value.f = (float) xmlXPathNAN;
1843 } else {
1844 xmlSchemaFreeValue(v);
1845 goto error;
1846 }
1847 } else {
1848 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1849 if (v != NULL) {
1850 v->value.d = xmlXPathNAN;
1851 } else {
1852 xmlSchemaFreeValue(v);
1853 goto error;
1854 }
1855 }
1856 *val = v;
1857 }
1858 goto return0;
1859 }
1860 if (*cur == '-') {
1861 neg = 1;
1862 cur++;
1863 }
1864 if ((cur[0] == 'I') && (cur[1] == 'N') && (cur[2] == 'F')) {
1865 cur += 3;
1866 if (*cur != 0)
1867 goto return1;
1868 if (val != NULL) {
1869 if (type == xmlSchemaTypeFloatDef) {
1870 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1871 if (v != NULL) {
1872 if (neg)
1873 v->value.f = (float) xmlXPathNINF;
1874 else
1875 v->value.f = (float) xmlXPathPINF;
1876 } else {
1877 xmlSchemaFreeValue(v);
1878 goto error;
1879 }
1880 } else {
1881 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1882 if (v != NULL) {
1883 if (neg)
1884 v->value.d = xmlXPathNINF;
1885 else
1886 v->value.d = xmlXPathPINF;
1887 } else {
1888 xmlSchemaFreeValue(v);
1889 goto error;
1890 }
1891 }
1892 *val = v;
1893 }
1894 goto return0;
1895 }
1896 if ((neg == 0) && (*cur == '+'))
1897 cur++;
1898 if ((cur[0] == 0) || (cur[0] == '+') || (cur[0] == '-'))
1899 goto return1;
1900 while ((*cur >= '0') && (*cur <= '9')) {
1901 cur++;
1902 }
1903 if (*cur == '.') {
1904 cur++;
1905 while ((*cur >= '0') && (*cur <= '9'))
1906 cur++;
1907 }
1908 if ((*cur == 'e') || (*cur == 'E')) {
1909 cur++;
1910 if ((*cur == '-') || (*cur == '+'))
1911 cur++;
1912 while ((*cur >= '0') && (*cur <= '9'))
1913 cur++;
1914 }
1915 if (*cur != 0)
1916 goto return1;
1917 if (val != NULL) {
1918 if (type == xmlSchemaTypeFloatDef) {
1919 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1920 if (v != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001921 if (sscanf((const char *) value, "%f",
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001922 &(v->value.f)) == 1) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00001923 *val = v;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001924 } else {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001925 xmlSchemaFreeValue(v);
1926 goto return1;
1927 }
1928 } else {
1929 goto error;
1930 }
1931 } else {
1932 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1933 if (v != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001934 if (sscanf((const char *) value, "%lf",
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001935 &(v->value.d)) == 1) {
1936 *val = v;
1937 } else {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001938 xmlSchemaFreeValue(v);
1939 goto return1;
1940 }
1941 } else {
1942 goto error;
1943 }
1944 }
1945 }
1946 goto return0;
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00001947 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001948 case XML_SCHEMAS_BOOLEAN:{
1949 const xmlChar *cur = value;
1950
1951 if ((cur[0] == '0') && (cur[1] == 0))
1952 ret = 0;
1953 else if ((cur[0] == '1') && (cur[1] == 0))
1954 ret = 1;
1955 else if ((cur[0] == 't') && (cur[1] == 'r')
1956 && (cur[2] == 'u') && (cur[3] == 'e')
1957 && (cur[4] == 0))
1958 ret = 1;
1959 else if ((cur[0] == 'f') && (cur[1] == 'a')
1960 && (cur[2] == 'l') && (cur[3] == 's')
1961 && (cur[4] == 'e') && (cur[5] == 0))
1962 ret = 0;
1963 else
1964 goto return1;
1965 if (val != NULL) {
1966 v = xmlSchemaNewValue(XML_SCHEMAS_BOOLEAN);
1967 if (v != NULL) {
1968 v->value.b = ret;
1969 *val = v;
1970 } else {
1971 goto error;
1972 }
1973 }
1974 goto return0;
1975 }
1976 case XML_SCHEMAS_TOKEN:{
1977 const xmlChar *cur = value;
1978
William M. Brack76e95df2003-10-18 16:20:14 +00001979 if (IS_BLANK_CH(*cur))
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001980 goto return1;
1981
1982 while (*cur != 0) {
1983 if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) {
1984 goto return1;
1985 } else if (*cur == ' ') {
1986 cur++;
1987 if (*cur == 0)
1988 goto return1;
1989 if (*cur == ' ')
1990 goto return1;
1991 } else {
1992 cur++;
1993 }
1994 }
1995 if (val != NULL) {
1996 v = xmlSchemaNewValue(XML_SCHEMAS_TOKEN);
1997 if (v != NULL) {
1998 v->value.str = xmlStrdup(value);
1999 *val = v;
2000 } else {
2001 goto error;
2002 }
2003 }
2004 goto return0;
2005 }
2006 case XML_SCHEMAS_LANGUAGE:
2007 if (xmlCheckLanguageID(value) == 1) {
2008 if (val != NULL) {
2009 v = xmlSchemaNewValue(XML_SCHEMAS_LANGUAGE);
2010 if (v != NULL) {
2011 v->value.str = xmlStrdup(value);
2012 *val = v;
2013 } else {
2014 goto error;
2015 }
2016 }
2017 goto return0;
2018 }
2019 goto return1;
2020 case XML_SCHEMAS_NMTOKEN:
2021 if (xmlValidateNMToken(value, 1) == 0) {
2022 if (val != NULL) {
2023 v = xmlSchemaNewValue(XML_SCHEMAS_NMTOKEN);
2024 if (v != NULL) {
2025 v->value.str = xmlStrdup(value);
2026 *val = v;
2027 } else {
2028 goto error;
2029 }
2030 }
2031 goto return0;
2032 }
2033 goto return1;
2034 case XML_SCHEMAS_NMTOKENS:
2035 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeNmtokenDef,
2036 value, val, node);
2037 if (ret > 0)
2038 ret = 0;
2039 else
2040 ret = 1;
2041 goto done;
2042 case XML_SCHEMAS_NAME:
2043 ret = xmlValidateName(value, 1);
2044 if ((ret == 0) && (val != NULL)) {
2045 TODO;
2046 }
2047 goto done;
2048 case XML_SCHEMAS_QNAME:{
2049 xmlChar *uri = NULL;
2050 xmlChar *local = NULL;
2051
2052 ret = xmlValidateQName(value, 1);
2053 if ((ret == 0) && (node != NULL)) {
2054 xmlChar *prefix;
2055
2056 local = xmlSplitQName2(value, &prefix);
2057 if (prefix != NULL) {
2058 xmlNsPtr ns;
2059
2060 ns = xmlSearchNs(node->doc, node, prefix);
2061 if (ns == NULL)
2062 ret = 1;
2063 else if (val != NULL)
2064 uri = xmlStrdup(ns->href);
2065 }
2066 if ((local != NULL) && ((val == NULL) || (ret != 0)))
2067 xmlFree(local);
2068 if (prefix != NULL)
2069 xmlFree(prefix);
2070 }
2071 if ((ret == 0) && (val != NULL)) {
2072 v = xmlSchemaNewValue(XML_SCHEMAS_QNAME);
2073 if (v != NULL) {
2074 if (local != NULL)
2075 v->value.qname.name = local;
2076 else
2077 v->value.qname.name = xmlStrdup(value);
2078 if (uri != NULL)
2079 v->value.qname.uri = uri;
2080
2081 *val = v;
2082 } else {
2083 if (local != NULL)
2084 xmlFree(local);
2085 if (uri != NULL)
2086 xmlFree(uri);
2087 goto error;
2088 }
2089 }
2090 goto done;
2091 }
2092 case XML_SCHEMAS_NCNAME:
2093 ret = xmlValidateNCName(value, 1);
2094 if ((ret == 0) && (val != NULL)) {
2095 v = xmlSchemaNewValue(XML_SCHEMAS_NCNAME);
2096 if (v != NULL) {
2097 v->value.str = xmlStrdup(value);
2098 *val = v;
2099 } else {
2100 goto error;
2101 }
2102 }
2103 goto done;
2104 case XML_SCHEMAS_ID:
2105 ret = xmlValidateNCName(value, 1);
2106 if ((ret == 0) && (val != NULL)) {
2107 v = xmlSchemaNewValue(XML_SCHEMAS_ID);
2108 if (v != NULL) {
2109 v->value.str = xmlStrdup(value);
2110 *val = v;
2111 } else {
2112 goto error;
2113 }
2114 }
2115 if ((ret == 0) && (node != NULL) &&
2116 (node->type == XML_ATTRIBUTE_NODE)) {
2117 xmlAttrPtr attr = (xmlAttrPtr) node;
2118
2119 /*
2120 * NOTE: the IDness might have already be declared in the DTD
2121 */
2122 if (attr->atype != XML_ATTRIBUTE_ID) {
2123 xmlIDPtr res;
2124 xmlChar *strip;
2125
2126 strip = xmlSchemaStrip(value);
2127 if (strip != NULL) {
2128 res = xmlAddID(NULL, node->doc, strip, attr);
2129 xmlFree(strip);
2130 } else
2131 res = xmlAddID(NULL, node->doc, value, attr);
2132 if (res == NULL) {
2133 ret = 2;
2134 } else {
2135 attr->atype = XML_ATTRIBUTE_ID;
2136 }
2137 }
2138 }
2139 goto done;
2140 case XML_SCHEMAS_IDREF:
2141 ret = xmlValidateNCName(value, 1);
2142 if ((ret == 0) && (val != NULL)) {
2143 TODO;
2144 }
2145 if ((ret == 0) && (node != NULL) &&
2146 (node->type == XML_ATTRIBUTE_NODE)) {
2147 xmlAttrPtr attr = (xmlAttrPtr) node;
2148 xmlChar *strip;
2149
2150 strip = xmlSchemaStrip(value);
2151 if (strip != NULL) {
2152 xmlAddRef(NULL, node->doc, strip, attr);
2153 xmlFree(strip);
2154 } else
2155 xmlAddRef(NULL, node->doc, value, attr);
2156 attr->atype = XML_ATTRIBUTE_IDREF;
2157 }
2158 goto done;
2159 case XML_SCHEMAS_IDREFS:
2160 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeIdrefDef,
2161 value, val, node);
2162 if (ret < 0)
2163 ret = 2;
2164 else
2165 ret = 0;
2166 if ((ret == 0) && (node != NULL) &&
2167 (node->type == XML_ATTRIBUTE_NODE)) {
2168 xmlAttrPtr attr = (xmlAttrPtr) node;
2169
2170 attr->atype = XML_ATTRIBUTE_IDREFS;
2171 }
2172 goto done;
2173 case XML_SCHEMAS_ENTITY:{
2174 xmlChar *strip;
2175
2176 ret = xmlValidateNCName(value, 1);
2177 if ((node == NULL) || (node->doc == NULL))
2178 ret = 3;
2179 if (ret == 0) {
2180 xmlEntityPtr ent;
2181
2182 strip = xmlSchemaStrip(value);
2183 if (strip != NULL) {
2184 ent = xmlGetDocEntity(node->doc, strip);
2185 xmlFree(strip);
2186 } else {
2187 ent = xmlGetDocEntity(node->doc, value);
2188 }
2189 if ((ent == NULL) ||
2190 (ent->etype !=
2191 XML_EXTERNAL_GENERAL_UNPARSED_ENTITY))
2192 ret = 4;
2193 }
2194 if ((ret == 0) && (val != NULL)) {
2195 TODO;
2196 }
2197 if ((ret == 0) && (node != NULL) &&
2198 (node->type == XML_ATTRIBUTE_NODE)) {
2199 xmlAttrPtr attr = (xmlAttrPtr) node;
2200
2201 attr->atype = XML_ATTRIBUTE_ENTITY;
2202 }
2203 goto done;
2204 }
2205 case XML_SCHEMAS_ENTITIES:
2206 if ((node == NULL) || (node->doc == NULL))
2207 goto return3;
2208 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeEntityDef,
2209 value, val, node);
2210 if (ret <= 0)
2211 ret = 1;
2212 else
2213 ret = 0;
2214 if ((ret == 0) && (node != NULL) &&
2215 (node->type == XML_ATTRIBUTE_NODE)) {
2216 xmlAttrPtr attr = (xmlAttrPtr) node;
2217
2218 attr->atype = XML_ATTRIBUTE_ENTITIES;
2219 }
2220 goto done;
2221 case XML_SCHEMAS_NOTATION:{
2222 xmlChar *uri = NULL;
2223 xmlChar *local = NULL;
2224
2225 ret = xmlValidateQName(value, 1);
2226 if ((ret == 0) && (node != NULL)) {
2227 xmlChar *prefix;
2228
2229 local = xmlSplitQName2(value, &prefix);
2230 if (prefix != NULL) {
2231 xmlNsPtr ns;
2232
2233 ns = xmlSearchNs(node->doc, node, prefix);
2234 if (ns == NULL)
2235 ret = 1;
2236 else if (val != NULL)
2237 uri = xmlStrdup(ns->href);
2238 }
2239 if ((local != NULL) && ((val == NULL) || (ret != 0)))
2240 xmlFree(local);
2241 if (prefix != NULL)
2242 xmlFree(prefix);
2243 }
2244 if ((node == NULL) || (node->doc == NULL))
2245 ret = 3;
2246 if (ret == 0) {
2247 ret = xmlValidateNotationUse(NULL, node->doc, value);
2248 if (ret == 1)
2249 ret = 0;
2250 else
2251 ret = 1;
2252 }
2253 if ((ret == 0) && (val != NULL)) {
2254 v = xmlSchemaNewValue(XML_SCHEMAS_NOTATION);
2255 if (v != NULL) {
2256 if (local != NULL)
2257 v->value.qname.name = local;
2258 else
2259 v->value.qname.name = xmlStrdup(value);
2260 if (uri != NULL)
2261 v->value.qname.uri = uri;
2262
2263 *val = v;
2264 } else {
2265 if (local != NULL)
2266 xmlFree(local);
2267 if (uri != NULL)
2268 xmlFree(uri);
2269 goto error;
2270 }
2271 }
2272 goto done;
2273 }
2274 case XML_SCHEMAS_ANYURI:{
Daniel Veillard11c466a2004-03-14 12:20:15 +00002275 if (*value != 0) {
2276 xmlURIPtr uri = xmlParseURI((const char *) value);
2277 if (uri == NULL)
2278 goto return1;
2279 xmlFreeURI(uri);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002280 }
Daniel Veillard11c466a2004-03-14 12:20:15 +00002281
2282 if (val != NULL) {
2283 v = xmlSchemaNewValue(XML_SCHEMAS_ANYURI);
2284 if (v == NULL)
2285 goto error;
2286 v->value.str = xmlStrdup(value);
2287 *val = v;
2288 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002289 goto return0;
2290 }
2291 case XML_SCHEMAS_HEXBINARY:{
2292 const xmlChar *cur = value;
2293 xmlChar *base;
2294 int total, i = 0;
2295
2296 if (cur == NULL)
2297 goto return1;
2298
2299 while (((*cur >= '0') && (*cur <= '9')) ||
2300 ((*cur >= 'A') && (*cur <= 'F')) ||
2301 ((*cur >= 'a') && (*cur <= 'f'))) {
2302 i++;
2303 cur++;
2304 }
2305
2306 if (*cur != 0)
2307 goto return1;
2308 if ((i % 2) != 0)
2309 goto return1;
2310
2311 if (val != NULL) {
2312
2313 v = xmlSchemaNewValue(XML_SCHEMAS_HEXBINARY);
2314 if (v == NULL)
2315 goto error;
2316
2317 cur = xmlStrdup(value);
2318 if (cur == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002319 xmlSchemaTypeErrMemory(node, "allocating hexbin data");
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002320 xmlFree(v);
2321 goto return1;
2322 }
2323
2324 total = i / 2; /* number of octets */
2325
2326 base = (xmlChar *) cur;
2327 while (i-- > 0) {
2328 if (*base >= 'a')
2329 *base = *base - ('a' - 'A');
2330 base++;
2331 }
2332
2333 v->value.hex.str = (xmlChar *) cur;
2334 v->value.hex.total = total;
2335 *val = v;
2336 }
2337 goto return0;
2338 }
2339 case XML_SCHEMAS_BASE64BINARY:{
2340 /* ISSUE:
2341 *
2342 * Ignore all stray characters? (yes, currently)
2343 * Worry about long lines? (no, currently)
2344 *
2345 * rfc2045.txt:
2346 *
2347 * "The encoded output stream must be represented in lines of
2348 * no more than 76 characters each. All line breaks or other
2349 * characters not found in Table 1 must be ignored by decoding
2350 * software. In base64 data, characters other than those in
2351 * Table 1, line breaks, and other white space probably
2352 * indicate a transmission error, about which a warning
2353 * message or even a message rejection might be appropriate
2354 * under some circumstances." */
2355 const xmlChar *cur = value;
2356 xmlChar *base;
2357 int total, i = 0, pad = 0;
2358
2359 if (cur == NULL)
2360 goto return1;
2361
2362 for (; *cur; ++cur) {
2363 int decc;
2364
2365 decc = _xmlSchemaBase64Decode(*cur);
2366 if (decc < 0) ;
2367 else if (decc < 64)
2368 i++;
2369 else
2370 break;
2371 }
2372 for (; *cur; ++cur) {
2373 int decc;
2374
2375 decc = _xmlSchemaBase64Decode(*cur);
2376 if (decc < 0) ;
2377 else if (decc < 64)
2378 goto return1;
2379 if (decc == 64)
2380 pad++;
2381 }
2382
2383 /* rfc2045.txt: "Special processing is performed if fewer than
2384 * 24 bits are available at the end of the data being encoded.
2385 * A full encoding quantum is always completed at the end of a
2386 * body. When fewer than 24 input bits are available in an
2387 * input group, zero bits are added (on the right) to form an
2388 * integral number of 6-bit groups. Padding at the end of the
2389 * data is performed using the "=" character. Since all
2390 * base64 input is an integral number of octets, only the
2391 * following cases can arise: (1) the final quantum of
2392 * encoding input is an integral multiple of 24 bits; here,
2393 * the final unit of encoded output will be an integral
2394 * multiple ofindent: Standard input:701: Warning:old style
2395 * assignment ambiguity in "=*". Assuming "= *" 4 characters
2396 * with no "=" padding, (2) the final
2397 * quantum of encoding input is exactly 8 bits; here, the
2398 * final unit of encoded output will be two characters
2399 * followed by two "=" padding characters, or (3) the final
2400 * quantum of encoding input is exactly 16 bits; here, the
2401 * final unit of encoded output will be three characters
2402 * followed by one "=" padding character." */
2403
2404 total = 3 * (i / 4);
2405 if (pad == 0) {
2406 if (i % 4 != 0)
2407 goto return1;
2408 } else if (pad == 1) {
2409 int decc;
2410
2411 if (i % 4 != 3)
2412 goto return1;
2413 for (decc = _xmlSchemaBase64Decode(*cur);
2414 (decc < 0) || (decc > 63);
2415 decc = _xmlSchemaBase64Decode(*cur))
2416 --cur;
2417 /* 16bits in 24bits means 2 pad bits: nnnnnn nnmmmm mmmm00*/
2418 /* 00111100 -> 0x3c */
2419 if (decc & ~0x3c)
2420 goto return1;
2421 total += 2;
2422 } else if (pad == 2) {
2423 int decc;
2424
2425 if (i % 4 != 2)
2426 goto return1;
2427 for (decc = _xmlSchemaBase64Decode(*cur);
2428 (decc < 0) || (decc > 63);
2429 decc = _xmlSchemaBase64Decode(*cur))
2430 --cur;
2431 /* 8bits in 12bits means 4 pad bits: nnnnnn nn0000 */
2432 /* 00110000 -> 0x30 */
2433 if (decc & ~0x30)
2434 goto return1;
2435 total += 1;
2436 } else
2437 goto return1;
2438
2439 if (val != NULL) {
2440 v = xmlSchemaNewValue(XML_SCHEMAS_BASE64BINARY);
2441 if (v == NULL)
2442 goto error;
2443 base =
2444 (xmlChar *) xmlMallocAtomic((i + pad + 1) *
2445 sizeof(xmlChar));
2446 if (base == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002447 xmlSchemaTypeErrMemory(node, "allocating base64 data");
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002448 xmlFree(v);
2449 goto return1;
2450 }
2451 v->value.base64.str = base;
2452 for (cur = value; *cur; ++cur)
2453 if (_xmlSchemaBase64Decode(*cur) >= 0) {
2454 *base = *cur;
2455 ++base;
2456 }
2457 *base = 0;
2458 v->value.base64.total = total;
2459 *val = v;
2460 }
2461 goto return0;
2462 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002463 case XML_SCHEMAS_INTEGER:
2464 case XML_SCHEMAS_PINTEGER:
2465 case XML_SCHEMAS_NPINTEGER:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002466 case XML_SCHEMAS_NINTEGER:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002467 case XML_SCHEMAS_NNINTEGER:{
2468 const xmlChar *cur = value;
2469 unsigned long lo, mi, hi;
2470 int sign = 0;
2471
2472 if (cur == NULL)
2473 goto return1;
2474 if (*cur == '-') {
2475 sign = 1;
2476 cur++;
2477 } else if (*cur == '+')
2478 cur++;
2479 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2480 if (ret == 0)
2481 goto return1;
2482 if (*cur != 0)
2483 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002484 if (type->builtInType == XML_SCHEMAS_NPINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002485 if ((sign == 0) &&
2486 ((hi != 0) || (mi != 0) || (lo != 0)))
2487 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002488 } else if (type->builtInType == XML_SCHEMAS_PINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002489 if (sign == 1)
2490 goto return1;
2491 if ((hi == 0) && (mi == 0) && (lo == 0))
2492 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002493 } else if (type->builtInType == XML_SCHEMAS_NINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002494 if (sign == 0)
2495 goto return1;
2496 if ((hi == 0) && (mi == 0) && (lo == 0))
2497 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002498 } else if (type->builtInType == XML_SCHEMAS_NNINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002499 if ((sign == 1) &&
2500 ((hi != 0) || (mi != 0) || (lo != 0)))
2501 goto return1;
2502 }
2503 /*
2504 * We can store a value only if no overflow occured
2505 */
2506 if ((ret > 0) && (val != NULL)) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00002507 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002508 if (v != NULL) {
2509 v->value.decimal.lo = lo;
2510 v->value.decimal.mi = lo;
2511 v->value.decimal.hi = lo;
2512 v->value.decimal.sign = sign;
2513 v->value.decimal.frac = 0;
2514 v->value.decimal.total = cur - value;
2515 *val = v;
2516 }
2517 }
2518 goto return0;
2519 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002520 case XML_SCHEMAS_LONG:
2521 case XML_SCHEMAS_BYTE:
2522 case XML_SCHEMAS_SHORT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002523 case XML_SCHEMAS_INT:{
2524 const xmlChar *cur = value;
2525 unsigned long lo, mi, hi;
2526 int total = 0;
2527 int sign = 0;
2528
2529 if (cur == NULL)
2530 goto return1;
2531 if (*cur == '-') {
2532 sign = 1;
2533 cur++;
2534 } else if (*cur == '+')
2535 cur++;
2536 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2537 if (ret <= 0)
2538 goto return1;
2539 if (*cur != 0)
2540 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002541 if (type->builtInType == XML_SCHEMAS_LONG) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002542 if (hi >= 922) {
2543 if (hi > 922)
2544 goto return1;
2545 if (mi >= 33720368) {
2546 if (mi > 33720368)
2547 goto return1;
2548 if ((sign == 0) && (lo > 54775807))
2549 goto return1;
2550 if ((sign == 1) && (lo > 54775808))
2551 goto return1;
2552 }
2553 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002554 } else if (type->builtInType == XML_SCHEMAS_INT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002555 if (hi != 0)
2556 goto return1;
2557 if (mi >= 21) {
2558 if (mi > 21)
2559 goto return1;
2560 if ((sign == 0) && (lo > 47483647))
2561 goto return1;
2562 if ((sign == 1) && (lo > 47483648))
2563 goto return1;
2564 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002565 } else if (type->builtInType == XML_SCHEMAS_SHORT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002566 if ((mi != 0) || (hi != 0))
2567 goto return1;
2568 if ((sign == 1) && (lo > 32768))
2569 goto return1;
2570 if ((sign == 0) && (lo > 32767))
2571 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002572 } else if (type->builtInType == XML_SCHEMAS_BYTE) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002573 if ((mi != 0) || (hi != 0))
2574 goto return1;
2575 if ((sign == 1) && (lo > 128))
2576 goto return1;
2577 if ((sign == 0) && (lo > 127))
2578 goto return1;
2579 }
2580 if (val != NULL) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00002581 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002582 if (v != NULL) {
2583 v->value.decimal.lo = lo;
2584 v->value.decimal.mi = lo;
2585 v->value.decimal.hi = lo;
2586 v->value.decimal.sign = sign;
2587 v->value.decimal.frac = 0;
2588 v->value.decimal.total = total;
2589 *val = v;
2590 }
2591 }
2592 goto return0;
2593 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002594 case XML_SCHEMAS_UINT:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002595 case XML_SCHEMAS_ULONG:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002596 case XML_SCHEMAS_USHORT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002597 case XML_SCHEMAS_UBYTE:{
2598 const xmlChar *cur = value;
2599 unsigned long lo, mi, hi;
2600 int total = 0;
2601
2602 if (cur == NULL)
2603 goto return1;
2604 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2605 if (ret <= 0)
2606 goto return1;
2607 if (*cur != 0)
2608 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002609 if (type->builtInType == XML_SCHEMAS_ULONG) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002610 if (hi >= 1844) {
2611 if (hi > 1844)
2612 goto return1;
2613 if (mi >= 67440737) {
2614 if (mi > 67440737)
2615 goto return1;
2616 if (lo > 9551615)
2617 goto return1;
2618 }
2619 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002620 } else if (type->builtInType == XML_SCHEMAS_UINT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002621 if (hi != 0)
2622 goto return1;
2623 if (mi >= 42) {
2624 if (mi > 42)
2625 goto return1;
2626 if (lo > 94967295)
2627 goto return1;
2628 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002629 } else if (type->builtInType == XML_SCHEMAS_USHORT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002630 if ((mi != 0) || (hi != 0))
2631 goto return1;
2632 if (lo > 65535)
2633 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002634 } else if (type->builtInType == XML_SCHEMAS_UBYTE) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002635 if ((mi != 0) || (hi != 0))
2636 goto return1;
2637 if (lo > 255)
2638 goto return1;
2639 }
2640 if (val != NULL) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00002641 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002642 if (v != NULL) {
2643 v->value.decimal.lo = lo;
2644 v->value.decimal.mi = mi;
2645 v->value.decimal.hi = hi;
2646 v->value.decimal.sign = 0;
2647 v->value.decimal.frac = 0;
2648 v->value.decimal.total = total;
2649 *val = v;
2650 }
2651 }
2652 goto return0;
2653 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002654 }
2655
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002656 done:
2657 if (norm != NULL)
2658 xmlFree(norm);
2659 return (ret);
2660 return3:
2661 if (norm != NULL)
2662 xmlFree(norm);
2663 return (3);
2664 return1:
2665 if (norm != NULL)
2666 xmlFree(norm);
2667 return (1);
2668 return0:
2669 if (norm != NULL)
2670 xmlFree(norm);
2671 return (0);
2672 error:
2673 if (norm != NULL)
2674 xmlFree(norm);
2675 return (-1);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002676}
2677
2678/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002679 * xmlSchemaValPredefTypeNode:
Daniel Veillard4255d502002-04-16 15:50:10 +00002680 * @type: the predefined type
2681 * @value: the value to check
2682 * @val: the return computed value
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002683 * @node: the node containing the value
Daniel Veillard4255d502002-04-16 15:50:10 +00002684 *
2685 * Check that a value conforms to the lexical space of the predefined type.
2686 * if true a value is computed and returned in @val.
2687 *
2688 * Returns 0 if this validates, a positive error code number otherwise
2689 * and -1 in case of internal or API error.
2690 */
2691int
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002692xmlSchemaValPredefTypeNode(xmlSchemaTypePtr type, const xmlChar *value,
2693 xmlSchemaValPtr *val, xmlNodePtr node) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002694 return(xmlSchemaValAtomicType(type, value, val, node, 0));
Daniel Veillard4255d502002-04-16 15:50:10 +00002695}
2696
2697/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002698 * xmlSchemaValidatePredefinedType:
2699 * @type: the predefined type
2700 * @value: the value to check
2701 * @val: the return computed value
2702 *
2703 * Check that a value conforms to the lexical space of the predefined type.
2704 * if true a value is computed and returned in @val.
2705 *
2706 * Returns 0 if this validates, a positive error code number otherwise
2707 * and -1 in case of internal or API error.
2708 */
2709int
2710xmlSchemaValidatePredefinedType(xmlSchemaTypePtr type, const xmlChar *value,
2711 xmlSchemaValPtr *val) {
2712 return(xmlSchemaValPredefTypeNode(type, value, val, NULL));
2713}
2714
2715/**
Daniel Veillard4255d502002-04-16 15:50:10 +00002716 * xmlSchemaCompareDecimals:
2717 * @x: a first decimal value
2718 * @y: a second decimal value
2719 *
2720 * Compare 2 decimals
2721 *
2722 * Returns -1 if x < y, 0 if x == y, 1 if x > y and -2 in case of error
2723 */
2724static int
2725xmlSchemaCompareDecimals(xmlSchemaValPtr x, xmlSchemaValPtr y)
2726{
2727 xmlSchemaValPtr swp;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002728 int order = 1, p;
Daniel Veillard4255d502002-04-16 15:50:10 +00002729 unsigned long tmp;
2730
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002731 if ((x->value.decimal.sign) &&
2732 ((x->value.decimal.lo != 0) ||
2733 (x->value.decimal.mi != 0) ||
2734 (x->value.decimal.hi != 0))) {
2735 if ((y->value.decimal.sign) &&
2736 ((y->value.decimal.lo != 0) ||
2737 (y->value.decimal.mi != 0) ||
2738 (y->value.decimal.hi != 0)))
Daniel Veillard80b19092003-03-28 13:29:53 +00002739 order = -1;
2740 else
2741 return (-1);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002742 } else if ((y->value.decimal.sign) &&
2743 ((y->value.decimal.lo != 0) ||
2744 (y->value.decimal.mi != 0) ||
2745 (y->value.decimal.hi != 0))) {
Daniel Veillard4255d502002-04-16 15:50:10 +00002746 return (1);
Daniel Veillard80b19092003-03-28 13:29:53 +00002747 }
Daniel Veillard4255d502002-04-16 15:50:10 +00002748 if (x->value.decimal.frac == y->value.decimal.frac) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002749 if (x->value.decimal.hi < y->value.decimal.hi)
2750 return (-order);
Daniel Veillard01fa6152004-06-29 17:04:39 +00002751 if (x->value.decimal.hi > y->value.decimal.hi)
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002752 return (order);
2753 if (x->value.decimal.mi < y->value.decimal.mi)
2754 return (-order);
Daniel Veillard01fa6152004-06-29 17:04:39 +00002755 if (x->value.decimal.mi > y->value.decimal.mi)
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002756 return (order);
2757 if (x->value.decimal.lo < y->value.decimal.lo)
Daniel Veillard80b19092003-03-28 13:29:53 +00002758 return (-order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002759 if (x->value.decimal.lo > y->value.decimal.lo)
Daniel Veillard80b19092003-03-28 13:29:53 +00002760 return(order);
2761 return(0);
Daniel Veillard4255d502002-04-16 15:50:10 +00002762 }
2763 if (y->value.decimal.frac > x->value.decimal.frac) {
2764 swp = y;
2765 y = x;
2766 x = swp;
2767 order = -order;
2768 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002769 p = powten[x->value.decimal.frac - y->value.decimal.frac];
2770 tmp = x->value.decimal.lo / p;
2771 if (tmp > y->value.decimal.lo)
Daniel Veillard4255d502002-04-16 15:50:10 +00002772 return (order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002773 if (tmp < y->value.decimal.lo)
Daniel Veillard4255d502002-04-16 15:50:10 +00002774 return (-order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002775 tmp = y->value.decimal.lo * p;
2776 if (x->value.decimal.lo < tmp)
Daniel Veillard4255d502002-04-16 15:50:10 +00002777 return (-order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002778 if (x->value.decimal.lo == tmp)
Daniel Veillard4255d502002-04-16 15:50:10 +00002779 return (0);
2780 return (order);
2781}
2782
2783/**
Daniel Veillard070803b2002-05-03 07:29:38 +00002784 * xmlSchemaCompareDurations:
2785 * @x: a first duration value
2786 * @y: a second duration value
2787 *
2788 * Compare 2 durations
2789 *
2790 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
2791 * case of error
2792 */
2793static int
2794xmlSchemaCompareDurations(xmlSchemaValPtr x, xmlSchemaValPtr y)
2795{
2796 long carry, mon, day;
2797 double sec;
Daniel Veillard80b19092003-03-28 13:29:53 +00002798 int invert = 1;
2799 long xmon, xday, myear, minday, maxday;
Daniel Veillard070803b2002-05-03 07:29:38 +00002800 static const long dayRange [2][12] = {
2801 { 0, 28, 59, 89, 120, 150, 181, 212, 242, 273, 303, 334, },
2802 { 0, 31, 62, 92, 123, 153, 184, 215, 245, 276, 306, 337} };
2803
2804 if ((x == NULL) || (y == NULL))
Daniel Veillard5a872412002-05-22 06:40:27 +00002805 return -2;
Daniel Veillard070803b2002-05-03 07:29:38 +00002806
2807 /* months */
2808 mon = x->value.dur.mon - y->value.dur.mon;
2809
2810 /* seconds */
2811 sec = x->value.dur.sec - y->value.dur.sec;
2812 carry = (long)sec / SECS_PER_DAY;
2813 sec -= (double)(carry * SECS_PER_DAY);
2814
2815 /* days */
2816 day = x->value.dur.day - y->value.dur.day + carry;
2817
2818 /* easy test */
2819 if (mon == 0) {
2820 if (day == 0)
2821 if (sec == 0.0)
2822 return 0;
2823 else if (sec < 0.0)
2824 return -1;
2825 else
2826 return 1;
2827 else if (day < 0)
2828 return -1;
2829 else
2830 return 1;
2831 }
2832
2833 if (mon > 0) {
2834 if ((day >= 0) && (sec >= 0.0))
2835 return 1;
2836 else {
2837 xmon = mon;
2838 xday = -day;
2839 }
2840 } else if ((day <= 0) && (sec <= 0.0)) {
2841 return -1;
2842 } else {
Daniel Veillard80b19092003-03-28 13:29:53 +00002843 invert = -1;
Daniel Veillard070803b2002-05-03 07:29:38 +00002844 xmon = -mon;
2845 xday = day;
2846 }
2847
2848 myear = xmon / 12;
Daniel Veillard80b19092003-03-28 13:29:53 +00002849 if (myear == 0) {
2850 minday = 0;
2851 maxday = 0;
2852 } else {
2853 maxday = 366 * ((myear + 3) / 4) +
2854 365 * ((myear - 1) % 4);
2855 minday = maxday - 1;
2856 }
2857
Daniel Veillard070803b2002-05-03 07:29:38 +00002858 xmon = xmon % 12;
2859 minday += dayRange[0][xmon];
2860 maxday += dayRange[1][xmon];
2861
Daniel Veillard80b19092003-03-28 13:29:53 +00002862 if ((maxday == minday) && (maxday == xday))
2863 return(0); /* can this really happen ? */
Daniel Veillard070803b2002-05-03 07:29:38 +00002864 if (maxday < xday)
Daniel Veillard80b19092003-03-28 13:29:53 +00002865 return(-invert);
2866 if (minday > xday)
2867 return(invert);
Daniel Veillard070803b2002-05-03 07:29:38 +00002868
2869 /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00002870 return 2;
2871}
2872
2873/*
2874 * macros for adding date/times and durations
2875 */
2876#define FQUOTIENT(a,b) (floor(((double)a/(double)b)))
2877#define MODULO(a,b) (a - FQUOTIENT(a,b) * b)
2878#define FQUOTIENT_RANGE(a,low,high) (FQUOTIENT((a-low),(high-low)))
2879#define MODULO_RANGE(a,low,high) ((MODULO((a-low),(high-low)))+low)
2880
2881/**
Daniel Veillard669adfc2004-05-29 20:12:46 +00002882 * xmlSchemaDupVal:
2883 * @v: the #xmlSchemaValPtr value to duplicate
2884 *
2885 * Makes a copy of @v. The calling program is responsible for freeing
2886 * the returned value.
2887 *
2888 * returns a pointer to a duplicated #xmlSchemaValPtr or NULL if error.
2889 */
2890static xmlSchemaValPtr
2891xmlSchemaDupVal (xmlSchemaValPtr v)
2892{
2893 xmlSchemaValPtr ret = xmlSchemaNewValue(v->type);
2894 if (ret == NULL)
2895 return NULL;
2896
2897 memcpy(ret, v, sizeof(xmlSchemaVal));
2898 return ret;
2899}
2900
2901/**
Daniel Veillard5a872412002-05-22 06:40:27 +00002902 * _xmlSchemaDateAdd:
2903 * @dt: an #xmlSchemaValPtr
2904 * @dur: an #xmlSchemaValPtr of type #XS_DURATION
2905 *
2906 * Compute a new date/time from @dt and @dur. This function assumes @dt
2907 * is either #XML_SCHEMAS_DATETIME, #XML_SCHEMAS_DATE, #XML_SCHEMAS_GYEARMONTH,
Daniel Veillard669adfc2004-05-29 20:12:46 +00002908 * or #XML_SCHEMAS_GYEAR. The returned #xmlSchemaVal is the same type as
2909 * @dt. The calling program is responsible for freeing the returned value.
Daniel Veillard5a872412002-05-22 06:40:27 +00002910 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00002911 * Returns a pointer to a new #xmlSchemaVal or NULL if error.
Daniel Veillard5a872412002-05-22 06:40:27 +00002912 */
2913static xmlSchemaValPtr
2914_xmlSchemaDateAdd (xmlSchemaValPtr dt, xmlSchemaValPtr dur)
2915{
Daniel Veillard669adfc2004-05-29 20:12:46 +00002916 xmlSchemaValPtr ret, tmp;
Daniel Veillard5a872412002-05-22 06:40:27 +00002917 long carry, tempdays, temp;
2918 xmlSchemaValDatePtr r, d;
2919 xmlSchemaValDurationPtr u;
2920
2921 if ((dt == NULL) || (dur == NULL))
2922 return NULL;
2923
2924 ret = xmlSchemaNewValue(dt->type);
2925 if (ret == NULL)
2926 return NULL;
2927
Daniel Veillard669adfc2004-05-29 20:12:46 +00002928 /* make a copy so we don't alter the original value */
2929 tmp = xmlSchemaDupVal(dt);
2930 if (tmp == NULL) {
2931 xmlSchemaFreeValue(ret);
2932 return NULL;
2933 }
2934
Daniel Veillard5a872412002-05-22 06:40:27 +00002935 r = &(ret->value.date);
Daniel Veillard669adfc2004-05-29 20:12:46 +00002936 d = &(tmp->value.date);
Daniel Veillard5a872412002-05-22 06:40:27 +00002937 u = &(dur->value.dur);
2938
2939 /* normalization */
2940 if (d->mon == 0)
2941 d->mon = 1;
2942
2943 /* normalize for time zone offset */
2944 u->sec -= (d->tzo * 60);
2945 d->tzo = 0;
2946
2947 /* normalization */
2948 if (d->day == 0)
2949 d->day = 1;
2950
2951 /* month */
2952 carry = d->mon + u->mon;
Daniel Veillardebe25d42004-03-25 09:35:49 +00002953 r->mon = (unsigned int) MODULO_RANGE(carry, 1, 13);
2954 carry = (long) FQUOTIENT_RANGE(carry, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00002955
2956 /* year (may be modified later) */
2957 r->year = d->year + carry;
2958 if (r->year == 0) {
2959 if (d->year > 0)
2960 r->year--;
2961 else
2962 r->year++;
2963 }
2964
2965 /* time zone */
2966 r->tzo = d->tzo;
2967 r->tz_flag = d->tz_flag;
2968
2969 /* seconds */
2970 r->sec = d->sec + u->sec;
Daniel Veillardebe25d42004-03-25 09:35:49 +00002971 carry = (long) FQUOTIENT((long)r->sec, 60);
Daniel Veillard5a872412002-05-22 06:40:27 +00002972 if (r->sec != 0.0) {
2973 r->sec = MODULO(r->sec, 60.0);
2974 }
2975
2976 /* minute */
2977 carry += d->min;
Daniel Veillardebe25d42004-03-25 09:35:49 +00002978 r->min = (unsigned int) MODULO(carry, 60);
2979 carry = (long) FQUOTIENT(carry, 60);
Daniel Veillard5a872412002-05-22 06:40:27 +00002980
2981 /* hours */
2982 carry += d->hour;
Daniel Veillardebe25d42004-03-25 09:35:49 +00002983 r->hour = (unsigned int) MODULO(carry, 24);
2984 carry = (long)FQUOTIENT(carry, 24);
Daniel Veillard5a872412002-05-22 06:40:27 +00002985
2986 /*
2987 * days
2988 * Note we use tempdays because the temporary values may need more
2989 * than 5 bits
2990 */
2991 if ((VALID_YEAR(r->year)) && (VALID_MONTH(r->mon)) &&
2992 (d->day > MAX_DAYINMONTH(r->year, r->mon)))
2993 tempdays = MAX_DAYINMONTH(r->year, r->mon);
2994 else if (d->day < 1)
2995 tempdays = 1;
2996 else
2997 tempdays = d->day;
2998
2999 tempdays += u->day + carry;
3000
3001 while (1) {
3002 if (tempdays < 1) {
Daniel Veillardebe25d42004-03-25 09:35:49 +00003003 long tmon = (long) MODULO_RANGE(r->mon-1, 1, 13);
3004 long tyr = r->year + (long)FQUOTIENT_RANGE(r->mon-1, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00003005 if (tyr == 0)
3006 tyr--;
3007 tempdays += MAX_DAYINMONTH(tyr, tmon);
3008 carry = -1;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003009 } else if (tempdays > (long) MAX_DAYINMONTH(r->year, r->mon)) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003010 tempdays = tempdays - MAX_DAYINMONTH(r->year, r->mon);
3011 carry = 1;
3012 } else
3013 break;
3014
3015 temp = r->mon + carry;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003016 r->mon = (unsigned int) MODULO_RANGE(temp, 1, 13);
3017 r->year = r->year + (unsigned int) FQUOTIENT_RANGE(temp, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00003018 if (r->year == 0) {
3019 if (temp < 1)
3020 r->year--;
3021 else
3022 r->year++;
3023 }
3024 }
3025
3026 r->day = tempdays;
3027
3028 /*
3029 * adjust the date/time type to the date values
3030 */
3031 if (ret->type != XML_SCHEMAS_DATETIME) {
3032 if ((r->hour) || (r->min) || (r->sec))
3033 ret->type = XML_SCHEMAS_DATETIME;
3034 else if (ret->type != XML_SCHEMAS_DATE) {
3035 if ((r->mon != 1) && (r->day != 1))
3036 ret->type = XML_SCHEMAS_DATE;
3037 else if ((ret->type != XML_SCHEMAS_GYEARMONTH) && (r->mon != 1))
3038 ret->type = XML_SCHEMAS_GYEARMONTH;
3039 }
3040 }
3041
Daniel Veillard669adfc2004-05-29 20:12:46 +00003042 xmlSchemaFreeValue(tmp);
Daniel Veillard5a872412002-05-22 06:40:27 +00003043
Daniel Veillard5a872412002-05-22 06:40:27 +00003044 return ret;
3045}
3046
3047/**
3048 * xmlSchemaDateNormalize:
Daniel Veillard669adfc2004-05-29 20:12:46 +00003049 * @dt: an #xmlSchemaValPtr of a date/time type value.
3050 * @offset: number of seconds to adjust @dt by.
Daniel Veillard5a872412002-05-22 06:40:27 +00003051 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00003052 * Normalize @dt to GMT time. The @offset parameter is subtracted from
3053 * the return value is a time-zone offset is present on @dt.
Daniel Veillard5a872412002-05-22 06:40:27 +00003054 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00003055 * Returns a normalized copy of @dt or NULL if error.
Daniel Veillard5a872412002-05-22 06:40:27 +00003056 */
3057static xmlSchemaValPtr
3058xmlSchemaDateNormalize (xmlSchemaValPtr dt, double offset)
3059{
3060 xmlSchemaValPtr dur, ret;
3061
3062 if (dt == NULL)
3063 return NULL;
3064
3065 if (((dt->type != XML_SCHEMAS_TIME) &&
3066 (dt->type != XML_SCHEMAS_DATETIME)) || (dt->value.date.tzo == 0))
3067 return xmlSchemaDupVal(dt);
3068
3069 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
3070 if (dur == NULL)
3071 return NULL;
3072
3073 dur->value.date.sec -= offset;
3074
3075 ret = _xmlSchemaDateAdd(dt, dur);
3076 if (ret == NULL)
3077 return NULL;
3078
3079 xmlSchemaFreeValue(dur);
3080
3081 /* ret->value.date.tzo = 0; */
3082 return ret;
3083}
3084
3085/**
3086 * _xmlSchemaDateCastYMToDays:
3087 * @dt: an #xmlSchemaValPtr
3088 *
3089 * Convert mon and year of @dt to total number of days. Take the
3090 * number of years since (or before) 1 AD and add the number of leap
3091 * years. This is a function because negative
3092 * years must be handled a little differently and there is no zero year.
3093 *
3094 * Returns number of days.
3095 */
3096static long
3097_xmlSchemaDateCastYMToDays (const xmlSchemaValPtr dt)
3098{
3099 long ret;
3100
3101 if (dt->value.date.year < 0)
3102 ret = (dt->value.date.year * 365) +
3103 (((dt->value.date.year+1)/4)-((dt->value.date.year+1)/100)+
3104 ((dt->value.date.year+1)/400)) +
3105 DAY_IN_YEAR(0, dt->value.date.mon, dt->value.date.year);
3106 else
3107 ret = ((dt->value.date.year-1) * 365) +
3108 (((dt->value.date.year-1)/4)-((dt->value.date.year-1)/100)+
3109 ((dt->value.date.year-1)/400)) +
3110 DAY_IN_YEAR(0, dt->value.date.mon, dt->value.date.year);
3111
3112 return ret;
3113}
3114
3115/**
3116 * TIME_TO_NUMBER:
3117 * @dt: an #xmlSchemaValPtr
3118 *
3119 * Calculates the number of seconds in the time portion of @dt.
3120 *
3121 * Returns seconds.
3122 */
3123#define TIME_TO_NUMBER(dt) \
3124 ((double)((dt->value.date.hour * SECS_PER_HOUR) + \
Daniel Veillardb3721c22003-03-31 11:22:25 +00003125 (dt->value.date.min * SECS_PER_MIN) + \
3126 (dt->value.date.tzo * SECS_PER_MIN)) + \
3127 dt->value.date.sec)
Daniel Veillard5a872412002-05-22 06:40:27 +00003128
3129/**
3130 * xmlSchemaCompareDates:
3131 * @x: a first date/time value
3132 * @y: a second date/time value
3133 *
3134 * Compare 2 date/times
3135 *
3136 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3137 * case of error
3138 */
3139static int
3140xmlSchemaCompareDates (xmlSchemaValPtr x, xmlSchemaValPtr y)
3141{
3142 unsigned char xmask, ymask, xor_mask, and_mask;
3143 xmlSchemaValPtr p1, p2, q1, q2;
3144 long p1d, p2d, q1d, q2d;
3145
3146 if ((x == NULL) || (y == NULL))
3147 return -2;
3148
3149 if (x->value.date.tz_flag) {
3150
3151 if (!y->value.date.tz_flag) {
3152 p1 = xmlSchemaDateNormalize(x, 0);
3153 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3154 /* normalize y + 14:00 */
3155 q1 = xmlSchemaDateNormalize(y, (14 * SECS_PER_HOUR));
3156
3157 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003158 if (p1d < q1d) {
3159 xmlSchemaFreeValue(p1);
3160 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003161 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003162 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003163 double sec;
3164
3165 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00003166 if (sec < 0.0) {
3167 xmlSchemaFreeValue(p1);
3168 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003169 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003170 } else {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003171 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003172 /* normalize y - 14:00 */
3173 q2 = xmlSchemaDateNormalize(y, -(14 * SECS_PER_HOUR));
3174 q2d = _xmlSchemaDateCastYMToDays(q2) + q2->value.date.day;
3175 if (p1d > q2d)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003176 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003177 else if (p1d == q2d) {
3178 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q2);
3179 if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003180 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003181 else
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003182 ret = 2; /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00003183 }
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003184 xmlSchemaFreeValue(p1);
3185 xmlSchemaFreeValue(q1);
3186 xmlSchemaFreeValue(q2);
3187 if (ret != 0)
3188 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003189 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00003190 } else {
3191 xmlSchemaFreeValue(p1);
3192 xmlSchemaFreeValue(q1);
3193 }
Daniel Veillard5a872412002-05-22 06:40:27 +00003194 }
3195 } else if (y->value.date.tz_flag) {
3196 q1 = xmlSchemaDateNormalize(y, 0);
3197 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
3198
3199 /* normalize x - 14:00 */
3200 p1 = xmlSchemaDateNormalize(x, -(14 * SECS_PER_HOUR));
3201 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3202
Daniel Veillardfdc91562002-07-01 21:52:03 +00003203 if (p1d < q1d) {
3204 xmlSchemaFreeValue(p1);
3205 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003206 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003207 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003208 double sec;
3209
3210 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00003211 if (sec < 0.0) {
3212 xmlSchemaFreeValue(p1);
3213 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003214 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003215 } else {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003216 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003217 /* normalize x + 14:00 */
3218 p2 = xmlSchemaDateNormalize(x, (14 * SECS_PER_HOUR));
3219 p2d = _xmlSchemaDateCastYMToDays(p2) + p2->value.date.day;
3220
Daniel Veillard6560a422003-03-27 21:25:38 +00003221 if (p2d > q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003222 ret = 1;
Daniel Veillard6560a422003-03-27 21:25:38 +00003223 } else if (p2d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003224 sec = TIME_TO_NUMBER(p2) - TIME_TO_NUMBER(q1);
3225 if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003226 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003227 else
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003228 ret = 2; /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00003229 }
Daniel Veillard6560a422003-03-27 21:25:38 +00003230 xmlSchemaFreeValue(p1);
3231 xmlSchemaFreeValue(q1);
3232 xmlSchemaFreeValue(p2);
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003233 if (ret != 0)
3234 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003235 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00003236 } else {
3237 xmlSchemaFreeValue(p1);
3238 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003239 }
3240 }
3241
3242 /*
3243 * if the same type then calculate the difference
3244 */
3245 if (x->type == y->type) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003246 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003247 q1 = xmlSchemaDateNormalize(y, 0);
3248 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
3249
3250 p1 = xmlSchemaDateNormalize(x, 0);
3251 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3252
Daniel Veillardfdc91562002-07-01 21:52:03 +00003253 if (p1d < q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003254 ret = -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003255 } else if (p1d > q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003256 ret = 1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003257 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00003258 double sec;
3259
3260 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
3261 if (sec < 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003262 ret = -1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003263 else if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003264 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003265
3266 }
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003267 xmlSchemaFreeValue(p1);
3268 xmlSchemaFreeValue(q1);
3269 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003270 }
3271
3272 switch (x->type) {
3273 case XML_SCHEMAS_DATETIME:
3274 xmask = 0xf;
3275 break;
3276 case XML_SCHEMAS_DATE:
3277 xmask = 0x7;
3278 break;
3279 case XML_SCHEMAS_GYEAR:
3280 xmask = 0x1;
3281 break;
3282 case XML_SCHEMAS_GMONTH:
3283 xmask = 0x2;
3284 break;
3285 case XML_SCHEMAS_GDAY:
3286 xmask = 0x3;
3287 break;
3288 case XML_SCHEMAS_GYEARMONTH:
3289 xmask = 0x3;
3290 break;
3291 case XML_SCHEMAS_GMONTHDAY:
3292 xmask = 0x6;
3293 break;
3294 case XML_SCHEMAS_TIME:
3295 xmask = 0x8;
3296 break;
3297 default:
3298 xmask = 0;
3299 break;
3300 }
3301
3302 switch (y->type) {
3303 case XML_SCHEMAS_DATETIME:
3304 ymask = 0xf;
3305 break;
3306 case XML_SCHEMAS_DATE:
3307 ymask = 0x7;
3308 break;
3309 case XML_SCHEMAS_GYEAR:
3310 ymask = 0x1;
3311 break;
3312 case XML_SCHEMAS_GMONTH:
3313 ymask = 0x2;
3314 break;
3315 case XML_SCHEMAS_GDAY:
3316 ymask = 0x3;
3317 break;
3318 case XML_SCHEMAS_GYEARMONTH:
3319 ymask = 0x3;
3320 break;
3321 case XML_SCHEMAS_GMONTHDAY:
3322 ymask = 0x6;
3323 break;
3324 case XML_SCHEMAS_TIME:
3325 ymask = 0x8;
3326 break;
3327 default:
3328 ymask = 0;
3329 break;
3330 }
3331
3332 xor_mask = xmask ^ ymask; /* mark type differences */
3333 and_mask = xmask & ymask; /* mark field specification */
3334
3335 /* year */
3336 if (xor_mask & 1)
3337 return 2; /* indeterminate */
3338 else if (and_mask & 1) {
3339 if (x->value.date.year < y->value.date.year)
3340 return -1;
3341 else if (x->value.date.year > y->value.date.year)
3342 return 1;
3343 }
3344
3345 /* month */
3346 if (xor_mask & 2)
3347 return 2; /* indeterminate */
3348 else if (and_mask & 2) {
3349 if (x->value.date.mon < y->value.date.mon)
3350 return -1;
3351 else if (x->value.date.mon > y->value.date.mon)
3352 return 1;
3353 }
3354
3355 /* day */
3356 if (xor_mask & 4)
3357 return 2; /* indeterminate */
3358 else if (and_mask & 4) {
3359 if (x->value.date.day < y->value.date.day)
3360 return -1;
3361 else if (x->value.date.day > y->value.date.day)
3362 return 1;
3363 }
3364
3365 /* time */
3366 if (xor_mask & 8)
3367 return 2; /* indeterminate */
3368 else if (and_mask & 8) {
3369 if (x->value.date.hour < y->value.date.hour)
3370 return -1;
3371 else if (x->value.date.hour > y->value.date.hour)
3372 return 1;
3373 else if (x->value.date.min < y->value.date.min)
3374 return -1;
3375 else if (x->value.date.min > y->value.date.min)
3376 return 1;
3377 else if (x->value.date.sec < y->value.date.sec)
3378 return -1;
3379 else if (x->value.date.sec > y->value.date.sec)
3380 return 1;
3381 }
3382
Daniel Veillard070803b2002-05-03 07:29:38 +00003383 return 0;
3384}
3385
3386/**
Daniel Veillardc4c21552003-03-29 10:53:38 +00003387 * xmlSchemaCompareNormStrings:
3388 * @x: a first string value
3389 * @y: a second string value
3390 *
3391 * Compare 2 string for their normalized values.
3392 *
3393 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
3394 * case of error
3395 */
3396static int
3397xmlSchemaCompareNormStrings(xmlSchemaValPtr x, xmlSchemaValPtr y) {
3398 const xmlChar *utf1;
3399 const xmlChar *utf2;
3400 int tmp;
3401
3402 if ((x == NULL) || (y == NULL))
3403 return(-2);
3404 utf1 = x->value.str;
3405 utf2 = y->value.str;
3406
William M. Brack76e95df2003-10-18 16:20:14 +00003407 while (IS_BLANK_CH(*utf1)) utf1++;
3408 while (IS_BLANK_CH(*utf2)) utf2++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003409 while ((*utf1 != 0) && (*utf2 != 0)) {
William M. Brack76e95df2003-10-18 16:20:14 +00003410 if (IS_BLANK_CH(*utf1)) {
3411 if (!IS_BLANK_CH(*utf2)) {
Daniel Veillardc4c21552003-03-29 10:53:38 +00003412 tmp = *utf1 - *utf2;
3413 return(tmp);
3414 }
William M. Brack76e95df2003-10-18 16:20:14 +00003415 while (IS_BLANK_CH(*utf1)) utf1++;
3416 while (IS_BLANK_CH(*utf2)) utf2++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003417 } else {
3418 tmp = *utf1++ - *utf2++;
3419 if (tmp < 0)
3420 return(-1);
3421 if (tmp > 0)
3422 return(1);
3423 }
3424 }
3425 if (*utf1 != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00003426 while (IS_BLANK_CH(*utf1)) utf1++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003427 if (*utf1 != 0)
3428 return(1);
3429 }
3430 if (*utf2 != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00003431 while (IS_BLANK_CH(*utf2)) utf2++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003432 if (*utf2 != 0)
3433 return(-1);
3434 }
3435 return(0);
3436}
3437
3438/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003439 * xmlSchemaCompareFloats:
3440 * @x: a first float or double value
3441 * @y: a second float or double value
3442 *
3443 * Compare 2 values
3444 *
3445 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3446 * case of error
3447 */
3448static int
3449xmlSchemaCompareFloats(xmlSchemaValPtr x, xmlSchemaValPtr y) {
3450 double d1, d2;
3451
3452 if ((x == NULL) || (y == NULL))
3453 return(-2);
3454
3455 /*
3456 * Cast everything to doubles.
3457 */
3458 if (x->type == XML_SCHEMAS_DOUBLE)
3459 d1 = x->value.d;
3460 else if (x->type == XML_SCHEMAS_FLOAT)
3461 d1 = x->value.f;
3462 else
3463 return(-2);
3464
3465 if (y->type == XML_SCHEMAS_DOUBLE)
3466 d2 = y->value.d;
3467 else if (y->type == XML_SCHEMAS_FLOAT)
3468 d2 = y->value.f;
3469 else
3470 return(-2);
3471
3472 /*
3473 * Check for special cases.
3474 */
3475 if (xmlXPathIsNaN(d1)) {
3476 if (xmlXPathIsNaN(d2))
3477 return(0);
3478 return(1);
3479 }
3480 if (xmlXPathIsNaN(d2))
3481 return(-1);
3482 if (d1 == xmlXPathPINF) {
3483 if (d2 == xmlXPathPINF)
3484 return(0);
3485 return(1);
3486 }
3487 if (d2 == xmlXPathPINF)
3488 return(-1);
3489 if (d1 == xmlXPathNINF) {
3490 if (d2 == xmlXPathNINF)
3491 return(0);
3492 return(-1);
3493 }
3494 if (d2 == xmlXPathNINF)
3495 return(1);
3496
3497 /*
3498 * basic tests, the last one we should have equality, but
3499 * portability is more important than speed and handling
3500 * NaN or Inf in a portable way is always a challenge, so ...
3501 */
3502 if (d1 < d2)
3503 return(-1);
3504 if (d1 > d2)
3505 return(1);
3506 if (d1 == d2)
3507 return(0);
3508 return(2);
3509}
3510
3511/**
Daniel Veillard4255d502002-04-16 15:50:10 +00003512 * xmlSchemaCompareValues:
3513 * @x: a first value
3514 * @y: a second value
3515 *
3516 * Compare 2 values
3517 *
Daniel Veillard5a872412002-05-22 06:40:27 +00003518 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3519 * case of error
Daniel Veillard4255d502002-04-16 15:50:10 +00003520 */
Daniel Veillard80b19092003-03-28 13:29:53 +00003521int
Daniel Veillard4255d502002-04-16 15:50:10 +00003522xmlSchemaCompareValues(xmlSchemaValPtr x, xmlSchemaValPtr y) {
3523 if ((x == NULL) || (y == NULL))
3524 return(-2);
3525
3526 switch (x->type) {
Daniel Veillard80b19092003-03-28 13:29:53 +00003527 case XML_SCHEMAS_UNKNOWN:
3528 return(-2);
3529 case XML_SCHEMAS_INTEGER:
3530 case XML_SCHEMAS_NPINTEGER:
3531 case XML_SCHEMAS_NINTEGER:
3532 case XML_SCHEMAS_NNINTEGER:
3533 case XML_SCHEMAS_PINTEGER:
3534 case XML_SCHEMAS_INT:
3535 case XML_SCHEMAS_UINT:
3536 case XML_SCHEMAS_LONG:
3537 case XML_SCHEMAS_ULONG:
3538 case XML_SCHEMAS_SHORT:
3539 case XML_SCHEMAS_USHORT:
3540 case XML_SCHEMAS_BYTE:
3541 case XML_SCHEMAS_UBYTE:
Daniel Veillard4255d502002-04-16 15:50:10 +00003542 case XML_SCHEMAS_DECIMAL:
Daniel Veillard80b19092003-03-28 13:29:53 +00003543 if (y->type == x->type)
3544 return(xmlSchemaCompareDecimals(x, y));
3545 if ((y->type == XML_SCHEMAS_DECIMAL) ||
3546 (y->type == XML_SCHEMAS_INTEGER) ||
3547 (y->type == XML_SCHEMAS_NPINTEGER) ||
3548 (y->type == XML_SCHEMAS_NINTEGER) ||
3549 (y->type == XML_SCHEMAS_NNINTEGER) ||
3550 (y->type == XML_SCHEMAS_PINTEGER) ||
3551 (y->type == XML_SCHEMAS_INT) ||
3552 (y->type == XML_SCHEMAS_UINT) ||
3553 (y->type == XML_SCHEMAS_LONG) ||
3554 (y->type == XML_SCHEMAS_ULONG) ||
3555 (y->type == XML_SCHEMAS_SHORT) ||
3556 (y->type == XML_SCHEMAS_USHORT) ||
3557 (y->type == XML_SCHEMAS_BYTE) ||
3558 (y->type == XML_SCHEMAS_UBYTE))
Daniel Veillard4255d502002-04-16 15:50:10 +00003559 return(xmlSchemaCompareDecimals(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00003560 return(-2);
Daniel Veillard070803b2002-05-03 07:29:38 +00003561 case XML_SCHEMAS_DURATION:
3562 if (y->type == XML_SCHEMAS_DURATION)
3563 return(xmlSchemaCompareDurations(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00003564 return(-2);
3565 case XML_SCHEMAS_TIME:
3566 case XML_SCHEMAS_GDAY:
3567 case XML_SCHEMAS_GMONTH:
3568 case XML_SCHEMAS_GMONTHDAY:
3569 case XML_SCHEMAS_GYEAR:
3570 case XML_SCHEMAS_GYEARMONTH:
3571 case XML_SCHEMAS_DATE:
3572 case XML_SCHEMAS_DATETIME:
3573 if ((y->type == XML_SCHEMAS_DATETIME) ||
3574 (y->type == XML_SCHEMAS_TIME) ||
3575 (y->type == XML_SCHEMAS_GDAY) ||
3576 (y->type == XML_SCHEMAS_GMONTH) ||
3577 (y->type == XML_SCHEMAS_GMONTHDAY) ||
3578 (y->type == XML_SCHEMAS_GYEAR) ||
3579 (y->type == XML_SCHEMAS_DATE) ||
3580 (y->type == XML_SCHEMAS_GYEARMONTH))
3581 return (xmlSchemaCompareDates(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00003582 return (-2);
Daniel Veillard80b19092003-03-28 13:29:53 +00003583 case XML_SCHEMAS_NORMSTRING:
Daniel Veillard80b19092003-03-28 13:29:53 +00003584 case XML_SCHEMAS_TOKEN:
3585 case XML_SCHEMAS_LANGUAGE:
3586 case XML_SCHEMAS_NMTOKEN:
Daniel Veillard80b19092003-03-28 13:29:53 +00003587 case XML_SCHEMAS_NAME:
Daniel Veillard80b19092003-03-28 13:29:53 +00003588 case XML_SCHEMAS_NCNAME:
3589 case XML_SCHEMAS_ID:
3590 case XML_SCHEMAS_IDREF:
Daniel Veillard80b19092003-03-28 13:29:53 +00003591 case XML_SCHEMAS_ENTITY:
Daniel Veillard80b19092003-03-28 13:29:53 +00003592 case XML_SCHEMAS_NOTATION:
3593 case XML_SCHEMAS_ANYURI:
Daniel Veillardc4c21552003-03-29 10:53:38 +00003594 if ((y->type == XML_SCHEMAS_NORMSTRING) ||
3595 (y->type == XML_SCHEMAS_TOKEN) ||
3596 (y->type == XML_SCHEMAS_LANGUAGE) ||
3597 (y->type == XML_SCHEMAS_NMTOKEN) ||
3598 (y->type == XML_SCHEMAS_NAME) ||
3599 (y->type == XML_SCHEMAS_QNAME) ||
3600 (y->type == XML_SCHEMAS_NCNAME) ||
3601 (y->type == XML_SCHEMAS_ID) ||
3602 (y->type == XML_SCHEMAS_IDREF) ||
3603 (y->type == XML_SCHEMAS_ENTITY) ||
3604 (y->type == XML_SCHEMAS_NOTATION) ||
3605 (y->type == XML_SCHEMAS_ANYURI))
3606 return (xmlSchemaCompareNormStrings(x, y));
3607 return (-2);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003608 case XML_SCHEMAS_QNAME:
3609 if (y->type == XML_SCHEMAS_QNAME) {
3610 if ((xmlStrEqual(x->value.qname.name, y->value.qname.name)) &&
3611 (xmlStrEqual(x->value.qname.uri, y->value.qname.uri)))
3612 return(0);
3613 return(2);
3614 }
3615 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00003616 case XML_SCHEMAS_FLOAT:
3617 case XML_SCHEMAS_DOUBLE:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003618 if ((y->type == XML_SCHEMAS_FLOAT) ||
3619 (y->type == XML_SCHEMAS_DOUBLE))
3620 return (xmlSchemaCompareFloats(x, y));
3621 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00003622 case XML_SCHEMAS_BOOLEAN:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003623 if (y->type == XML_SCHEMAS_BOOLEAN) {
3624 if (x->value.b == y->value.b)
3625 return(0);
3626 if (x->value.b == 0)
3627 return(-1);
3628 return(1);
3629 }
3630 return (-2);
Daniel Veillard560c2a42003-07-06 21:13:49 +00003631 case XML_SCHEMAS_HEXBINARY:
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00003632 if (y->type == XML_SCHEMAS_HEXBINARY) {
3633 if (x->value.hex.total == y->value.hex.total) {
3634 int ret = xmlStrcmp(x->value.hex.str, y->value.hex.str);
3635 if (ret > 0)
3636 return(1);
3637 else if (ret == 0)
3638 return(0);
3639 }
3640 else if (x->value.hex.total > y->value.hex.total)
3641 return(1);
3642
3643 return(-1);
3644 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00003645 return (-2);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003646 case XML_SCHEMAS_BASE64BINARY:
3647 if (y->type == XML_SCHEMAS_BASE64BINARY) {
3648 if (x->value.base64.total == y->value.base64.total) {
3649 int ret = xmlStrcmp(x->value.base64.str,
3650 y->value.base64.str);
3651 if (ret > 0)
3652 return(1);
3653 else if (ret == 0)
3654 return(0);
3655 }
3656 else if (x->value.base64.total > y->value.base64.total)
3657 return(1);
3658 else
3659 return(-1);
3660 }
3661 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00003662 case XML_SCHEMAS_STRING:
3663 case XML_SCHEMAS_IDREFS:
3664 case XML_SCHEMAS_ENTITIES:
3665 case XML_SCHEMAS_NMTOKENS:
3666 TODO
3667 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00003668 }
Daniel Veillard5a872412002-05-22 06:40:27 +00003669 return -2;
Daniel Veillard4255d502002-04-16 15:50:10 +00003670}
3671
3672/**
Daniel Veillardc4c21552003-03-29 10:53:38 +00003673 * xmlSchemaNormLen:
3674 * @value: a string
3675 *
3676 * Computes the UTF8 length of the normalized value of the string
3677 *
3678 * Returns the length or -1 in case of error.
3679 */
3680static int
3681xmlSchemaNormLen(const xmlChar *value) {
3682 const xmlChar *utf;
3683 int ret = 0;
3684
3685 if (value == NULL)
3686 return(-1);
3687 utf = value;
William M. Brack76e95df2003-10-18 16:20:14 +00003688 while (IS_BLANK_CH(*utf)) utf++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003689 while (*utf != 0) {
3690 if (utf[0] & 0x80) {
3691 if ((utf[1] & 0xc0) != 0x80)
3692 return(-1);
3693 if ((utf[0] & 0xe0) == 0xe0) {
3694 if ((utf[2] & 0xc0) != 0x80)
3695 return(-1);
3696 if ((utf[0] & 0xf0) == 0xf0) {
3697 if ((utf[0] & 0xf8) != 0xf0 || (utf[3] & 0xc0) != 0x80)
3698 return(-1);
3699 utf += 4;
3700 } else {
3701 utf += 3;
3702 }
3703 } else {
3704 utf += 2;
3705 }
William M. Brack76e95df2003-10-18 16:20:14 +00003706 } else if (IS_BLANK_CH(*utf)) {
3707 while (IS_BLANK_CH(*utf)) utf++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003708 if (*utf == 0)
3709 break;
3710 } else {
3711 utf++;
3712 }
3713 ret++;
3714 }
3715 return(ret);
3716}
3717
3718/**
Daniel Veillard01fa6152004-06-29 17:04:39 +00003719 * xmlSchemaValidateListSimpleTypeFacet:
3720 * @facet: the facet to check
3721 * @value: the lexical repr of the value to validate
3722 * @actualLen: the number of list items
3723 * @expectedLen: the resulting expected number of list items
3724 *
3725 * Checks the value of a list simple type against a facet.
3726 *
3727 * Returns 0 if the value is valid, a positive error code
3728 * number otherwise and -1 in case of an internal error.
3729 */
3730int
3731xmlSchemaValidateListSimpleTypeFacet(xmlSchemaFacetPtr facet,
3732 const xmlChar *value,
3733 unsigned long actualLen,
3734 unsigned long *expectedLen)
3735{
3736 /*
3737 * TODO: Check if this will work with large numbers.
3738 * (compare value.decimal.mi and value.decimal.hi as well?).
3739 */
3740 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
3741 if (actualLen != facet->val->value.decimal.lo) {
3742 *expectedLen = facet->val->value.decimal.lo;
3743 return (XML_SCHEMAV_CVC_LENGTH_VALID);
3744 }
3745 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
3746 if (actualLen < facet->val->value.decimal.lo) {
3747 *expectedLen = facet->val->value.decimal.lo;
3748 return (XML_SCHEMAV_CVC_MINLENGTH_VALID);
3749 }
3750 } else if (facet->type == XML_SCHEMA_FACET_MAXLENGTH) {
3751 if (actualLen > facet->val->value.decimal.lo) {
3752 *expectedLen = facet->val->value.decimal.lo;
3753 return (XML_SCHEMAV_CVC_MAXLENGTH_VALID);
3754 }
3755 } else
3756 /*
3757 * NOTE: That we can pass NULL as xmlSchemaValPtr to
3758 * xmlSchemaValidateFacet, since the remaining facet types
3759 * are: XML_SCHEMA_FACET_PATTERN, XML_SCHEMA_FACET_ENUMERATION.
3760 */
3761 return(xmlSchemaValidateFacet(NULL, facet, value, NULL));
3762 return (0);
3763}
3764
3765/**
Daniel Veillard4255d502002-04-16 15:50:10 +00003766 * xmlSchemaValidateFacet:
Daniel Veillard01c13b52002-12-10 15:19:08 +00003767 * @base: the base type
Daniel Veillard4255d502002-04-16 15:50:10 +00003768 * @facet: the facet to check
3769 * @value: the lexical repr of the value to validate
3770 * @val: the precomputed value
3771 *
3772 * Check a value against a facet condition
3773 *
3774 * Returns 0 if the element is schemas valid, a positive error code
3775 * number otherwise and -1 in case of internal or API error.
3776 */
3777int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00003778xmlSchemaValidateFacet(xmlSchemaTypePtr base ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +00003779 xmlSchemaFacetPtr facet,
Daniel Veillard4255d502002-04-16 15:50:10 +00003780 const xmlChar *value, xmlSchemaValPtr val)
3781{
3782 int ret;
3783
3784 switch (facet->type) {
3785 case XML_SCHEMA_FACET_PATTERN:
3786 ret = xmlRegexpExec(facet->regexp, value);
3787 if (ret == 1)
3788 return(0);
3789 if (ret == 0) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00003790 return(XML_SCHEMAV_CVC_PATTERN_VALID);
Daniel Veillard4255d502002-04-16 15:50:10 +00003791 }
3792 return(ret);
3793 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
3794 ret = xmlSchemaCompareValues(val, facet->val);
3795 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003796 /* TODO error code */
Daniel Veillard4255d502002-04-16 15:50:10 +00003797 return(-1);
3798 }
3799 if (ret == -1)
3800 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00003801 /* error code */
Daniel Veillard01fa6152004-06-29 17:04:39 +00003802 return(XML_SCHEMAV_CVC_MAXEXCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00003803 case XML_SCHEMA_FACET_MAXINCLUSIVE:
3804 ret = xmlSchemaCompareValues(val, facet->val);
3805 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003806 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00003807 return(-1);
3808 }
3809 if ((ret == -1) || (ret == 0))
3810 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00003811 /* error code */
Daniel Veillard01fa6152004-06-29 17:04:39 +00003812 return(XML_SCHEMAV_CVC_MAXINCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00003813 case XML_SCHEMA_FACET_MINEXCLUSIVE:
3814 ret = xmlSchemaCompareValues(val, facet->val);
3815 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003816 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00003817 return(-1);
3818 }
3819 if (ret == 1)
3820 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00003821 /* error code */
Daniel Veillard01fa6152004-06-29 17:04:39 +00003822 return(XML_SCHEMAV_CVC_MINEXCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00003823 case XML_SCHEMA_FACET_MININCLUSIVE:
3824 ret = xmlSchemaCompareValues(val, facet->val);
3825 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003826 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00003827 return(-1);
3828 }
3829 if ((ret == 1) || (ret == 0))
3830 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00003831 /* error code */
Daniel Veillard01fa6152004-06-29 17:04:39 +00003832 return(XML_SCHEMAV_CVC_MININCLUSIVE_VALID);
Daniel Veillard8651f532002-04-17 09:06:27 +00003833 case XML_SCHEMA_FACET_WHITESPACE:
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003834 /* TODO whitespaces */
Daniel Veillard01fa6152004-06-29 17:04:39 +00003835 /*
3836 * NOTE: Whitespace should be handled to normalize
3837 * the value to be validated against a the facets;
3838 * not to normalize the value in-between.
3839 */
Daniel Veillard8651f532002-04-17 09:06:27 +00003840 return(0);
Daniel Veillard88c58912002-04-23 07:12:20 +00003841 case XML_SCHEMA_FACET_ENUMERATION:
3842 if ((facet->value != NULL) &&
3843 (xmlStrEqual(facet->value, value)))
3844 return(0);
Daniel Veillard01fa6152004-06-29 17:04:39 +00003845 return(XML_SCHEMAV_CVC_ENUMERATION_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003846 case XML_SCHEMA_FACET_LENGTH:
3847 case XML_SCHEMA_FACET_MAXLENGTH:
3848 case XML_SCHEMA_FACET_MINLENGTH: {
3849 unsigned int len = 0;
3850
3851 if ((facet->val == NULL) ||
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003852 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
3853 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003854 (facet->val->value.decimal.frac != 0)) {
3855 return(-1);
3856 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00003857 if ((val != NULL) && (val->type == XML_SCHEMAS_HEXBINARY))
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00003858 len = val->value.hex.total;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003859 else if ((val != NULL) && (val->type == XML_SCHEMAS_BASE64BINARY))
3860 len = val->value.base64.total;
3861 else {
Daniel Veillard01fa6152004-06-29 17:04:39 +00003862 switch (base->builtInType) {
Daniel Veillard560c2a42003-07-06 21:13:49 +00003863 case XML_SCHEMAS_IDREF:
3864 case XML_SCHEMAS_NORMSTRING:
3865 case XML_SCHEMAS_TOKEN:
3866 case XML_SCHEMAS_LANGUAGE:
3867 case XML_SCHEMAS_NMTOKEN:
3868 case XML_SCHEMAS_NAME:
3869 case XML_SCHEMAS_NCNAME:
3870 case XML_SCHEMAS_ID:
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00003871 len = xmlSchemaNormLen(value);
3872 break;
Daniel Veillard560c2a42003-07-06 21:13:49 +00003873 case XML_SCHEMAS_STRING:
Daniel Veillard01fa6152004-06-29 17:04:39 +00003874 /*
3875 * FIXME: What exactly to do with anyURI?
3876 */
3877 case XML_SCHEMAS_ANYURI:
William M. Brackfbf2c5e2004-02-03 17:55:56 +00003878 if (value != NULL)
3879 len = xmlUTF8Strlen(value);
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00003880 break;
Daniel Veillard560c2a42003-07-06 21:13:49 +00003881 default:
3882 TODO
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00003883 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003884 }
3885 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003886 if (len != facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00003887 return(XML_SCHEMAV_CVC_LENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003888 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003889 if (len < facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00003890 return(XML_SCHEMAV_CVC_MINLENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003891 } else {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003892 if (len > facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00003893 return(XML_SCHEMAV_CVC_MAXLENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003894 }
3895 break;
3896 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00003897 case XML_SCHEMA_FACET_TOTALDIGITS:
3898 case XML_SCHEMA_FACET_FRACTIONDIGITS:
3899
3900 if ((facet->val == NULL) ||
3901 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
3902 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
3903 (facet->val->value.decimal.frac != 0)) {
3904 return(-1);
3905 }
3906 if ((val == NULL) ||
3907 ((val->type != XML_SCHEMAS_DECIMAL) &&
3908 (val->type != XML_SCHEMAS_INTEGER) &&
3909 (val->type != XML_SCHEMAS_NPINTEGER) &&
3910 (val->type != XML_SCHEMAS_NINTEGER) &&
3911 (val->type != XML_SCHEMAS_NNINTEGER) &&
3912 (val->type != XML_SCHEMAS_PINTEGER) &&
3913 (val->type != XML_SCHEMAS_INT) &&
3914 (val->type != XML_SCHEMAS_UINT) &&
3915 (val->type != XML_SCHEMAS_LONG) &&
3916 (val->type != XML_SCHEMAS_ULONG) &&
3917 (val->type != XML_SCHEMAS_SHORT) &&
3918 (val->type != XML_SCHEMAS_USHORT) &&
3919 (val->type != XML_SCHEMAS_BYTE) &&
3920 (val->type != XML_SCHEMAS_UBYTE))) {
3921 return(-1);
3922 }
3923 if (facet->type == XML_SCHEMA_FACET_TOTALDIGITS) {
3924 if (val->value.decimal.total > facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00003925 return(XML_SCHEMAV_CVC_TOTALDIGITS_VALID);
Daniel Veillard560c2a42003-07-06 21:13:49 +00003926
3927 } else if (facet->type == XML_SCHEMA_FACET_FRACTIONDIGITS) {
3928 if (val->value.decimal.frac > facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00003929 return(XML_SCHEMAV_CVC_FRACTIONDIGITS_VALID);
Daniel Veillard560c2a42003-07-06 21:13:49 +00003930 }
3931 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00003932 default:
3933 TODO
3934 }
3935 return(0);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003936
Daniel Veillard4255d502002-04-16 15:50:10 +00003937}
3938
3939#endif /* LIBXML_SCHEMAS_ENABLED */