blob: 9346ac69ac5f8357d3df254b7174698a4aff9d4a [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;
William M. Brack2f2a6632004-08-20 23:09:47 +0000229 else if ((type != XML_SCHEMAS_ANYTYPE) &&
230 (type != XML_SCHEMAS_ANYSIMPLETYPE))
Daniel Veillard01fa6152004-06-29 17:04:39 +0000231 ret->flags |= XML_SCHEMAS_TYPE_VARIETY_ATOMIC;
Daniel Veillard4255d502002-04-16 15:50:10 +0000232 ret->contentType = XML_SCHEMA_CONTENT_BASIC;
Daniel Veillard01fa6152004-06-29 17:04:39 +0000233 switch (type) {
234 case XML_SCHEMAS_STRING:
235 case XML_SCHEMAS_DECIMAL:
236 case XML_SCHEMAS_DATE:
237 case XML_SCHEMAS_DATETIME:
238 case XML_SCHEMAS_TIME:
239 case XML_SCHEMAS_GYEAR:
240 case XML_SCHEMAS_GYEARMONTH:
241 case XML_SCHEMAS_GMONTH:
242 case XML_SCHEMAS_GMONTHDAY:
243 case XML_SCHEMAS_GDAY:
244 case XML_SCHEMAS_DURATION:
245 case XML_SCHEMAS_FLOAT:
246 case XML_SCHEMAS_DOUBLE:
247 case XML_SCHEMAS_BOOLEAN:
248 case XML_SCHEMAS_ANYURI:
249 case XML_SCHEMAS_HEXBINARY:
250 case XML_SCHEMAS_BASE64BINARY:
251 case XML_SCHEMAS_QNAME:
252 case XML_SCHEMAS_NOTATION:
253 ret->flags |= XML_SCHEMAS_TYPE_BUILTIN_PRIMITIVE;
William M. Brack96d2eff2004-06-30 11:48:47 +0000254 default:
255 break;
Daniel Veillard01fa6152004-06-29 17:04:39 +0000256 }
257
Daniel Veillard4255d502002-04-16 15:50:10 +0000258 xmlHashAddEntry2(xmlSchemaTypesBank, ret->name,
259 XML_SCHEMAS_NAMESPACE_NAME, ret);
Daniel Veillard01fa6152004-06-29 17:04:39 +0000260 ret->builtInType = type;
Daniel Veillard4255d502002-04-16 15:50:10 +0000261 return(ret);
262}
263
264/*
265 * xmlSchemaInitTypes:
266 *
267 * Initialize the default XML Schemas type library
268 */
269void
Daniel Veillard6560a422003-03-27 21:25:38 +0000270xmlSchemaInitTypes(void)
271{
Daniel Veillard4255d502002-04-16 15:50:10 +0000272 if (xmlSchemaTypesInitialized != 0)
Daniel Veillard6560a422003-03-27 21:25:38 +0000273 return;
Daniel Veillard4255d502002-04-16 15:50:10 +0000274 xmlSchemaTypesBank = xmlHashCreate(40);
Daniel Veillard6560a422003-03-27 21:25:38 +0000275
Daniel Veillard01fa6152004-06-29 17:04:39 +0000276
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000277 /*
Daniel Veillard01fa6152004-06-29 17:04:39 +0000278 * 3.4.7 Built-in Complex Type Definition
279 */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000280 xmlSchemaTypeAnyTypeDef = xmlSchemaInitBasicType("anyType",
William M. Brack2f2a6632004-08-20 23:09:47 +0000281 XML_SCHEMAS_ANYTYPE,
Daniel Veillard01fa6152004-06-29 17:04:39 +0000282 NULL);
283 xmlSchemaTypeAnyTypeDef->baseType = xmlSchemaTypeAnyTypeDef;
284 xmlSchemaTypeAnyTypeDef->contentType = XML_SCHEMA_CONTENT_MIXED;
285 {
286 xmlSchemaWildcardPtr wild;
287
288 wild = (xmlSchemaWildcardPtr) xmlMalloc(sizeof(xmlSchemaWildcard));
289 if (wild == NULL) {
William M. Brack2f2a6632004-08-20 23:09:47 +0000290 xmlSchemaTypeErrMemory(NULL, "could not create an attribute wildcard on anyType");
Daniel Veillard01fa6152004-06-29 17:04:39 +0000291 return;
292 }
293 memset(wild, 0, sizeof(xmlSchemaWildcard));
294 wild->any = 1;
295 wild->processContents = XML_SCHEMAS_ANY_LAX;
296 wild->minOccurs = 1;
297 wild->maxOccurs = 1;
298 xmlSchemaTypeAnyTypeDef->attributeWildcard = wild;
299 }
300 xmlSchemaTypeAnySimpleTypeDef = xmlSchemaInitBasicType("anySimpleType",
William M. Brack2f2a6632004-08-20 23:09:47 +0000301 XML_SCHEMAS_ANYSIMPLETYPE,
Daniel Veillard01fa6152004-06-29 17:04:39 +0000302 xmlSchemaTypeAnyTypeDef);
303 /*
304 * primitive datatypes
305 */
306 xmlSchemaTypeStringDef = xmlSchemaInitBasicType("string",
307 XML_SCHEMAS_STRING,
308 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000309 xmlSchemaTypeDecimalDef = xmlSchemaInitBasicType("decimal",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000310 XML_SCHEMAS_DECIMAL,
311 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000312 xmlSchemaTypeDateDef = xmlSchemaInitBasicType("date",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000313 XML_SCHEMAS_DATE,
314 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000315 xmlSchemaTypeDatetimeDef = xmlSchemaInitBasicType("dateTime",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000316 XML_SCHEMAS_DATETIME,
317 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000318 xmlSchemaTypeTimeDef = xmlSchemaInitBasicType("time",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000319 XML_SCHEMAS_TIME,
320 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000321 xmlSchemaTypeGYearDef = xmlSchemaInitBasicType("gYear",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000322 XML_SCHEMAS_GYEAR,
323 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000324 xmlSchemaTypeGYearMonthDef = xmlSchemaInitBasicType("gYearMonth",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000325 XML_SCHEMAS_GYEARMONTH,
326 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000327 xmlSchemaTypeGMonthDef = xmlSchemaInitBasicType("gMonth",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000328 XML_SCHEMAS_GMONTH,
329 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000330 xmlSchemaTypeGMonthDayDef = xmlSchemaInitBasicType("gMonthDay",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000331 XML_SCHEMAS_GMONTHDAY,
332 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000333 xmlSchemaTypeGDayDef = xmlSchemaInitBasicType("gDay",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000334 XML_SCHEMAS_GDAY,
335 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000336 xmlSchemaTypeDurationDef = xmlSchemaInitBasicType("duration",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000337 XML_SCHEMAS_DURATION,
338 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000339 xmlSchemaTypeFloatDef = xmlSchemaInitBasicType("float",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000340 XML_SCHEMAS_FLOAT,
341 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000342 xmlSchemaTypeDoubleDef = xmlSchemaInitBasicType("double",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000343 XML_SCHEMAS_DOUBLE,
344 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000345 xmlSchemaTypeBooleanDef = xmlSchemaInitBasicType("boolean",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000346 XML_SCHEMAS_BOOLEAN,
347 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000348 xmlSchemaTypeAnyURIDef = xmlSchemaInitBasicType("anyURI",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000349 XML_SCHEMAS_ANYURI,
350 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard560c2a42003-07-06 21:13:49 +0000351 xmlSchemaTypeHexBinaryDef = xmlSchemaInitBasicType("hexBinary",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000352 XML_SCHEMAS_HEXBINARY,
353 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard1ac24d32003-08-27 14:15:15 +0000354 xmlSchemaTypeBase64BinaryDef
Daniel Veillard01fa6152004-06-29 17:04:39 +0000355 = xmlSchemaInitBasicType("base64Binary", XML_SCHEMAS_BASE64BINARY,
356 xmlSchemaTypeAnySimpleTypeDef);
357 xmlSchemaTypeNotationDef = xmlSchemaInitBasicType("NOTATION",
358 XML_SCHEMAS_NOTATION,
359 xmlSchemaTypeAnySimpleTypeDef);
360 xmlSchemaTypeQNameDef = xmlSchemaInitBasicType("QName",
361 XML_SCHEMAS_QNAME,
362 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard4255d502002-04-16 15:50:10 +0000363
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000364 /*
365 * derived datatypes
366 */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000367 xmlSchemaTypeIntegerDef = xmlSchemaInitBasicType("integer",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000368 XML_SCHEMAS_INTEGER,
369 xmlSchemaTypeDecimalDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000370 xmlSchemaTypeNonPositiveIntegerDef =
371 xmlSchemaInitBasicType("nonPositiveInteger",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000372 XML_SCHEMAS_NPINTEGER,
373 xmlSchemaTypeIntegerDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000374 xmlSchemaTypeNegativeIntegerDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000375 xmlSchemaInitBasicType("negativeInteger", XML_SCHEMAS_NINTEGER,
376 xmlSchemaTypeNonPositiveIntegerDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000377 xmlSchemaTypeLongDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000378 xmlSchemaInitBasicType("long", XML_SCHEMAS_LONG,
379 xmlSchemaTypeIntegerDef);
380 xmlSchemaTypeIntDef = xmlSchemaInitBasicType("int", XML_SCHEMAS_INT,
381 xmlSchemaTypeLongDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000382 xmlSchemaTypeShortDef = xmlSchemaInitBasicType("short",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000383 XML_SCHEMAS_SHORT,
384 xmlSchemaTypeIntDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000385 xmlSchemaTypeByteDef = xmlSchemaInitBasicType("byte",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000386 XML_SCHEMAS_BYTE,
387 xmlSchemaTypeShortDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000388 xmlSchemaTypeNonNegativeIntegerDef =
389 xmlSchemaInitBasicType("nonNegativeInteger",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000390 XML_SCHEMAS_NNINTEGER,
391 xmlSchemaTypeIntegerDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000392 xmlSchemaTypeUnsignedLongDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000393 xmlSchemaInitBasicType("unsignedLong", XML_SCHEMAS_ULONG,
394 xmlSchemaTypeNonNegativeIntegerDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000395 xmlSchemaTypeUnsignedIntDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000396 xmlSchemaInitBasicType("unsignedInt", XML_SCHEMAS_UINT,
397 xmlSchemaTypeUnsignedLongDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000398 xmlSchemaTypeUnsignedShortDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000399 xmlSchemaInitBasicType("unsignedShort", XML_SCHEMAS_USHORT,
400 xmlSchemaTypeUnsignedIntDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000401 xmlSchemaTypeUnsignedByteDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000402 xmlSchemaInitBasicType("unsignedByte", XML_SCHEMAS_UBYTE,
403 xmlSchemaTypeUnsignedShortDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000404 xmlSchemaTypePositiveIntegerDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000405 xmlSchemaInitBasicType("positiveInteger", XML_SCHEMAS_PINTEGER,
406 xmlSchemaTypeNonNegativeIntegerDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000407 xmlSchemaTypeNormStringDef = xmlSchemaInitBasicType("normalizedString",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000408 XML_SCHEMAS_NORMSTRING,
409 xmlSchemaTypeStringDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000410 xmlSchemaTypeTokenDef = xmlSchemaInitBasicType("token",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000411 XML_SCHEMAS_TOKEN,
412 xmlSchemaTypeNormStringDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000413 xmlSchemaTypeLanguageDef = xmlSchemaInitBasicType("language",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000414 XML_SCHEMAS_LANGUAGE,
415 xmlSchemaTypeTokenDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000416 xmlSchemaTypeNameDef = xmlSchemaInitBasicType("Name",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000417 XML_SCHEMAS_NAME,
418 xmlSchemaTypeTokenDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000419 xmlSchemaTypeNmtokenDef = xmlSchemaInitBasicType("NMTOKEN",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000420 XML_SCHEMAS_NMTOKEN,
421 xmlSchemaTypeTokenDef);
422 xmlSchemaTypeNCNameDef = xmlSchemaInitBasicType("NCName",
423 XML_SCHEMAS_NCNAME,
424 xmlSchemaTypeNameDef);
425 xmlSchemaTypeIdDef = xmlSchemaInitBasicType("ID", XML_SCHEMAS_ID,
426 xmlSchemaTypeNCNameDef);
427 xmlSchemaTypeIdrefDef = xmlSchemaInitBasicType("IDREF",
428 XML_SCHEMAS_IDREF,
429 xmlSchemaTypeNCNameDef);
430 xmlSchemaTypeIdrefsDef = xmlSchemaInitBasicType("IDREFS",
431 XML_SCHEMAS_IDREFS,
432 xmlSchemaTypeIdrefDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000433 xmlSchemaTypeNmtokensDef = xmlSchemaInitBasicType("NMTOKENS",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000434 XML_SCHEMAS_NMTOKENS,
435 xmlSchemaTypeNmtokenDef);
436 xmlSchemaTypeEntityDef = xmlSchemaInitBasicType("ENTITY",
437 XML_SCHEMAS_ENTITY,
438 xmlSchemaTypeNCNameDef);
439 xmlSchemaTypeEntitiesDef = xmlSchemaInitBasicType("ENTITIES",
440 XML_SCHEMAS_ENTITIES,
441 xmlSchemaTypeNCNameDef);
Daniel Veillard4255d502002-04-16 15:50:10 +0000442 xmlSchemaTypesInitialized = 1;
443}
444
445/**
446 * xmlSchemaCleanupTypes:
447 *
448 * Cleanup the default XML Schemas type library
449 */
450void
451xmlSchemaCleanupTypes(void) {
452 if (xmlSchemaTypesInitialized == 0)
453 return;
Daniel Veillard01fa6152004-06-29 17:04:39 +0000454 xmlSchemaFreeWildcard(xmlSchemaTypeAnyTypeDef->attributeWildcard);
Daniel Veillard4255d502002-04-16 15:50:10 +0000455 xmlHashFree(xmlSchemaTypesBank, (xmlHashDeallocator) xmlSchemaFreeType);
456 xmlSchemaTypesInitialized = 0;
457}
458
459/**
Daniel Veillard6927b102004-10-27 17:29:04 +0000460 * xmlSchemaIsBuiltInTypeFacet:
Daniel Veillard01fa6152004-06-29 17:04:39 +0000461 * @type: the built-in type
462 * @facetType: the facet type
463 *
464 * Evaluates if a specific facet can be
465 * used in conjunction with a type.
466 *
467 * Returns 1 if the facet can be used with the given built-in type,
468 * 0 otherwise and -1 in case the type is not a built-in type.
469 */
470int
471xmlSchemaIsBuiltInTypeFacet(xmlSchemaTypePtr type, int facetType)
472{
473 if (type->type != XML_SCHEMA_TYPE_BASIC)
474 return (-1);
475 switch (type->builtInType) {
476 case XML_SCHEMAS_BOOLEAN:
477 if ((facetType == XML_SCHEMA_FACET_PATTERN) ||
478 (facetType == XML_SCHEMA_FACET_WHITESPACE))
479 return (1);
480 else
481 return (0);
482 case XML_SCHEMAS_STRING:
483 case XML_SCHEMAS_NOTATION:
484 case XML_SCHEMAS_QNAME:
485 case XML_SCHEMAS_ANYURI:
486 case XML_SCHEMAS_BASE64BINARY:
487 case XML_SCHEMAS_HEXBINARY:
488 if ((facetType == XML_SCHEMA_FACET_LENGTH) ||
489 (facetType == XML_SCHEMA_FACET_MINLENGTH) ||
490 (facetType == XML_SCHEMA_FACET_MAXLENGTH) ||
491 (facetType == XML_SCHEMA_FACET_PATTERN) ||
492 (facetType == XML_SCHEMA_FACET_ENUMERATION) ||
493 (facetType == XML_SCHEMA_FACET_WHITESPACE))
494 return (1);
495 else
496 return (0);
497 case XML_SCHEMAS_DECIMAL:
498 if ((facetType == XML_SCHEMA_FACET_TOTALDIGITS) ||
499 (facetType == XML_SCHEMA_FACET_FRACTIONDIGITS) ||
500 (facetType == XML_SCHEMA_FACET_PATTERN) ||
501 (facetType == XML_SCHEMA_FACET_WHITESPACE) ||
502 (facetType == XML_SCHEMA_FACET_ENUMERATION) ||
503 (facetType == XML_SCHEMA_FACET_MAXINCLUSIVE) ||
504 (facetType == XML_SCHEMA_FACET_MAXEXCLUSIVE) ||
505 (facetType == XML_SCHEMA_FACET_MININCLUSIVE) ||
506 (facetType == XML_SCHEMA_FACET_MINEXCLUSIVE))
507 return (1);
508 else
509 return (0);
510 case XML_SCHEMAS_TIME:
511 case XML_SCHEMAS_GDAY:
512 case XML_SCHEMAS_GMONTH:
513 case XML_SCHEMAS_GMONTHDAY:
514 case XML_SCHEMAS_GYEAR:
515 case XML_SCHEMAS_GYEARMONTH:
516 case XML_SCHEMAS_DATE:
517 case XML_SCHEMAS_DATETIME:
518 case XML_SCHEMAS_DURATION:
519 case XML_SCHEMAS_FLOAT:
520 case XML_SCHEMAS_DOUBLE:
521 if ((facetType == XML_SCHEMA_FACET_PATTERN) ||
522 (facetType == XML_SCHEMA_FACET_ENUMERATION) ||
523 (facetType == XML_SCHEMA_FACET_WHITESPACE) ||
524 (facetType == XML_SCHEMA_FACET_MAXINCLUSIVE) ||
525 (facetType == XML_SCHEMA_FACET_MAXEXCLUSIVE) ||
526 (facetType == XML_SCHEMA_FACET_MININCLUSIVE) ||
527 (facetType == XML_SCHEMA_FACET_MINEXCLUSIVE))
528 return (1);
529 else
530 return (0);
531 default:
Daniel Veillardc7e3cc42004-09-28 12:33:52 +0000532 break;
Daniel Veillard01fa6152004-06-29 17:04:39 +0000533 }
534 return (0);
535}
536
537/**
538 * xmlSchemaGetBuiltInType:
539 * @type: the type of the built in type
540 *
541 * Gives you the type struct for a built-in
542 * type by its type id.
543 *
544 * Returns the type if found, NULL otherwise.
545 */
546xmlSchemaTypePtr
547xmlSchemaGetBuiltInType(xmlSchemaValType type)
548{
549 if (xmlSchemaTypesInitialized == 0)
550 xmlSchemaInitTypes();
551 switch (type) {
552
553 case XML_SCHEMAS_ANYSIMPLETYPE:
554 return (xmlSchemaTypeAnySimpleTypeDef);
555 case XML_SCHEMAS_STRING:
556 return (xmlSchemaTypeStringDef);
557 case XML_SCHEMAS_NORMSTRING:
558 return (xmlSchemaTypeNormStringDef);
559 case XML_SCHEMAS_DECIMAL:
560 return (xmlSchemaTypeDecimalDef);
561 case XML_SCHEMAS_TIME:
562 return (xmlSchemaTypeTimeDef);
563 case XML_SCHEMAS_GDAY:
564 return (xmlSchemaTypeGDayDef);
565 case XML_SCHEMAS_GMONTH:
566 return (xmlSchemaTypeGMonthDef);
567 case XML_SCHEMAS_GMONTHDAY:
568 return (xmlSchemaTypeGMonthDayDef);
569 case XML_SCHEMAS_GYEAR:
570 return (xmlSchemaTypeGYearDef);
571 case XML_SCHEMAS_GYEARMONTH:
572 return (xmlSchemaTypeGYearMonthDef);
573 case XML_SCHEMAS_DATE:
574 return (xmlSchemaTypeDateDef);
575 case XML_SCHEMAS_DATETIME:
576 return (xmlSchemaTypeDatetimeDef);
577 case XML_SCHEMAS_DURATION:
578 return (xmlSchemaTypeDurationDef);
579 case XML_SCHEMAS_FLOAT:
580 return (xmlSchemaTypeFloatDef);
581 case XML_SCHEMAS_DOUBLE:
582 return (xmlSchemaTypeDoubleDef);
583 case XML_SCHEMAS_BOOLEAN:
584 return (xmlSchemaTypeBooleanDef);
585 case XML_SCHEMAS_TOKEN:
586 return (xmlSchemaTypeTokenDef);
587 case XML_SCHEMAS_LANGUAGE:
588 return (xmlSchemaTypeLanguageDef);
589 case XML_SCHEMAS_NMTOKEN:
590 return (xmlSchemaTypeNmtokenDef);
591 case XML_SCHEMAS_NMTOKENS:
592 return (xmlSchemaTypeNmtokensDef);
593 case XML_SCHEMAS_NAME:
594 return (xmlSchemaTypeNameDef);
595 case XML_SCHEMAS_QNAME:
596 return (xmlSchemaTypeQNameDef);
597 case XML_SCHEMAS_NCNAME:
598 return (xmlSchemaTypeNCNameDef);
599 case XML_SCHEMAS_ID:
600 return (xmlSchemaTypeIdDef);
601 case XML_SCHEMAS_IDREF:
602 return (xmlSchemaTypeIdrefDef);
603 case XML_SCHEMAS_IDREFS:
604 return (xmlSchemaTypeIdrefsDef);
605 case XML_SCHEMAS_ENTITY:
606 return (xmlSchemaTypeEntityDef);
607 case XML_SCHEMAS_ENTITIES:
608 return (xmlSchemaTypeEntitiesDef);
609 case XML_SCHEMAS_NOTATION:
610 return (xmlSchemaTypeNotationDef);
611 case XML_SCHEMAS_ANYURI:
612 return (xmlSchemaTypeAnyURIDef);
613 case XML_SCHEMAS_INTEGER:
614 return (xmlSchemaTypeIntegerDef);
615 case XML_SCHEMAS_NPINTEGER:
616 return (xmlSchemaTypeNonPositiveIntegerDef);
617 case XML_SCHEMAS_NINTEGER:
618 return (xmlSchemaTypeNegativeIntegerDef);
619 case XML_SCHEMAS_NNINTEGER:
620 return (xmlSchemaTypeNonNegativeIntegerDef);
621 case XML_SCHEMAS_PINTEGER:
622 return (xmlSchemaTypePositiveIntegerDef);
623 case XML_SCHEMAS_INT:
624 return (xmlSchemaTypeIntDef);
625 case XML_SCHEMAS_UINT:
626 return (xmlSchemaTypeUnsignedIntDef);
627 case XML_SCHEMAS_LONG:
628 return (xmlSchemaTypeLongDef);
629 case XML_SCHEMAS_ULONG:
630 return (xmlSchemaTypeUnsignedLongDef);
631 case XML_SCHEMAS_SHORT:
632 return (xmlSchemaTypeShortDef);
633 case XML_SCHEMAS_USHORT:
634 return (xmlSchemaTypeUnsignedShortDef);
635 case XML_SCHEMAS_BYTE:
636 return (xmlSchemaTypeByteDef);
637 case XML_SCHEMAS_UBYTE:
638 return (xmlSchemaTypeUnsignedByteDef);
639 case XML_SCHEMAS_HEXBINARY:
640 return (xmlSchemaTypeHexBinaryDef);
641 case XML_SCHEMAS_BASE64BINARY:
642 return (xmlSchemaTypeBase64BinaryDef);
643 case XML_SCHEMAS_ANYTYPE:
644 return (xmlSchemaTypeAnyTypeDef);
645 default:
646 return (NULL);
647 }
648}
649
650/**
Daniel Veillard4255d502002-04-16 15:50:10 +0000651 * xmlSchemaNewValue:
652 * @type: the value type
653 *
654 * Allocate a new simple type value
655 *
656 * Returns a pointer to the new value or NULL in case of error
657 */
658static xmlSchemaValPtr
659xmlSchemaNewValue(xmlSchemaValType type) {
660 xmlSchemaValPtr value;
661
662 value = (xmlSchemaValPtr) xmlMalloc(sizeof(xmlSchemaVal));
663 if (value == NULL) {
664 return(NULL);
665 }
666 memset(value, 0, sizeof(xmlSchemaVal));
667 value->type = type;
668 return(value);
669}
670
671/**
672 * xmlSchemaFreeValue:
673 * @value: the value to free
674 *
675 * Cleanup the default XML Schemas type library
676 */
677void
678xmlSchemaFreeValue(xmlSchemaValPtr value) {
679 if (value == NULL)
680 return;
Daniel Veillardc4c21552003-03-29 10:53:38 +0000681 switch (value->type) {
682 case XML_SCHEMAS_STRING:
683 case XML_SCHEMAS_NORMSTRING:
684 case XML_SCHEMAS_TOKEN:
685 case XML_SCHEMAS_LANGUAGE:
686 case XML_SCHEMAS_NMTOKEN:
687 case XML_SCHEMAS_NMTOKENS:
688 case XML_SCHEMAS_NAME:
Daniel Veillardc4c21552003-03-29 10:53:38 +0000689 case XML_SCHEMAS_NCNAME:
690 case XML_SCHEMAS_ID:
691 case XML_SCHEMAS_IDREF:
692 case XML_SCHEMAS_IDREFS:
693 case XML_SCHEMAS_ENTITY:
694 case XML_SCHEMAS_ENTITIES:
695 case XML_SCHEMAS_NOTATION:
696 case XML_SCHEMAS_ANYURI:
697 if (value->value.str != NULL)
698 xmlFree(value->value.str);
699 break;
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000700 case XML_SCHEMAS_QNAME:
701 if (value->value.qname.uri != NULL)
702 xmlFree(value->value.qname.uri);
703 if (value->value.qname.name != NULL)
704 xmlFree(value->value.qname.name);
705 break;
Daniel Veillard70bcb0e2003-08-08 14:00:28 +0000706 case XML_SCHEMAS_HEXBINARY:
707 if (value->value.hex.str != NULL)
708 xmlFree(value->value.hex.str);
709 break;
Daniel Veillard1ac24d32003-08-27 14:15:15 +0000710 case XML_SCHEMAS_BASE64BINARY:
711 if (value->value.base64.str != NULL)
712 xmlFree(value->value.base64.str);
713 break;
Daniel Veillardc4c21552003-03-29 10:53:38 +0000714 default:
715 break;
716 }
Daniel Veillard4255d502002-04-16 15:50:10 +0000717 xmlFree(value);
718}
719
720/**
721 * xmlSchemaGetPredefinedType:
722 * @name: the type name
723 * @ns: the URI of the namespace usually "http://www.w3.org/2001/XMLSchema"
724 *
725 * Lookup a type in the default XML Schemas type library
726 *
727 * Returns the type if found, NULL otherwise
728 */
729xmlSchemaTypePtr
730xmlSchemaGetPredefinedType(const xmlChar *name, const xmlChar *ns) {
731 if (xmlSchemaTypesInitialized == 0)
732 xmlSchemaInitTypes();
733 if (name == NULL)
734 return(NULL);
735 return((xmlSchemaTypePtr) xmlHashLookup2(xmlSchemaTypesBank, name, ns));
736}
Daniel Veillard070803b2002-05-03 07:29:38 +0000737
Daniel Veillard01fa6152004-06-29 17:04:39 +0000738/**
739 * xmlSchemaGetBuiltInListSimpleTypeItemType:
740 * @type: the built-in simple type.
741 *
Daniel Veillard6927b102004-10-27 17:29:04 +0000742 * Lookup function
743 *
Daniel Veillardc0826a72004-08-10 14:17:33 +0000744 * Returns the item type of @type as defined by the built-in datatype
745 * hierarchy of XML Schema Part 2: Datatypes, or NULL in case of an error.
Daniel Veillard01fa6152004-06-29 17:04:39 +0000746 */
747xmlSchemaTypePtr
748xmlSchemaGetBuiltInListSimpleTypeItemType(xmlSchemaTypePtr type)
749{
750 if (type->type != XML_SCHEMA_TYPE_BASIC)
751 return (NULL);
752 switch (type->builtInType) {
753 case XML_SCHEMAS_NMTOKENS:
754 return (xmlSchemaTypeNmtokenDef );
755 case XML_SCHEMAS_IDREFS:
756 return (xmlSchemaTypeIdrefDef);
757 case XML_SCHEMAS_ENTITIES:
758 return (xmlSchemaTypeEntityDef);
759 default:
760 return (NULL);
761 }
762}
763
Daniel Veillard070803b2002-05-03 07:29:38 +0000764/****************************************************************
765 * *
766 * Convenience macros and functions *
767 * *
768 ****************************************************************/
769
770#define IS_TZO_CHAR(c) \
771 ((c == 0) || (c == 'Z') || (c == '+') || (c == '-'))
772
773#define VALID_YEAR(yr) (yr != 0)
774#define VALID_MONTH(mon) ((mon >= 1) && (mon <= 12))
775/* VALID_DAY should only be used when month is unknown */
776#define VALID_DAY(day) ((day >= 1) && (day <= 31))
777#define VALID_HOUR(hr) ((hr >= 0) && (hr <= 23))
778#define VALID_MIN(min) ((min >= 0) && (min <= 59))
779#define VALID_SEC(sec) ((sec >= 0) && (sec < 60))
780#define VALID_TZO(tzo) ((tzo > -1440) && (tzo < 1440))
781#define IS_LEAP(y) \
782 (((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0))
783
Daniel Veillardebe25d42004-03-25 09:35:49 +0000784static const unsigned int daysInMonth[12] =
Daniel Veillard070803b2002-05-03 07:29:38 +0000785 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
Daniel Veillardebe25d42004-03-25 09:35:49 +0000786static const unsigned int daysInMonthLeap[12] =
Daniel Veillard070803b2002-05-03 07:29:38 +0000787 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
788
Daniel Veillard5a872412002-05-22 06:40:27 +0000789#define MAX_DAYINMONTH(yr,mon) \
790 (IS_LEAP(yr) ? daysInMonthLeap[mon - 1] : daysInMonth[mon - 1])
791
Daniel Veillard070803b2002-05-03 07:29:38 +0000792#define VALID_MDAY(dt) \
793 (IS_LEAP(dt->year) ? \
794 (dt->day <= daysInMonthLeap[dt->mon - 1]) : \
795 (dt->day <= daysInMonth[dt->mon - 1]))
796
797#define VALID_DATE(dt) \
798 (VALID_YEAR(dt->year) && VALID_MONTH(dt->mon) && VALID_MDAY(dt))
799
800#define VALID_TIME(dt) \
801 (VALID_HOUR(dt->hour) && VALID_MIN(dt->min) && \
802 VALID_SEC(dt->sec) && VALID_TZO(dt->tzo))
803
804#define VALID_DATETIME(dt) \
805 (VALID_DATE(dt) && VALID_TIME(dt))
806
807#define SECS_PER_MIN (60)
808#define SECS_PER_HOUR (60 * SECS_PER_MIN)
809#define SECS_PER_DAY (24 * SECS_PER_HOUR)
810
Daniel Veillard5a872412002-05-22 06:40:27 +0000811static const long dayInYearByMonth[12] =
812 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
813static const long dayInLeapYearByMonth[12] =
814 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 };
815
816#define DAY_IN_YEAR(day, month, year) \
817 ((IS_LEAP(year) ? \
818 dayInLeapYearByMonth[month - 1] : \
819 dayInYearByMonth[month - 1]) + day)
820
821#ifdef DEBUG
822#define DEBUG_DATE(dt) \
823 xmlGenericError(xmlGenericErrorContext, \
824 "type=%o %04ld-%02u-%02uT%02u:%02u:%03f", \
825 dt->type,dt->value.date.year,dt->value.date.mon, \
826 dt->value.date.day,dt->value.date.hour,dt->value.date.min, \
827 dt->value.date.sec); \
828 if (dt->value.date.tz_flag) \
829 if (dt->value.date.tzo != 0) \
830 xmlGenericError(xmlGenericErrorContext, \
831 "%+05d\n",dt->value.date.tzo); \
832 else \
833 xmlGenericError(xmlGenericErrorContext, "Z\n"); \
834 else \
835 xmlGenericError(xmlGenericErrorContext,"\n")
836#else
837#define DEBUG_DATE(dt)
838#endif
839
Daniel Veillard070803b2002-05-03 07:29:38 +0000840/**
841 * _xmlSchemaParseGYear:
842 * @dt: pointer to a date structure
843 * @str: pointer to the string to analyze
844 *
845 * Parses a xs:gYear without time zone and fills in the appropriate
846 * field of the @dt structure. @str is updated to point just after the
847 * xs:gYear. It is supposed that @dt->year is big enough to contain
848 * the year.
849 *
850 * Returns 0 or the error code
851 */
852static int
853_xmlSchemaParseGYear (xmlSchemaValDatePtr dt, const xmlChar **str) {
854 const xmlChar *cur = *str, *firstChar;
855 int isneg = 0, digcnt = 0;
856
857 if (((*cur < '0') || (*cur > '9')) &&
858 (*cur != '-') && (*cur != '+'))
859 return -1;
860
861 if (*cur == '-') {
862 isneg = 1;
863 cur++;
864 }
865
866 firstChar = cur;
867
868 while ((*cur >= '0') && (*cur <= '9')) {
869 dt->year = dt->year * 10 + (*cur - '0');
870 cur++;
871 digcnt++;
872 }
873
874 /* year must be at least 4 digits (CCYY); over 4
875 * digits cannot have a leading zero. */
876 if ((digcnt < 4) || ((digcnt > 4) && (*firstChar == '0')))
877 return 1;
878
879 if (isneg)
880 dt->year = - dt->year;
881
882 if (!VALID_YEAR(dt->year))
883 return 2;
884
885 *str = cur;
886 return 0;
887}
888
889/**
890 * PARSE_2_DIGITS:
891 * @num: the integer to fill in
892 * @cur: an #xmlChar *
893 * @invalid: an integer
894 *
895 * Parses a 2-digits integer and updates @num with the value. @cur is
896 * updated to point just after the integer.
897 * In case of error, @invalid is set to %TRUE, values of @num and
898 * @cur are undefined.
899 */
900#define PARSE_2_DIGITS(num, cur, invalid) \
901 if ((cur[0] < '0') || (cur[0] > '9') || \
902 (cur[1] < '0') || (cur[1] > '9')) \
903 invalid = 1; \
904 else \
905 num = (cur[0] - '0') * 10 + (cur[1] - '0'); \
906 cur += 2;
907
908/**
909 * PARSE_FLOAT:
910 * @num: the double to fill in
911 * @cur: an #xmlChar *
912 * @invalid: an integer
913 *
914 * Parses a float and updates @num with the value. @cur is
915 * updated to point just after the float. The float must have a
916 * 2-digits integer part and may or may not have a decimal part.
917 * In case of error, @invalid is set to %TRUE, values of @num and
918 * @cur are undefined.
919 */
920#define PARSE_FLOAT(num, cur, invalid) \
921 PARSE_2_DIGITS(num, cur, invalid); \
922 if (!invalid && (*cur == '.')) { \
923 double mult = 1; \
924 cur++; \
925 if ((*cur < '0') || (*cur > '9')) \
926 invalid = 1; \
927 while ((*cur >= '0') && (*cur <= '9')) { \
928 mult /= 10; \
929 num += (*cur - '0') * mult; \
930 cur++; \
931 } \
932 }
933
934/**
935 * _xmlSchemaParseGMonth:
936 * @dt: pointer to a date structure
937 * @str: pointer to the string to analyze
938 *
939 * Parses a xs:gMonth without time zone and fills in the appropriate
940 * field of the @dt structure. @str is updated to point just after the
941 * xs:gMonth.
942 *
943 * Returns 0 or the error code
944 */
945static int
946_xmlSchemaParseGMonth (xmlSchemaValDatePtr dt, const xmlChar **str) {
947 const xmlChar *cur = *str;
948 int ret = 0;
949
950 PARSE_2_DIGITS(dt->mon, cur, ret);
951 if (ret != 0)
952 return ret;
953
954 if (!VALID_MONTH(dt->mon))
955 return 2;
956
957 *str = cur;
958 return 0;
959}
960
961/**
962 * _xmlSchemaParseGDay:
963 * @dt: pointer to a date structure
964 * @str: pointer to the string to analyze
965 *
966 * Parses a xs:gDay without time zone and fills in the appropriate
967 * field of the @dt structure. @str is updated to point just after the
968 * xs:gDay.
969 *
970 * Returns 0 or the error code
971 */
972static int
973_xmlSchemaParseGDay (xmlSchemaValDatePtr dt, const xmlChar **str) {
974 const xmlChar *cur = *str;
975 int ret = 0;
976
977 PARSE_2_DIGITS(dt->day, cur, ret);
978 if (ret != 0)
979 return ret;
980
981 if (!VALID_DAY(dt->day))
982 return 2;
983
984 *str = cur;
985 return 0;
986}
987
988/**
989 * _xmlSchemaParseTime:
990 * @dt: pointer to a date structure
991 * @str: pointer to the string to analyze
992 *
993 * Parses a xs:time without time zone and fills in the appropriate
994 * fields of the @dt structure. @str is updated to point just after the
995 * xs:time.
996 * In case of error, values of @dt fields are undefined.
997 *
998 * Returns 0 or the error code
999 */
1000static int
1001_xmlSchemaParseTime (xmlSchemaValDatePtr dt, const xmlChar **str) {
1002 const xmlChar *cur = *str;
1003 unsigned int hour = 0; /* use temp var in case str is not xs:time */
1004 int ret = 0;
1005
1006 PARSE_2_DIGITS(hour, cur, ret);
1007 if (ret != 0)
1008 return ret;
1009
1010 if (*cur != ':')
1011 return 1;
1012 cur++;
1013
1014 /* the ':' insures this string is xs:time */
1015 dt->hour = hour;
1016
1017 PARSE_2_DIGITS(dt->min, cur, ret);
1018 if (ret != 0)
1019 return ret;
1020
1021 if (*cur != ':')
1022 return 1;
1023 cur++;
1024
1025 PARSE_FLOAT(dt->sec, cur, ret);
1026 if (ret != 0)
1027 return ret;
1028
1029 if (!VALID_TIME(dt))
1030 return 2;
1031
1032 *str = cur;
1033 return 0;
1034}
1035
1036/**
1037 * _xmlSchemaParseTimeZone:
1038 * @dt: pointer to a date structure
1039 * @str: pointer to the string to analyze
1040 *
1041 * Parses a time zone without time zone and fills in the appropriate
1042 * field of the @dt structure. @str is updated to point just after the
1043 * time zone.
1044 *
1045 * Returns 0 or the error code
1046 */
1047static int
1048_xmlSchemaParseTimeZone (xmlSchemaValDatePtr dt, const xmlChar **str) {
1049 const xmlChar *cur = *str;
1050 int ret = 0;
1051
1052 if (str == NULL)
1053 return -1;
1054
1055 switch (*cur) {
1056 case 0:
1057 dt->tz_flag = 0;
1058 dt->tzo = 0;
1059 break;
1060
1061 case 'Z':
1062 dt->tz_flag = 1;
1063 dt->tzo = 0;
1064 cur++;
1065 break;
1066
1067 case '+':
1068 case '-': {
1069 int isneg = 0, tmp = 0;
1070 isneg = (*cur == '-');
1071
1072 cur++;
1073
1074 PARSE_2_DIGITS(tmp, cur, ret);
1075 if (ret != 0)
1076 return ret;
1077 if (!VALID_HOUR(tmp))
1078 return 2;
1079
1080 if (*cur != ':')
1081 return 1;
1082 cur++;
1083
1084 dt->tzo = tmp * 60;
1085
1086 PARSE_2_DIGITS(tmp, cur, ret);
1087 if (ret != 0)
1088 return ret;
1089 if (!VALID_MIN(tmp))
1090 return 2;
1091
1092 dt->tzo += tmp;
1093 if (isneg)
1094 dt->tzo = - dt->tzo;
1095
1096 if (!VALID_TZO(dt->tzo))
1097 return 2;
1098
Daniel Veillard5a872412002-05-22 06:40:27 +00001099 dt->tz_flag = 1;
Daniel Veillard070803b2002-05-03 07:29:38 +00001100 break;
1101 }
1102 default:
1103 return 1;
1104 }
1105
1106 *str = cur;
1107 return 0;
1108}
1109
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001110/**
1111 * _xmlSchemaBase64Decode:
1112 * @ch: a character
1113 *
1114 * Converts a base64 encoded character to its base 64 value.
1115 *
1116 * Returns 0-63 (value), 64 (pad), or -1 (not recognized)
1117 */
1118static int
1119_xmlSchemaBase64Decode (const xmlChar ch) {
1120 if (('A' <= ch) && (ch <= 'Z')) return ch - 'A';
1121 if (('a' <= ch) && (ch <= 'z')) return ch - 'a' + 26;
1122 if (('0' <= ch) && (ch <= '9')) return ch - '0' + 52;
1123 if ('+' == ch) return 62;
1124 if ('/' == ch) return 63;
1125 if ('=' == ch) return 64;
1126 return -1;
1127}
1128
Daniel Veillard070803b2002-05-03 07:29:38 +00001129/****************************************************************
1130 * *
1131 * XML Schema Dates/Times Datatypes Handling *
1132 * *
1133 ****************************************************************/
1134
1135/**
1136 * PARSE_DIGITS:
1137 * @num: the integer to fill in
1138 * @cur: an #xmlChar *
1139 * @num_type: an integer flag
1140 *
1141 * Parses a digits integer and updates @num with the value. @cur is
1142 * updated to point just after the integer.
1143 * In case of error, @num_type is set to -1, values of @num and
1144 * @cur are undefined.
1145 */
1146#define PARSE_DIGITS(num, cur, num_type) \
1147 if ((*cur < '0') || (*cur > '9')) \
1148 num_type = -1; \
1149 else \
1150 while ((*cur >= '0') && (*cur <= '9')) { \
1151 num = num * 10 + (*cur - '0'); \
1152 cur++; \
1153 }
1154
1155/**
1156 * PARSE_NUM:
1157 * @num: the double to fill in
1158 * @cur: an #xmlChar *
1159 * @num_type: an integer flag
1160 *
1161 * Parses a float or integer and updates @num with the value. @cur is
1162 * updated to point just after the number. If the number is a float,
1163 * then it must have an integer part and a decimal part; @num_type will
1164 * be set to 1. If there is no decimal part, @num_type is set to zero.
1165 * In case of error, @num_type is set to -1, values of @num and
1166 * @cur are undefined.
1167 */
1168#define PARSE_NUM(num, cur, num_type) \
1169 num = 0; \
1170 PARSE_DIGITS(num, cur, num_type); \
1171 if (!num_type && (*cur == '.')) { \
1172 double mult = 1; \
1173 cur++; \
1174 if ((*cur < '0') || (*cur > '9')) \
1175 num_type = -1; \
1176 else \
1177 num_type = 1; \
1178 while ((*cur >= '0') && (*cur <= '9')) { \
1179 mult /= 10; \
1180 num += (*cur - '0') * mult; \
1181 cur++; \
1182 } \
1183 }
1184
1185/**
Daniel Veillard5a872412002-05-22 06:40:27 +00001186 * xmlSchemaValidateDates:
Daniel Veillard455cc072003-03-31 10:13:23 +00001187 * @type: the expected type or XML_SCHEMAS_UNKNOWN
Daniel Veillard070803b2002-05-03 07:29:38 +00001188 * @dateTime: string to analyze
1189 * @val: the return computed value
1190 *
1191 * Check that @dateTime conforms to the lexical space of one of the date types.
1192 * if true a value is computed and returned in @val.
1193 *
1194 * Returns 0 if this validates, a positive error code number otherwise
1195 * and -1 in case of internal or API error.
1196 */
1197static int
Daniel Veillard455cc072003-03-31 10:13:23 +00001198xmlSchemaValidateDates (xmlSchemaValType type,
Daniel Veillard118aed72002-09-24 14:13:13 +00001199 const xmlChar *dateTime, xmlSchemaValPtr *val) {
Daniel Veillard070803b2002-05-03 07:29:38 +00001200 xmlSchemaValPtr dt;
1201 int ret;
1202 const xmlChar *cur = dateTime;
1203
1204#define RETURN_TYPE_IF_VALID(t) \
1205 if (IS_TZO_CHAR(*cur)) { \
1206 ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur); \
1207 if (ret == 0) { \
1208 if (*cur != 0) \
1209 goto error; \
1210 dt->type = t; \
Daniel Veillard455cc072003-03-31 10:13:23 +00001211 goto done; \
Daniel Veillard070803b2002-05-03 07:29:38 +00001212 } \
1213 }
1214
1215 if (dateTime == NULL)
1216 return -1;
1217
1218 if ((*cur != '-') && (*cur < '0') && (*cur > '9'))
1219 return 1;
1220
1221 dt = xmlSchemaNewValue(XML_SCHEMAS_UNKNOWN);
1222 if (dt == NULL)
1223 return -1;
1224
1225 if ((cur[0] == '-') && (cur[1] == '-')) {
1226 /*
1227 * It's an incomplete date (xs:gMonthDay, xs:gMonth or
1228 * xs:gDay)
1229 */
1230 cur += 2;
1231
1232 /* is it an xs:gDay? */
1233 if (*cur == '-') {
Daniel Veillard455cc072003-03-31 10:13:23 +00001234 if (type == XML_SCHEMAS_GMONTH)
1235 goto error;
Daniel Veillard070803b2002-05-03 07:29:38 +00001236 ++cur;
1237 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
1238 if (ret != 0)
1239 goto error;
1240
1241 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GDAY);
1242
1243 goto error;
1244 }
1245
1246 /*
1247 * it should be an xs:gMonthDay or xs:gMonth
1248 */
1249 ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
1250 if (ret != 0)
1251 goto error;
1252
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001253 /*
1254 * a '-' char could indicate this type is xs:gMonthDay or
1255 * a negative time zone offset. Check for xs:gMonthDay first.
1256 * Also the first three char's of a negative tzo (-MM:SS) can
1257 * appear to be a valid day; so even if the day portion
1258 * of the xs:gMonthDay verifies, we must insure it was not
1259 * a tzo.
1260 */
1261 if (*cur == '-') {
1262 const xmlChar *rewnd = cur;
1263 cur++;
Daniel Veillard070803b2002-05-03 07:29:38 +00001264
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001265 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
1266 if ((ret == 0) && ((*cur == 0) || (*cur != ':'))) {
1267
1268 /*
1269 * we can use the VALID_MDAY macro to validate the month
1270 * and day because the leap year test will flag year zero
1271 * as a leap year (even though zero is an invalid year).
1272 */
1273 if (VALID_MDAY((&(dt->value.date)))) {
1274
1275 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTHDAY);
1276
1277 goto error;
1278 }
1279 }
1280
1281 /*
1282 * not xs:gMonthDay so rewind and check if just xs:gMonth
1283 * with an optional time zone.
1284 */
1285 cur = rewnd;
1286 }
1287
1288 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTH);
Daniel Veillard070803b2002-05-03 07:29:38 +00001289
1290 goto error;
1291 }
1292
1293 /*
1294 * It's a right-truncated date or an xs:time.
1295 * Try to parse an xs:time then fallback on right-truncated dates.
1296 */
1297 if ((*cur >= '0') && (*cur <= '9')) {
1298 ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
1299 if (ret == 0) {
1300 /* it's an xs:time */
1301 RETURN_TYPE_IF_VALID(XML_SCHEMAS_TIME);
1302 }
1303 }
1304
1305 /* fallback on date parsing */
1306 cur = dateTime;
1307
1308 ret = _xmlSchemaParseGYear(&(dt->value.date), &cur);
1309 if (ret != 0)
1310 goto error;
1311
1312 /* is it an xs:gYear? */
1313 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEAR);
1314
1315 if (*cur != '-')
1316 goto error;
1317 cur++;
1318
1319 ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
1320 if (ret != 0)
1321 goto error;
1322
1323 /* is it an xs:gYearMonth? */
1324 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEARMONTH);
1325
1326 if (*cur != '-')
1327 goto error;
1328 cur++;
1329
1330 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
1331 if ((ret != 0) || !VALID_DATE((&(dt->value.date))))
1332 goto error;
1333
1334 /* is it an xs:date? */
1335 RETURN_TYPE_IF_VALID(XML_SCHEMAS_DATE);
1336
1337 if (*cur != 'T')
1338 goto error;
1339 cur++;
1340
1341 /* it should be an xs:dateTime */
1342 ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
1343 if (ret != 0)
1344 goto error;
1345
1346 ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur);
1347 if ((ret != 0) || (*cur != 0) || !VALID_DATETIME((&(dt->value.date))))
1348 goto error;
1349
Daniel Veillard455cc072003-03-31 10:13:23 +00001350
Daniel Veillard070803b2002-05-03 07:29:38 +00001351 dt->type = XML_SCHEMAS_DATETIME;
1352
Daniel Veillard455cc072003-03-31 10:13:23 +00001353done:
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001354#if 1
1355 if ((type != XML_SCHEMAS_UNKNOWN) && (type != dt->type))
1356 goto error;
1357#else
1358 /*
1359 * insure the parsed type is equal to or less significant (right
1360 * truncated) than the desired type.
1361 */
1362 if ((type != XML_SCHEMAS_UNKNOWN) && (type != dt->type)) {
1363
1364 /* time only matches time */
1365 if ((type == XML_SCHEMAS_TIME) && (dt->type == XML_SCHEMAS_TIME))
1366 goto error;
1367
1368 if ((type == XML_SCHEMAS_DATETIME) &&
1369 ((dt->type != XML_SCHEMAS_DATE) ||
1370 (dt->type != XML_SCHEMAS_GYEARMONTH) ||
1371 (dt->type != XML_SCHEMAS_GYEAR)))
1372 goto error;
1373
1374 if ((type == XML_SCHEMAS_DATE) &&
1375 ((dt->type != XML_SCHEMAS_GYEAR) ||
1376 (dt->type != XML_SCHEMAS_GYEARMONTH)))
1377 goto error;
1378
1379 if ((type == XML_SCHEMAS_GYEARMONTH) && (dt->type != XML_SCHEMAS_GYEAR))
1380 goto error;
1381
1382 if ((type == XML_SCHEMAS_GMONTHDAY) && (dt->type != XML_SCHEMAS_GMONTH))
1383 goto error;
1384 }
Daniel Veillard455cc072003-03-31 10:13:23 +00001385#endif
1386
Daniel Veillard070803b2002-05-03 07:29:38 +00001387 if (val != NULL)
1388 *val = dt;
Daniel Veillard80b19092003-03-28 13:29:53 +00001389 else
1390 xmlSchemaFreeValue(dt);
Daniel Veillard070803b2002-05-03 07:29:38 +00001391
1392 return 0;
1393
1394error:
1395 if (dt != NULL)
1396 xmlSchemaFreeValue(dt);
1397 return 1;
1398}
1399
1400/**
Daniel Veillard5a872412002-05-22 06:40:27 +00001401 * xmlSchemaValidateDuration:
Daniel Veillard070803b2002-05-03 07:29:38 +00001402 * @type: the predefined type
1403 * @duration: string to analyze
1404 * @val: the return computed value
1405 *
1406 * Check that @duration conforms to the lexical space of the duration type.
1407 * if true a value is computed and returned in @val.
1408 *
1409 * Returns 0 if this validates, a positive error code number otherwise
1410 * and -1 in case of internal or API error.
1411 */
1412static int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00001413xmlSchemaValidateDuration (xmlSchemaTypePtr type ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +00001414 const xmlChar *duration, xmlSchemaValPtr *val) {
Daniel Veillard070803b2002-05-03 07:29:38 +00001415 const xmlChar *cur = duration;
1416 xmlSchemaValPtr dur;
1417 int isneg = 0;
1418 unsigned int seq = 0;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001419 double num;
1420 int num_type = 0; /* -1 = invalid, 0 = int, 1 = floating */
1421 const xmlChar desig[] = {'Y', 'M', 'D', 'H', 'M', 'S'};
1422 const double multi[] = { 0.0, 0.0, 86400.0, 3600.0, 60.0, 1.0, 0.0};
Daniel Veillard070803b2002-05-03 07:29:38 +00001423
1424 if (duration == NULL)
1425 return -1;
1426
1427 if (*cur == '-') {
1428 isneg = 1;
1429 cur++;
1430 }
1431
1432 /* duration must start with 'P' (after sign) */
1433 if (*cur++ != 'P')
1434 return 1;
1435
Daniel Veillard80b19092003-03-28 13:29:53 +00001436 if (*cur == 0)
1437 return 1;
1438
Daniel Veillard070803b2002-05-03 07:29:38 +00001439 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
1440 if (dur == NULL)
1441 return -1;
1442
1443 while (*cur != 0) {
Daniel Veillard070803b2002-05-03 07:29:38 +00001444
1445 /* input string should be empty or invalid date/time item */
1446 if (seq >= sizeof(desig))
1447 goto error;
1448
1449 /* T designator must be present for time items */
1450 if (*cur == 'T') {
1451 if (seq <= 3) {
1452 seq = 3;
1453 cur++;
1454 } else
1455 return 1;
1456 } else if (seq == 3)
1457 goto error;
1458
1459 /* parse the number portion of the item */
1460 PARSE_NUM(num, cur, num_type);
1461
1462 if ((num_type == -1) || (*cur == 0))
1463 goto error;
1464
1465 /* update duration based on item type */
1466 while (seq < sizeof(desig)) {
1467 if (*cur == desig[seq]) {
1468
1469 /* verify numeric type; only seconds can be float */
1470 if ((num_type != 0) && (seq < (sizeof(desig)-1)))
1471 goto error;
1472
1473 switch (seq) {
1474 case 0:
1475 dur->value.dur.mon = (long)num * 12;
1476 break;
1477 case 1:
1478 dur->value.dur.mon += (long)num;
1479 break;
1480 default:
1481 /* convert to seconds using multiplier */
1482 dur->value.dur.sec += num * multi[seq];
1483 seq++;
1484 break;
1485 }
1486
1487 break; /* exit loop */
1488 }
1489 /* no date designators found? */
1490 if (++seq == 3)
1491 goto error;
1492 }
1493 cur++;
1494 }
1495
1496 if (isneg) {
1497 dur->value.dur.mon = -dur->value.dur.mon;
1498 dur->value.dur.day = -dur->value.dur.day;
1499 dur->value.dur.sec = -dur->value.dur.sec;
1500 }
1501
1502 if (val != NULL)
1503 *val = dur;
Daniel Veillard80b19092003-03-28 13:29:53 +00001504 else
1505 xmlSchemaFreeValue(dur);
Daniel Veillard070803b2002-05-03 07:29:38 +00001506
1507 return 0;
1508
1509error:
1510 if (dur != NULL)
1511 xmlSchemaFreeValue(dur);
1512 return 1;
1513}
1514
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001515/**
1516 * xmlSchemaStrip:
1517 * @value: a value
1518 *
1519 * Removes the leading and ending spaces of a string
1520 *
1521 * Returns the new string or NULL if no change was required.
1522 */
1523static xmlChar *
1524xmlSchemaStrip(const xmlChar *value) {
1525 const xmlChar *start = value, *end, *f;
1526
1527 if (value == NULL) return(NULL);
William M. Brack76e95df2003-10-18 16:20:14 +00001528 while ((*start != 0) && (IS_BLANK_CH(*start))) start++;
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001529 end = start;
1530 while (*end != 0) end++;
1531 f = end;
1532 end--;
William M. Brack76e95df2003-10-18 16:20:14 +00001533 while ((end > start) && (IS_BLANK_CH(*end))) end--;
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001534 end++;
1535 if ((start == value) && (f == end)) return(NULL);
1536 return(xmlStrndup(start, end - start));
1537}
Daniel Veillard96a4b252003-02-06 08:22:32 +00001538
1539/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001540 * xmlSchemaCollapseString:
1541 * @value: a value
1542 *
1543 * Removes and normalize white spaces in the string
1544 *
1545 * Returns the new string or NULL if no change was required.
1546 */
Daniel Veillard01fa6152004-06-29 17:04:39 +00001547xmlChar *
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001548xmlSchemaCollapseString(const xmlChar *value) {
1549 const xmlChar *start = value, *end, *f;
1550 xmlChar *g;
1551 int col = 0;
1552
1553 if (value == NULL) return(NULL);
William M. Brack76e95df2003-10-18 16:20:14 +00001554 while ((*start != 0) && (IS_BLANK_CH(*start))) start++;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001555 end = start;
1556 while (*end != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00001557 if ((*end == ' ') && (IS_BLANK_CH(end[1]))) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001558 col = end - start;
1559 break;
1560 } else if ((*end == 0xa) || (*end == 0x9) || (*end == 0xd)) {
1561 col = end - start;
1562 break;
1563 }
1564 end++;
1565 }
1566 if (col == 0) {
1567 f = end;
1568 end--;
William M. Brack76e95df2003-10-18 16:20:14 +00001569 while ((end > start) && (IS_BLANK_CH(*end))) end--;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001570 end++;
1571 if ((start == value) && (f == end)) return(NULL);
1572 return(xmlStrndup(start, end - start));
1573 }
1574 start = xmlStrdup(start);
1575 if (start == NULL) return(NULL);
1576 g = (xmlChar *) (start + col);
1577 end = g;
1578 while (*end != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00001579 if (IS_BLANK_CH(*end)) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001580 end++;
William M. Brack76e95df2003-10-18 16:20:14 +00001581 while (IS_BLANK_CH(*end)) end++;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001582 if (*end != 0)
1583 *g++ = ' ';
1584 } else
1585 *g++ = *end++;
1586 }
1587 *g = 0;
1588 return((xmlChar *) start);
1589}
1590
1591/**
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001592 * xmlSchemaValAtomicListNode:
1593 * @type: the predefined atomic type for a token in the list
1594 * @value: the list value to check
1595 * @ret: the return computed value
1596 * @node: the node containing the value
1597 *
1598 * Check that a value conforms to the lexical space of the predefined
1599 * list type. if true a value is computed and returned in @ret.
1600 *
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001601 * Returns the number of items if this validates, a negative error code
1602 * number otherwise
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001603 */
1604static int
1605xmlSchemaValAtomicListNode(xmlSchemaTypePtr type, const xmlChar *value,
1606 xmlSchemaValPtr *ret, xmlNodePtr node) {
1607 xmlChar *val, *cur, *endval;
1608 int nb_values = 0;
Daniel Veillard580ced82003-03-21 21:22:48 +00001609 int tmp = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001610
1611 if (value == NULL) {
1612 return(-1);
1613 }
1614 val = xmlStrdup(value);
1615 if (val == NULL) {
1616 return(-1);
1617 }
1618 cur = val;
1619 /*
1620 * Split the list
1621 */
William M. Brack76e95df2003-10-18 16:20:14 +00001622 while (IS_BLANK_CH(*cur)) *cur++ = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001623 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00001624 if (IS_BLANK_CH(*cur)) {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001625 *cur = 0;
1626 cur++;
William M. Brack76e95df2003-10-18 16:20:14 +00001627 while (IS_BLANK_CH(*cur)) *cur++ = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001628 } else {
1629 nb_values++;
1630 cur++;
William M. Brack76e95df2003-10-18 16:20:14 +00001631 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001632 }
1633 }
1634 if (nb_values == 0) {
1635 if (ret != NULL) {
1636 TODO
1637 }
1638 xmlFree(val);
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001639 return(nb_values);
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001640 }
1641 endval = cur;
1642 cur = val;
1643 while ((*cur == 0) && (cur != endval)) cur++;
1644 while (cur != endval) {
1645 tmp = xmlSchemaValPredefTypeNode(type, cur, NULL, node);
1646 if (tmp != 0)
1647 break;
1648 while (*cur != 0) cur++;
1649 while ((*cur == 0) && (cur != endval)) cur++;
1650 }
1651 xmlFree(val);
1652 if (ret != NULL) {
1653 TODO
1654 }
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001655 if (tmp == 0)
1656 return(nb_values);
1657 return(-1);
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001658}
1659
1660/**
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001661 * xmlSchemaParseUInt:
1662 * @str: pointer to the string R/W
1663 * @llo: pointer to the low result
1664 * @lmi: pointer to the mid result
1665 * @lhi: pointer to the high result
1666 *
1667 * Parse an unsigned long into 3 fields.
1668 *
1669 * Returns the number of chars parsed or -1 if overflow of the capacity
1670 */
1671static int
1672xmlSchemaParseUInt(const xmlChar **str, unsigned long *llo,
1673 unsigned long *lmi, unsigned long *lhi) {
1674 unsigned long lo = 0, mi = 0, hi = 0;
1675 const xmlChar *tmp, *cur = *str;
1676 int ret = 0, i = 0;
1677
1678 while (*cur == '0') {
1679 ret++;
1680 cur++;
1681 }
1682 tmp = cur;
1683 while ((*tmp != 0) && (*tmp >= '0') && (*tmp <= '9')) {
1684 i++;tmp++;ret++;
1685 }
1686 if (i > 24) {
1687 *str = tmp;
1688 return(-1);
1689 }
1690 while (i > 16) {
1691 hi = hi * 10 + (*cur++ - '0');
1692 i--;
1693 }
1694 while (i > 8) {
1695 mi = mi * 10 + (*cur++ - '0');
1696 i--;
1697 }
1698 while (i > 0) {
1699 lo = lo * 10 + (*cur++ - '0');
1700 i--;
1701 }
1702
1703 *str = cur;
1704 *llo = lo;
1705 *lmi = mi;
1706 *lhi = hi;
1707 return(ret);
1708}
1709
1710/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001711 * xmlSchemaValAtomicType:
1712 * @type: the predefined type
1713 * @value: the value to check
1714 * @val: the return computed value
1715 * @node: the node containing the value
1716 * flags: flags to control the vlidation
1717 *
1718 * Check that a value conforms to the lexical space of the atomic type.
1719 * if true a value is computed and returned in @val.
Daniel Veillard01fa6152004-06-29 17:04:39 +00001720 * This checks the value space for list types as well (IDREFS, NMTOKENS).
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001721 *
1722 * Returns 0 if this validates, a positive error code number otherwise
1723 * and -1 in case of internal or API error.
1724 */
1725static int
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001726xmlSchemaValAtomicType(xmlSchemaTypePtr type, const xmlChar * value,
1727 xmlSchemaValPtr * val, xmlNodePtr node, int flags)
1728{
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001729 xmlSchemaValPtr v;
1730 xmlChar *norm = NULL;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001731 int ret = 0;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001732
1733 if (xmlSchemaTypesInitialized == 0)
Daniel Veillard01fa6152004-06-29 17:04:39 +00001734 xmlSchemaInitTypes();
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001735 if (type == NULL)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001736 return (-1);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001737
Daniel Veillardeebd6332004-08-26 10:30:44 +00001738 /*
1739 * validating a non existant text node is similar to validating
1740 * an empty one.
1741 */
1742 if (value == NULL)
1743 value = BAD_CAST "";
1744
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001745 if (val != NULL)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001746 *val = NULL;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001747 if ((flags == 0) && (value != NULL)) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00001748 if ((type->builtInType != XML_SCHEMAS_STRING) &&
1749 (type->builtInType != XML_SCHEMAS_NORMSTRING)) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001750 norm = xmlSchemaCollapseString(value);
1751 if (norm != NULL)
1752 value = norm;
1753 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001754 }
1755
Daniel Veillard01fa6152004-06-29 17:04:39 +00001756 switch (type->builtInType) {
William M. Brack2f2a6632004-08-20 23:09:47 +00001757 case XML_SCHEMAS_UNKNOWN:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001758 goto error;
William M. Brack2f2a6632004-08-20 23:09:47 +00001759 case XML_SCHEMAS_ANYTYPE:
1760 case XML_SCHEMAS_ANYSIMPLETYPE:
1761 goto return0;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001762 case XML_SCHEMAS_STRING:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001763 goto return0;
Daniel Veillard1516d5b2004-01-22 07:27:45 +00001764 case XML_SCHEMAS_NORMSTRING:{
1765 const xmlChar *cur = value;
1766
1767 while (*cur != 0) {
1768 if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) {
1769 goto return1;
1770 } else {
1771 cur++;
1772 }
1773 }
1774 if (val != NULL) {
1775 v = xmlSchemaNewValue(XML_SCHEMAS_NORMSTRING);
1776 if (v != NULL) {
1777 v->value.str = xmlStrdup(value);
1778 *val = v;
1779 } else {
1780 goto error;
1781 }
1782 }
1783 goto return0;
1784 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001785 case XML_SCHEMAS_DECIMAL:{
1786 const xmlChar *cur = value, *tmp;
1787 unsigned int frac = 0, len, neg = 0;
1788 unsigned long base = 0;
1789
1790 if (cur == NULL)
1791 goto return1;
1792 if (*cur == '+')
1793 cur++;
1794 else if (*cur == '-') {
1795 neg = 1;
1796 cur++;
1797 }
1798 tmp = cur;
1799 while ((*cur >= '0') && (*cur <= '9')) {
1800 base = base * 10 + (*cur - '0');
1801 cur++;
1802 }
1803 len = cur - tmp;
1804 if (*cur == '.') {
1805 cur++;
1806 tmp = cur;
1807 while ((*cur >= '0') && (*cur <= '9')) {
1808 base = base * 10 + (*cur - '0');
1809 cur++;
1810 }
1811 frac = cur - tmp;
1812 }
1813 if (*cur != 0)
1814 goto return1;
1815 if (val != NULL) {
1816 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
1817 if (v != NULL) {
1818 v->value.decimal.lo = base;
1819 v->value.decimal.sign = neg;
1820 v->value.decimal.frac = frac;
1821 v->value.decimal.total = frac + len;
1822 *val = v;
1823 }
1824 }
1825 goto return0;
1826 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001827 case XML_SCHEMAS_TIME:
1828 case XML_SCHEMAS_GDAY:
1829 case XML_SCHEMAS_GMONTH:
1830 case XML_SCHEMAS_GMONTHDAY:
1831 case XML_SCHEMAS_GYEAR:
1832 case XML_SCHEMAS_GYEARMONTH:
1833 case XML_SCHEMAS_DATE:
1834 case XML_SCHEMAS_DATETIME:
Daniel Veillard01fa6152004-06-29 17:04:39 +00001835 ret = xmlSchemaValidateDates(type->builtInType, value, val);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001836 break;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001837 case XML_SCHEMAS_DURATION:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001838 ret = xmlSchemaValidateDuration(type, value, val);
1839 break;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001840 case XML_SCHEMAS_FLOAT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001841 case XML_SCHEMAS_DOUBLE:{
1842 const xmlChar *cur = value;
1843 int neg = 0;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001844
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001845 if (cur == NULL)
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00001846 goto return1;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001847 if ((cur[0] == 'N') && (cur[1] == 'a') && (cur[2] == 'N')) {
1848 cur += 3;
1849 if (*cur != 0)
1850 goto return1;
1851 if (val != NULL) {
1852 if (type == xmlSchemaTypeFloatDef) {
1853 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1854 if (v != NULL) {
1855 v->value.f = (float) xmlXPathNAN;
1856 } else {
1857 xmlSchemaFreeValue(v);
1858 goto error;
1859 }
1860 } else {
1861 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1862 if (v != NULL) {
1863 v->value.d = xmlXPathNAN;
1864 } else {
1865 xmlSchemaFreeValue(v);
1866 goto error;
1867 }
1868 }
1869 *val = v;
1870 }
1871 goto return0;
1872 }
1873 if (*cur == '-') {
1874 neg = 1;
1875 cur++;
1876 }
1877 if ((cur[0] == 'I') && (cur[1] == 'N') && (cur[2] == 'F')) {
1878 cur += 3;
1879 if (*cur != 0)
1880 goto return1;
1881 if (val != NULL) {
1882 if (type == xmlSchemaTypeFloatDef) {
1883 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1884 if (v != NULL) {
1885 if (neg)
1886 v->value.f = (float) xmlXPathNINF;
1887 else
1888 v->value.f = (float) xmlXPathPINF;
1889 } else {
1890 xmlSchemaFreeValue(v);
1891 goto error;
1892 }
1893 } else {
1894 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1895 if (v != NULL) {
1896 if (neg)
1897 v->value.d = xmlXPathNINF;
1898 else
1899 v->value.d = xmlXPathPINF;
1900 } else {
1901 xmlSchemaFreeValue(v);
1902 goto error;
1903 }
1904 }
1905 *val = v;
1906 }
1907 goto return0;
1908 }
1909 if ((neg == 0) && (*cur == '+'))
1910 cur++;
1911 if ((cur[0] == 0) || (cur[0] == '+') || (cur[0] == '-'))
1912 goto return1;
1913 while ((*cur >= '0') && (*cur <= '9')) {
1914 cur++;
1915 }
1916 if (*cur == '.') {
1917 cur++;
1918 while ((*cur >= '0') && (*cur <= '9'))
1919 cur++;
1920 }
1921 if ((*cur == 'e') || (*cur == 'E')) {
1922 cur++;
1923 if ((*cur == '-') || (*cur == '+'))
1924 cur++;
1925 while ((*cur >= '0') && (*cur <= '9'))
1926 cur++;
1927 }
1928 if (*cur != 0)
1929 goto return1;
1930 if (val != NULL) {
1931 if (type == xmlSchemaTypeFloatDef) {
1932 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1933 if (v != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001934 if (sscanf((const char *) value, "%f",
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001935 &(v->value.f)) == 1) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00001936 *val = v;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001937 } else {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001938 xmlSchemaFreeValue(v);
1939 goto return1;
1940 }
1941 } else {
1942 goto error;
1943 }
1944 } else {
1945 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1946 if (v != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001947 if (sscanf((const char *) value, "%lf",
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001948 &(v->value.d)) == 1) {
1949 *val = v;
1950 } else {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001951 xmlSchemaFreeValue(v);
1952 goto return1;
1953 }
1954 } else {
1955 goto error;
1956 }
1957 }
1958 }
1959 goto return0;
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00001960 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001961 case XML_SCHEMAS_BOOLEAN:{
1962 const xmlChar *cur = value;
1963
1964 if ((cur[0] == '0') && (cur[1] == 0))
1965 ret = 0;
1966 else if ((cur[0] == '1') && (cur[1] == 0))
1967 ret = 1;
1968 else if ((cur[0] == 't') && (cur[1] == 'r')
1969 && (cur[2] == 'u') && (cur[3] == 'e')
1970 && (cur[4] == 0))
1971 ret = 1;
1972 else if ((cur[0] == 'f') && (cur[1] == 'a')
1973 && (cur[2] == 'l') && (cur[3] == 's')
1974 && (cur[4] == 'e') && (cur[5] == 0))
1975 ret = 0;
1976 else
1977 goto return1;
1978 if (val != NULL) {
1979 v = xmlSchemaNewValue(XML_SCHEMAS_BOOLEAN);
1980 if (v != NULL) {
1981 v->value.b = ret;
1982 *val = v;
1983 } else {
1984 goto error;
1985 }
1986 }
1987 goto return0;
1988 }
1989 case XML_SCHEMAS_TOKEN:{
1990 const xmlChar *cur = value;
1991
William M. Brack76e95df2003-10-18 16:20:14 +00001992 if (IS_BLANK_CH(*cur))
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001993 goto return1;
1994
1995 while (*cur != 0) {
1996 if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) {
1997 goto return1;
1998 } else if (*cur == ' ') {
1999 cur++;
2000 if (*cur == 0)
2001 goto return1;
2002 if (*cur == ' ')
2003 goto return1;
2004 } else {
2005 cur++;
2006 }
2007 }
2008 if (val != NULL) {
2009 v = xmlSchemaNewValue(XML_SCHEMAS_TOKEN);
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 case XML_SCHEMAS_LANGUAGE:
2020 if (xmlCheckLanguageID(value) == 1) {
2021 if (val != NULL) {
2022 v = xmlSchemaNewValue(XML_SCHEMAS_LANGUAGE);
2023 if (v != NULL) {
2024 v->value.str = xmlStrdup(value);
2025 *val = v;
2026 } else {
2027 goto error;
2028 }
2029 }
2030 goto return0;
2031 }
2032 goto return1;
2033 case XML_SCHEMAS_NMTOKEN:
2034 if (xmlValidateNMToken(value, 1) == 0) {
2035 if (val != NULL) {
2036 v = xmlSchemaNewValue(XML_SCHEMAS_NMTOKEN);
2037 if (v != NULL) {
2038 v->value.str = xmlStrdup(value);
2039 *val = v;
2040 } else {
2041 goto error;
2042 }
2043 }
2044 goto return0;
2045 }
2046 goto return1;
2047 case XML_SCHEMAS_NMTOKENS:
2048 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeNmtokenDef,
2049 value, val, node);
2050 if (ret > 0)
2051 ret = 0;
2052 else
2053 ret = 1;
2054 goto done;
2055 case XML_SCHEMAS_NAME:
2056 ret = xmlValidateName(value, 1);
2057 if ((ret == 0) && (val != NULL)) {
2058 TODO;
2059 }
2060 goto done;
2061 case XML_SCHEMAS_QNAME:{
2062 xmlChar *uri = NULL;
2063 xmlChar *local = NULL;
2064
2065 ret = xmlValidateQName(value, 1);
2066 if ((ret == 0) && (node != NULL)) {
2067 xmlChar *prefix;
2068
2069 local = xmlSplitQName2(value, &prefix);
2070 if (prefix != NULL) {
2071 xmlNsPtr ns;
2072
2073 ns = xmlSearchNs(node->doc, node, prefix);
2074 if (ns == NULL)
2075 ret = 1;
2076 else if (val != NULL)
2077 uri = xmlStrdup(ns->href);
2078 }
2079 if ((local != NULL) && ((val == NULL) || (ret != 0)))
2080 xmlFree(local);
2081 if (prefix != NULL)
2082 xmlFree(prefix);
2083 }
2084 if ((ret == 0) && (val != NULL)) {
2085 v = xmlSchemaNewValue(XML_SCHEMAS_QNAME);
2086 if (v != NULL) {
2087 if (local != NULL)
2088 v->value.qname.name = local;
2089 else
2090 v->value.qname.name = xmlStrdup(value);
2091 if (uri != NULL)
2092 v->value.qname.uri = uri;
2093
2094 *val = v;
2095 } else {
2096 if (local != NULL)
2097 xmlFree(local);
2098 if (uri != NULL)
2099 xmlFree(uri);
2100 goto error;
2101 }
2102 }
2103 goto done;
2104 }
2105 case XML_SCHEMAS_NCNAME:
2106 ret = xmlValidateNCName(value, 1);
2107 if ((ret == 0) && (val != NULL)) {
2108 v = xmlSchemaNewValue(XML_SCHEMAS_NCNAME);
2109 if (v != NULL) {
2110 v->value.str = xmlStrdup(value);
2111 *val = v;
2112 } else {
2113 goto error;
2114 }
2115 }
2116 goto done;
2117 case XML_SCHEMAS_ID:
2118 ret = xmlValidateNCName(value, 1);
2119 if ((ret == 0) && (val != NULL)) {
2120 v = xmlSchemaNewValue(XML_SCHEMAS_ID);
2121 if (v != NULL) {
2122 v->value.str = xmlStrdup(value);
2123 *val = v;
2124 } else {
2125 goto error;
2126 }
2127 }
2128 if ((ret == 0) && (node != NULL) &&
2129 (node->type == XML_ATTRIBUTE_NODE)) {
2130 xmlAttrPtr attr = (xmlAttrPtr) node;
2131
2132 /*
2133 * NOTE: the IDness might have already be declared in the DTD
2134 */
2135 if (attr->atype != XML_ATTRIBUTE_ID) {
2136 xmlIDPtr res;
2137 xmlChar *strip;
2138
2139 strip = xmlSchemaStrip(value);
2140 if (strip != NULL) {
2141 res = xmlAddID(NULL, node->doc, strip, attr);
2142 xmlFree(strip);
2143 } else
2144 res = xmlAddID(NULL, node->doc, value, attr);
2145 if (res == NULL) {
2146 ret = 2;
2147 } else {
2148 attr->atype = XML_ATTRIBUTE_ID;
2149 }
2150 }
2151 }
2152 goto done;
2153 case XML_SCHEMAS_IDREF:
2154 ret = xmlValidateNCName(value, 1);
2155 if ((ret == 0) && (val != NULL)) {
2156 TODO;
2157 }
2158 if ((ret == 0) && (node != NULL) &&
2159 (node->type == XML_ATTRIBUTE_NODE)) {
2160 xmlAttrPtr attr = (xmlAttrPtr) node;
2161 xmlChar *strip;
2162
2163 strip = xmlSchemaStrip(value);
2164 if (strip != NULL) {
2165 xmlAddRef(NULL, node->doc, strip, attr);
2166 xmlFree(strip);
2167 } else
2168 xmlAddRef(NULL, node->doc, value, attr);
2169 attr->atype = XML_ATTRIBUTE_IDREF;
2170 }
2171 goto done;
2172 case XML_SCHEMAS_IDREFS:
2173 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeIdrefDef,
2174 value, val, node);
2175 if (ret < 0)
2176 ret = 2;
2177 else
2178 ret = 0;
2179 if ((ret == 0) && (node != NULL) &&
2180 (node->type == XML_ATTRIBUTE_NODE)) {
2181 xmlAttrPtr attr = (xmlAttrPtr) node;
2182
2183 attr->atype = XML_ATTRIBUTE_IDREFS;
2184 }
2185 goto done;
2186 case XML_SCHEMAS_ENTITY:{
2187 xmlChar *strip;
2188
2189 ret = xmlValidateNCName(value, 1);
2190 if ((node == NULL) || (node->doc == NULL))
2191 ret = 3;
2192 if (ret == 0) {
2193 xmlEntityPtr ent;
2194
2195 strip = xmlSchemaStrip(value);
2196 if (strip != NULL) {
2197 ent = xmlGetDocEntity(node->doc, strip);
2198 xmlFree(strip);
2199 } else {
2200 ent = xmlGetDocEntity(node->doc, value);
2201 }
2202 if ((ent == NULL) ||
2203 (ent->etype !=
2204 XML_EXTERNAL_GENERAL_UNPARSED_ENTITY))
2205 ret = 4;
2206 }
2207 if ((ret == 0) && (val != NULL)) {
2208 TODO;
2209 }
2210 if ((ret == 0) && (node != NULL) &&
2211 (node->type == XML_ATTRIBUTE_NODE)) {
2212 xmlAttrPtr attr = (xmlAttrPtr) node;
2213
2214 attr->atype = XML_ATTRIBUTE_ENTITY;
2215 }
2216 goto done;
2217 }
2218 case XML_SCHEMAS_ENTITIES:
2219 if ((node == NULL) || (node->doc == NULL))
2220 goto return3;
2221 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeEntityDef,
2222 value, val, node);
2223 if (ret <= 0)
2224 ret = 1;
2225 else
2226 ret = 0;
2227 if ((ret == 0) && (node != NULL) &&
2228 (node->type == XML_ATTRIBUTE_NODE)) {
2229 xmlAttrPtr attr = (xmlAttrPtr) node;
2230
2231 attr->atype = XML_ATTRIBUTE_ENTITIES;
2232 }
2233 goto done;
2234 case XML_SCHEMAS_NOTATION:{
2235 xmlChar *uri = NULL;
2236 xmlChar *local = NULL;
2237
2238 ret = xmlValidateQName(value, 1);
2239 if ((ret == 0) && (node != NULL)) {
2240 xmlChar *prefix;
2241
2242 local = xmlSplitQName2(value, &prefix);
2243 if (prefix != NULL) {
2244 xmlNsPtr ns;
2245
2246 ns = xmlSearchNs(node->doc, node, prefix);
2247 if (ns == NULL)
2248 ret = 1;
2249 else if (val != NULL)
2250 uri = xmlStrdup(ns->href);
2251 }
2252 if ((local != NULL) && ((val == NULL) || (ret != 0)))
2253 xmlFree(local);
2254 if (prefix != NULL)
2255 xmlFree(prefix);
2256 }
2257 if ((node == NULL) || (node->doc == NULL))
2258 ret = 3;
2259 if (ret == 0) {
2260 ret = xmlValidateNotationUse(NULL, node->doc, value);
2261 if (ret == 1)
2262 ret = 0;
2263 else
2264 ret = 1;
2265 }
2266 if ((ret == 0) && (val != NULL)) {
2267 v = xmlSchemaNewValue(XML_SCHEMAS_NOTATION);
2268 if (v != NULL) {
2269 if (local != NULL)
2270 v->value.qname.name = local;
2271 else
2272 v->value.qname.name = xmlStrdup(value);
2273 if (uri != NULL)
2274 v->value.qname.uri = uri;
2275
2276 *val = v;
2277 } else {
2278 if (local != NULL)
2279 xmlFree(local);
2280 if (uri != NULL)
2281 xmlFree(uri);
2282 goto error;
2283 }
2284 }
2285 goto done;
2286 }
2287 case XML_SCHEMAS_ANYURI:{
Daniel Veillard11c466a2004-03-14 12:20:15 +00002288 if (*value != 0) {
2289 xmlURIPtr uri = xmlParseURI((const char *) value);
2290 if (uri == NULL)
2291 goto return1;
2292 xmlFreeURI(uri);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002293 }
Daniel Veillard11c466a2004-03-14 12:20:15 +00002294
2295 if (val != NULL) {
2296 v = xmlSchemaNewValue(XML_SCHEMAS_ANYURI);
2297 if (v == NULL)
2298 goto error;
2299 v->value.str = xmlStrdup(value);
2300 *val = v;
2301 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002302 goto return0;
2303 }
2304 case XML_SCHEMAS_HEXBINARY:{
2305 const xmlChar *cur = value;
2306 xmlChar *base;
2307 int total, i = 0;
2308
Daniel Veillardf34a20e2004-08-31 08:42:17 +00002309 if (cur == NULL)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002310 goto return1;
2311
2312 while (((*cur >= '0') && (*cur <= '9')) ||
2313 ((*cur >= 'A') && (*cur <= 'F')) ||
2314 ((*cur >= 'a') && (*cur <= 'f'))) {
2315 i++;
2316 cur++;
2317 }
2318
2319 if (*cur != 0)
2320 goto return1;
2321 if ((i % 2) != 0)
2322 goto return1;
2323
2324 if (val != NULL) {
2325
2326 v = xmlSchemaNewValue(XML_SCHEMAS_HEXBINARY);
2327 if (v == NULL)
2328 goto error;
2329
2330 cur = xmlStrdup(value);
2331 if (cur == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002332 xmlSchemaTypeErrMemory(node, "allocating hexbin data");
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002333 xmlFree(v);
2334 goto return1;
2335 }
2336
2337 total = i / 2; /* number of octets */
2338
2339 base = (xmlChar *) cur;
2340 while (i-- > 0) {
2341 if (*base >= 'a')
2342 *base = *base - ('a' - 'A');
2343 base++;
2344 }
2345
2346 v->value.hex.str = (xmlChar *) cur;
2347 v->value.hex.total = total;
2348 *val = v;
2349 }
2350 goto return0;
2351 }
2352 case XML_SCHEMAS_BASE64BINARY:{
2353 /* ISSUE:
2354 *
2355 * Ignore all stray characters? (yes, currently)
2356 * Worry about long lines? (no, currently)
2357 *
2358 * rfc2045.txt:
2359 *
2360 * "The encoded output stream must be represented in lines of
2361 * no more than 76 characters each. All line breaks or other
2362 * characters not found in Table 1 must be ignored by decoding
2363 * software. In base64 data, characters other than those in
2364 * Table 1, line breaks, and other white space probably
2365 * indicate a transmission error, about which a warning
2366 * message or even a message rejection might be appropriate
2367 * under some circumstances." */
2368 const xmlChar *cur = value;
2369 xmlChar *base;
2370 int total, i = 0, pad = 0;
2371
2372 if (cur == NULL)
2373 goto return1;
2374
2375 for (; *cur; ++cur) {
2376 int decc;
2377
2378 decc = _xmlSchemaBase64Decode(*cur);
2379 if (decc < 0) ;
2380 else if (decc < 64)
2381 i++;
2382 else
2383 break;
2384 }
2385 for (; *cur; ++cur) {
2386 int decc;
2387
2388 decc = _xmlSchemaBase64Decode(*cur);
2389 if (decc < 0) ;
2390 else if (decc < 64)
2391 goto return1;
2392 if (decc == 64)
2393 pad++;
2394 }
2395
2396 /* rfc2045.txt: "Special processing is performed if fewer than
2397 * 24 bits are available at the end of the data being encoded.
2398 * A full encoding quantum is always completed at the end of a
2399 * body. When fewer than 24 input bits are available in an
2400 * input group, zero bits are added (on the right) to form an
2401 * integral number of 6-bit groups. Padding at the end of the
2402 * data is performed using the "=" character. Since all
2403 * base64 input is an integral number of octets, only the
2404 * following cases can arise: (1) the final quantum of
2405 * encoding input is an integral multiple of 24 bits; here,
2406 * the final unit of encoded output will be an integral
2407 * multiple ofindent: Standard input:701: Warning:old style
2408 * assignment ambiguity in "=*". Assuming "= *" 4 characters
2409 * with no "=" padding, (2) the final
2410 * quantum of encoding input is exactly 8 bits; here, the
2411 * final unit of encoded output will be two characters
2412 * followed by two "=" padding characters, or (3) the final
2413 * quantum of encoding input is exactly 16 bits; here, the
2414 * final unit of encoded output will be three characters
2415 * followed by one "=" padding character." */
2416
2417 total = 3 * (i / 4);
2418 if (pad == 0) {
2419 if (i % 4 != 0)
2420 goto return1;
2421 } else if (pad == 1) {
2422 int decc;
2423
2424 if (i % 4 != 3)
2425 goto return1;
2426 for (decc = _xmlSchemaBase64Decode(*cur);
2427 (decc < 0) || (decc > 63);
2428 decc = _xmlSchemaBase64Decode(*cur))
2429 --cur;
2430 /* 16bits in 24bits means 2 pad bits: nnnnnn nnmmmm mmmm00*/
2431 /* 00111100 -> 0x3c */
2432 if (decc & ~0x3c)
2433 goto return1;
2434 total += 2;
2435 } else if (pad == 2) {
2436 int decc;
2437
2438 if (i % 4 != 2)
2439 goto return1;
2440 for (decc = _xmlSchemaBase64Decode(*cur);
2441 (decc < 0) || (decc > 63);
2442 decc = _xmlSchemaBase64Decode(*cur))
2443 --cur;
2444 /* 8bits in 12bits means 4 pad bits: nnnnnn nn0000 */
2445 /* 00110000 -> 0x30 */
2446 if (decc & ~0x30)
2447 goto return1;
2448 total += 1;
2449 } else
2450 goto return1;
2451
2452 if (val != NULL) {
2453 v = xmlSchemaNewValue(XML_SCHEMAS_BASE64BINARY);
2454 if (v == NULL)
2455 goto error;
2456 base =
2457 (xmlChar *) xmlMallocAtomic((i + pad + 1) *
2458 sizeof(xmlChar));
2459 if (base == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002460 xmlSchemaTypeErrMemory(node, "allocating base64 data");
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002461 xmlFree(v);
2462 goto return1;
2463 }
2464 v->value.base64.str = base;
2465 for (cur = value; *cur; ++cur)
2466 if (_xmlSchemaBase64Decode(*cur) >= 0) {
2467 *base = *cur;
2468 ++base;
2469 }
2470 *base = 0;
2471 v->value.base64.total = total;
2472 *val = v;
2473 }
2474 goto return0;
2475 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002476 case XML_SCHEMAS_INTEGER:
2477 case XML_SCHEMAS_PINTEGER:
2478 case XML_SCHEMAS_NPINTEGER:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002479 case XML_SCHEMAS_NINTEGER:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002480 case XML_SCHEMAS_NNINTEGER:{
2481 const xmlChar *cur = value;
2482 unsigned long lo, mi, hi;
2483 int sign = 0;
2484
2485 if (cur == NULL)
2486 goto return1;
2487 if (*cur == '-') {
2488 sign = 1;
2489 cur++;
2490 } else if (*cur == '+')
2491 cur++;
2492 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2493 if (ret == 0)
2494 goto return1;
2495 if (*cur != 0)
2496 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002497 if (type->builtInType == XML_SCHEMAS_NPINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002498 if ((sign == 0) &&
2499 ((hi != 0) || (mi != 0) || (lo != 0)))
2500 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002501 } else if (type->builtInType == XML_SCHEMAS_PINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002502 if (sign == 1)
2503 goto return1;
2504 if ((hi == 0) && (mi == 0) && (lo == 0))
2505 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002506 } else if (type->builtInType == XML_SCHEMAS_NINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002507 if (sign == 0)
2508 goto return1;
2509 if ((hi == 0) && (mi == 0) && (lo == 0))
2510 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002511 } else if (type->builtInType == XML_SCHEMAS_NNINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002512 if ((sign == 1) &&
2513 ((hi != 0) || (mi != 0) || (lo != 0)))
2514 goto return1;
2515 }
2516 /*
2517 * We can store a value only if no overflow occured
2518 */
2519 if ((ret > 0) && (val != NULL)) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00002520 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002521 if (v != NULL) {
2522 v->value.decimal.lo = lo;
2523 v->value.decimal.mi = lo;
2524 v->value.decimal.hi = lo;
2525 v->value.decimal.sign = sign;
2526 v->value.decimal.frac = 0;
2527 v->value.decimal.total = cur - value;
2528 *val = v;
2529 }
2530 }
2531 goto return0;
2532 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002533 case XML_SCHEMAS_LONG:
2534 case XML_SCHEMAS_BYTE:
2535 case XML_SCHEMAS_SHORT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002536 case XML_SCHEMAS_INT:{
2537 const xmlChar *cur = value;
2538 unsigned long lo, mi, hi;
2539 int total = 0;
2540 int sign = 0;
2541
2542 if (cur == NULL)
2543 goto return1;
2544 if (*cur == '-') {
2545 sign = 1;
2546 cur++;
2547 } else if (*cur == '+')
2548 cur++;
2549 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2550 if (ret <= 0)
2551 goto return1;
2552 if (*cur != 0)
2553 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002554 if (type->builtInType == XML_SCHEMAS_LONG) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002555 if (hi >= 922) {
2556 if (hi > 922)
2557 goto return1;
2558 if (mi >= 33720368) {
2559 if (mi > 33720368)
2560 goto return1;
2561 if ((sign == 0) && (lo > 54775807))
2562 goto return1;
2563 if ((sign == 1) && (lo > 54775808))
2564 goto return1;
2565 }
2566 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002567 } else if (type->builtInType == XML_SCHEMAS_INT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002568 if (hi != 0)
2569 goto return1;
2570 if (mi >= 21) {
2571 if (mi > 21)
2572 goto return1;
2573 if ((sign == 0) && (lo > 47483647))
2574 goto return1;
2575 if ((sign == 1) && (lo > 47483648))
2576 goto return1;
2577 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002578 } else if (type->builtInType == XML_SCHEMAS_SHORT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002579 if ((mi != 0) || (hi != 0))
2580 goto return1;
2581 if ((sign == 1) && (lo > 32768))
2582 goto return1;
2583 if ((sign == 0) && (lo > 32767))
2584 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002585 } else if (type->builtInType == XML_SCHEMAS_BYTE) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002586 if ((mi != 0) || (hi != 0))
2587 goto return1;
2588 if ((sign == 1) && (lo > 128))
2589 goto return1;
2590 if ((sign == 0) && (lo > 127))
2591 goto return1;
2592 }
2593 if (val != NULL) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00002594 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002595 if (v != NULL) {
2596 v->value.decimal.lo = lo;
2597 v->value.decimal.mi = lo;
2598 v->value.decimal.hi = lo;
2599 v->value.decimal.sign = sign;
2600 v->value.decimal.frac = 0;
2601 v->value.decimal.total = total;
2602 *val = v;
2603 }
2604 }
2605 goto return0;
2606 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002607 case XML_SCHEMAS_UINT:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002608 case XML_SCHEMAS_ULONG:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002609 case XML_SCHEMAS_USHORT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002610 case XML_SCHEMAS_UBYTE:{
2611 const xmlChar *cur = value;
2612 unsigned long lo, mi, hi;
2613 int total = 0;
2614
2615 if (cur == NULL)
2616 goto return1;
2617 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2618 if (ret <= 0)
2619 goto return1;
2620 if (*cur != 0)
2621 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002622 if (type->builtInType == XML_SCHEMAS_ULONG) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002623 if (hi >= 1844) {
2624 if (hi > 1844)
2625 goto return1;
2626 if (mi >= 67440737) {
2627 if (mi > 67440737)
2628 goto return1;
2629 if (lo > 9551615)
2630 goto return1;
2631 }
2632 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002633 } else if (type->builtInType == XML_SCHEMAS_UINT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002634 if (hi != 0)
2635 goto return1;
2636 if (mi >= 42) {
2637 if (mi > 42)
2638 goto return1;
2639 if (lo > 94967295)
2640 goto return1;
2641 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002642 } else if (type->builtInType == XML_SCHEMAS_USHORT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002643 if ((mi != 0) || (hi != 0))
2644 goto return1;
2645 if (lo > 65535)
2646 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002647 } else if (type->builtInType == XML_SCHEMAS_UBYTE) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002648 if ((mi != 0) || (hi != 0))
2649 goto return1;
2650 if (lo > 255)
2651 goto return1;
2652 }
2653 if (val != NULL) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00002654 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002655 if (v != NULL) {
2656 v->value.decimal.lo = lo;
2657 v->value.decimal.mi = mi;
2658 v->value.decimal.hi = hi;
2659 v->value.decimal.sign = 0;
2660 v->value.decimal.frac = 0;
2661 v->value.decimal.total = total;
2662 *val = v;
2663 }
2664 }
2665 goto return0;
2666 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002667 }
2668
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002669 done:
2670 if (norm != NULL)
2671 xmlFree(norm);
2672 return (ret);
2673 return3:
2674 if (norm != NULL)
2675 xmlFree(norm);
2676 return (3);
2677 return1:
2678 if (norm != NULL)
2679 xmlFree(norm);
2680 return (1);
2681 return0:
2682 if (norm != NULL)
2683 xmlFree(norm);
2684 return (0);
2685 error:
2686 if (norm != NULL)
2687 xmlFree(norm);
2688 return (-1);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002689}
2690
2691/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002692 * xmlSchemaValPredefTypeNode:
Daniel Veillard4255d502002-04-16 15:50:10 +00002693 * @type: the predefined type
2694 * @value: the value to check
2695 * @val: the return computed value
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002696 * @node: the node containing the value
Daniel Veillard4255d502002-04-16 15:50:10 +00002697 *
2698 * Check that a value conforms to the lexical space of the predefined type.
2699 * if true a value is computed and returned in @val.
2700 *
2701 * Returns 0 if this validates, a positive error code number otherwise
2702 * and -1 in case of internal or API error.
2703 */
2704int
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002705xmlSchemaValPredefTypeNode(xmlSchemaTypePtr type, const xmlChar *value,
2706 xmlSchemaValPtr *val, xmlNodePtr node) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002707 return(xmlSchemaValAtomicType(type, value, val, node, 0));
Daniel Veillard4255d502002-04-16 15:50:10 +00002708}
2709
2710/**
Daniel Veillardc0826a72004-08-10 14:17:33 +00002711 * xmlSchemaValPredefTypeNodeNoNorm:
2712 * @type: the predefined type
2713 * @value: the value to check
2714 * @val: the return computed value
2715 * @node: the node containing the value
2716 *
2717 * Check that a value conforms to the lexical space of the predefined type.
2718 * if true a value is computed and returned in @val.
2719 * This one does apply any normalization to the value.
2720 *
2721 * Returns 0 if this validates, a positive error code number otherwise
2722 * and -1 in case of internal or API error.
2723 */
2724int
2725xmlSchemaValPredefTypeNodeNoNorm(xmlSchemaTypePtr type, const xmlChar *value,
2726 xmlSchemaValPtr *val, xmlNodePtr node) {
2727 return(xmlSchemaValAtomicType(type, value, val, node, 1));
2728}
2729
2730/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002731 * xmlSchemaValidatePredefinedType:
2732 * @type: the predefined type
2733 * @value: the value to check
2734 * @val: the return computed value
2735 *
2736 * Check that a value conforms to the lexical space of the predefined type.
2737 * if true a value is computed and returned in @val.
2738 *
2739 * Returns 0 if this validates, a positive error code number otherwise
2740 * and -1 in case of internal or API error.
2741 */
2742int
2743xmlSchemaValidatePredefinedType(xmlSchemaTypePtr type, const xmlChar *value,
2744 xmlSchemaValPtr *val) {
2745 return(xmlSchemaValPredefTypeNode(type, value, val, NULL));
2746}
2747
2748/**
Daniel Veillard4255d502002-04-16 15:50:10 +00002749 * xmlSchemaCompareDecimals:
2750 * @x: a first decimal value
2751 * @y: a second decimal value
2752 *
2753 * Compare 2 decimals
2754 *
2755 * Returns -1 if x < y, 0 if x == y, 1 if x > y and -2 in case of error
2756 */
2757static int
2758xmlSchemaCompareDecimals(xmlSchemaValPtr x, xmlSchemaValPtr y)
2759{
2760 xmlSchemaValPtr swp;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002761 int order = 1, p;
Daniel Veillard4255d502002-04-16 15:50:10 +00002762 unsigned long tmp;
2763
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002764 if ((x->value.decimal.sign) &&
2765 ((x->value.decimal.lo != 0) ||
2766 (x->value.decimal.mi != 0) ||
2767 (x->value.decimal.hi != 0))) {
2768 if ((y->value.decimal.sign) &&
2769 ((y->value.decimal.lo != 0) ||
2770 (y->value.decimal.mi != 0) ||
2771 (y->value.decimal.hi != 0)))
Daniel Veillard80b19092003-03-28 13:29:53 +00002772 order = -1;
2773 else
2774 return (-1);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002775 } else if ((y->value.decimal.sign) &&
2776 ((y->value.decimal.lo != 0) ||
2777 (y->value.decimal.mi != 0) ||
2778 (y->value.decimal.hi != 0))) {
Daniel Veillard4255d502002-04-16 15:50:10 +00002779 return (1);
Daniel Veillard80b19092003-03-28 13:29:53 +00002780 }
Daniel Veillard4255d502002-04-16 15:50:10 +00002781 if (x->value.decimal.frac == y->value.decimal.frac) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002782 if (x->value.decimal.hi < y->value.decimal.hi)
2783 return (-order);
Daniel Veillard01fa6152004-06-29 17:04:39 +00002784 if (x->value.decimal.hi > y->value.decimal.hi)
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002785 return (order);
2786 if (x->value.decimal.mi < y->value.decimal.mi)
2787 return (-order);
Daniel Veillard01fa6152004-06-29 17:04:39 +00002788 if (x->value.decimal.mi > y->value.decimal.mi)
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002789 return (order);
2790 if (x->value.decimal.lo < y->value.decimal.lo)
Daniel Veillard80b19092003-03-28 13:29:53 +00002791 return (-order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002792 if (x->value.decimal.lo > y->value.decimal.lo)
Daniel Veillard80b19092003-03-28 13:29:53 +00002793 return(order);
2794 return(0);
Daniel Veillard4255d502002-04-16 15:50:10 +00002795 }
2796 if (y->value.decimal.frac > x->value.decimal.frac) {
2797 swp = y;
2798 y = x;
2799 x = swp;
2800 order = -order;
2801 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002802 p = powten[x->value.decimal.frac - y->value.decimal.frac];
2803 tmp = x->value.decimal.lo / p;
2804 if (tmp > y->value.decimal.lo)
Daniel Veillard4255d502002-04-16 15:50:10 +00002805 return (order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002806 if (tmp < y->value.decimal.lo)
Daniel Veillard4255d502002-04-16 15:50:10 +00002807 return (-order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002808 tmp = y->value.decimal.lo * p;
2809 if (x->value.decimal.lo < tmp)
Daniel Veillard4255d502002-04-16 15:50:10 +00002810 return (-order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002811 if (x->value.decimal.lo == tmp)
Daniel Veillard4255d502002-04-16 15:50:10 +00002812 return (0);
2813 return (order);
2814}
2815
2816/**
Daniel Veillard070803b2002-05-03 07:29:38 +00002817 * xmlSchemaCompareDurations:
2818 * @x: a first duration value
2819 * @y: a second duration value
2820 *
2821 * Compare 2 durations
2822 *
2823 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
2824 * case of error
2825 */
2826static int
2827xmlSchemaCompareDurations(xmlSchemaValPtr x, xmlSchemaValPtr y)
2828{
2829 long carry, mon, day;
2830 double sec;
Daniel Veillard80b19092003-03-28 13:29:53 +00002831 int invert = 1;
2832 long xmon, xday, myear, minday, maxday;
Daniel Veillard070803b2002-05-03 07:29:38 +00002833 static const long dayRange [2][12] = {
2834 { 0, 28, 59, 89, 120, 150, 181, 212, 242, 273, 303, 334, },
2835 { 0, 31, 62, 92, 123, 153, 184, 215, 245, 276, 306, 337} };
2836
2837 if ((x == NULL) || (y == NULL))
Daniel Veillard5a872412002-05-22 06:40:27 +00002838 return -2;
Daniel Veillard070803b2002-05-03 07:29:38 +00002839
2840 /* months */
2841 mon = x->value.dur.mon - y->value.dur.mon;
2842
2843 /* seconds */
2844 sec = x->value.dur.sec - y->value.dur.sec;
2845 carry = (long)sec / SECS_PER_DAY;
2846 sec -= (double)(carry * SECS_PER_DAY);
2847
2848 /* days */
2849 day = x->value.dur.day - y->value.dur.day + carry;
2850
2851 /* easy test */
2852 if (mon == 0) {
2853 if (day == 0)
2854 if (sec == 0.0)
2855 return 0;
2856 else if (sec < 0.0)
2857 return -1;
2858 else
2859 return 1;
2860 else if (day < 0)
2861 return -1;
2862 else
2863 return 1;
2864 }
2865
2866 if (mon > 0) {
2867 if ((day >= 0) && (sec >= 0.0))
2868 return 1;
2869 else {
2870 xmon = mon;
2871 xday = -day;
2872 }
2873 } else if ((day <= 0) && (sec <= 0.0)) {
2874 return -1;
2875 } else {
Daniel Veillard80b19092003-03-28 13:29:53 +00002876 invert = -1;
Daniel Veillard070803b2002-05-03 07:29:38 +00002877 xmon = -mon;
2878 xday = day;
2879 }
2880
2881 myear = xmon / 12;
Daniel Veillard80b19092003-03-28 13:29:53 +00002882 if (myear == 0) {
2883 minday = 0;
2884 maxday = 0;
2885 } else {
2886 maxday = 366 * ((myear + 3) / 4) +
2887 365 * ((myear - 1) % 4);
2888 minday = maxday - 1;
2889 }
2890
Daniel Veillard070803b2002-05-03 07:29:38 +00002891 xmon = xmon % 12;
2892 minday += dayRange[0][xmon];
2893 maxday += dayRange[1][xmon];
2894
Daniel Veillard80b19092003-03-28 13:29:53 +00002895 if ((maxday == minday) && (maxday == xday))
2896 return(0); /* can this really happen ? */
Daniel Veillard070803b2002-05-03 07:29:38 +00002897 if (maxday < xday)
Daniel Veillard80b19092003-03-28 13:29:53 +00002898 return(-invert);
2899 if (minday > xday)
2900 return(invert);
Daniel Veillard070803b2002-05-03 07:29:38 +00002901
2902 /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00002903 return 2;
2904}
2905
2906/*
2907 * macros for adding date/times and durations
2908 */
2909#define FQUOTIENT(a,b) (floor(((double)a/(double)b)))
2910#define MODULO(a,b) (a - FQUOTIENT(a,b) * b)
2911#define FQUOTIENT_RANGE(a,low,high) (FQUOTIENT((a-low),(high-low)))
2912#define MODULO_RANGE(a,low,high) ((MODULO((a-low),(high-low)))+low)
2913
2914/**
Daniel Veillard669adfc2004-05-29 20:12:46 +00002915 * xmlSchemaDupVal:
2916 * @v: the #xmlSchemaValPtr value to duplicate
2917 *
2918 * Makes a copy of @v. The calling program is responsible for freeing
2919 * the returned value.
2920 *
2921 * returns a pointer to a duplicated #xmlSchemaValPtr or NULL if error.
2922 */
2923static xmlSchemaValPtr
2924xmlSchemaDupVal (xmlSchemaValPtr v)
2925{
2926 xmlSchemaValPtr ret = xmlSchemaNewValue(v->type);
2927 if (ret == NULL)
2928 return NULL;
2929
2930 memcpy(ret, v, sizeof(xmlSchemaVal));
2931 return ret;
2932}
2933
2934/**
Daniel Veillard5a872412002-05-22 06:40:27 +00002935 * _xmlSchemaDateAdd:
2936 * @dt: an #xmlSchemaValPtr
2937 * @dur: an #xmlSchemaValPtr of type #XS_DURATION
2938 *
2939 * Compute a new date/time from @dt and @dur. This function assumes @dt
2940 * is either #XML_SCHEMAS_DATETIME, #XML_SCHEMAS_DATE, #XML_SCHEMAS_GYEARMONTH,
Daniel Veillard669adfc2004-05-29 20:12:46 +00002941 * or #XML_SCHEMAS_GYEAR. The returned #xmlSchemaVal is the same type as
2942 * @dt. The calling program is responsible for freeing the returned value.
Daniel Veillard5a872412002-05-22 06:40:27 +00002943 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00002944 * Returns a pointer to a new #xmlSchemaVal or NULL if error.
Daniel Veillard5a872412002-05-22 06:40:27 +00002945 */
2946static xmlSchemaValPtr
2947_xmlSchemaDateAdd (xmlSchemaValPtr dt, xmlSchemaValPtr dur)
2948{
Daniel Veillard669adfc2004-05-29 20:12:46 +00002949 xmlSchemaValPtr ret, tmp;
Daniel Veillard5a872412002-05-22 06:40:27 +00002950 long carry, tempdays, temp;
2951 xmlSchemaValDatePtr r, d;
2952 xmlSchemaValDurationPtr u;
2953
2954 if ((dt == NULL) || (dur == NULL))
2955 return NULL;
2956
2957 ret = xmlSchemaNewValue(dt->type);
2958 if (ret == NULL)
2959 return NULL;
2960
Daniel Veillard669adfc2004-05-29 20:12:46 +00002961 /* make a copy so we don't alter the original value */
2962 tmp = xmlSchemaDupVal(dt);
2963 if (tmp == NULL) {
2964 xmlSchemaFreeValue(ret);
2965 return NULL;
2966 }
2967
Daniel Veillard5a872412002-05-22 06:40:27 +00002968 r = &(ret->value.date);
Daniel Veillard669adfc2004-05-29 20:12:46 +00002969 d = &(tmp->value.date);
Daniel Veillard5a872412002-05-22 06:40:27 +00002970 u = &(dur->value.dur);
2971
2972 /* normalization */
2973 if (d->mon == 0)
2974 d->mon = 1;
2975
2976 /* normalize for time zone offset */
2977 u->sec -= (d->tzo * 60);
2978 d->tzo = 0;
2979
2980 /* normalization */
2981 if (d->day == 0)
2982 d->day = 1;
2983
2984 /* month */
2985 carry = d->mon + u->mon;
Daniel Veillardebe25d42004-03-25 09:35:49 +00002986 r->mon = (unsigned int) MODULO_RANGE(carry, 1, 13);
2987 carry = (long) FQUOTIENT_RANGE(carry, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00002988
2989 /* year (may be modified later) */
2990 r->year = d->year + carry;
2991 if (r->year == 0) {
2992 if (d->year > 0)
2993 r->year--;
2994 else
2995 r->year++;
2996 }
2997
2998 /* time zone */
2999 r->tzo = d->tzo;
3000 r->tz_flag = d->tz_flag;
3001
3002 /* seconds */
3003 r->sec = d->sec + u->sec;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003004 carry = (long) FQUOTIENT((long)r->sec, 60);
Daniel Veillard5a872412002-05-22 06:40:27 +00003005 if (r->sec != 0.0) {
3006 r->sec = MODULO(r->sec, 60.0);
3007 }
3008
3009 /* minute */
3010 carry += d->min;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003011 r->min = (unsigned int) MODULO(carry, 60);
3012 carry = (long) FQUOTIENT(carry, 60);
Daniel Veillard5a872412002-05-22 06:40:27 +00003013
3014 /* hours */
3015 carry += d->hour;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003016 r->hour = (unsigned int) MODULO(carry, 24);
3017 carry = (long)FQUOTIENT(carry, 24);
Daniel Veillard5a872412002-05-22 06:40:27 +00003018
3019 /*
3020 * days
3021 * Note we use tempdays because the temporary values may need more
3022 * than 5 bits
3023 */
3024 if ((VALID_YEAR(r->year)) && (VALID_MONTH(r->mon)) &&
3025 (d->day > MAX_DAYINMONTH(r->year, r->mon)))
3026 tempdays = MAX_DAYINMONTH(r->year, r->mon);
3027 else if (d->day < 1)
3028 tempdays = 1;
3029 else
3030 tempdays = d->day;
3031
3032 tempdays += u->day + carry;
3033
3034 while (1) {
3035 if (tempdays < 1) {
Daniel Veillardebe25d42004-03-25 09:35:49 +00003036 long tmon = (long) MODULO_RANGE(r->mon-1, 1, 13);
3037 long tyr = r->year + (long)FQUOTIENT_RANGE(r->mon-1, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00003038 if (tyr == 0)
3039 tyr--;
3040 tempdays += MAX_DAYINMONTH(tyr, tmon);
3041 carry = -1;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003042 } else if (tempdays > (long) MAX_DAYINMONTH(r->year, r->mon)) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003043 tempdays = tempdays - MAX_DAYINMONTH(r->year, r->mon);
3044 carry = 1;
3045 } else
3046 break;
3047
3048 temp = r->mon + carry;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003049 r->mon = (unsigned int) MODULO_RANGE(temp, 1, 13);
3050 r->year = r->year + (unsigned int) FQUOTIENT_RANGE(temp, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00003051 if (r->year == 0) {
3052 if (temp < 1)
3053 r->year--;
3054 else
3055 r->year++;
3056 }
3057 }
3058
3059 r->day = tempdays;
3060
3061 /*
3062 * adjust the date/time type to the date values
3063 */
3064 if (ret->type != XML_SCHEMAS_DATETIME) {
3065 if ((r->hour) || (r->min) || (r->sec))
3066 ret->type = XML_SCHEMAS_DATETIME;
3067 else if (ret->type != XML_SCHEMAS_DATE) {
3068 if ((r->mon != 1) && (r->day != 1))
3069 ret->type = XML_SCHEMAS_DATE;
3070 else if ((ret->type != XML_SCHEMAS_GYEARMONTH) && (r->mon != 1))
3071 ret->type = XML_SCHEMAS_GYEARMONTH;
3072 }
3073 }
3074
Daniel Veillard669adfc2004-05-29 20:12:46 +00003075 xmlSchemaFreeValue(tmp);
Daniel Veillard5a872412002-05-22 06:40:27 +00003076
Daniel Veillard5a872412002-05-22 06:40:27 +00003077 return ret;
3078}
3079
3080/**
3081 * xmlSchemaDateNormalize:
Daniel Veillard669adfc2004-05-29 20:12:46 +00003082 * @dt: an #xmlSchemaValPtr of a date/time type value.
3083 * @offset: number of seconds to adjust @dt by.
Daniel Veillard5a872412002-05-22 06:40:27 +00003084 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00003085 * Normalize @dt to GMT time. The @offset parameter is subtracted from
3086 * the return value is a time-zone offset is present on @dt.
Daniel Veillard5a872412002-05-22 06:40:27 +00003087 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00003088 * Returns a normalized copy of @dt or NULL if error.
Daniel Veillard5a872412002-05-22 06:40:27 +00003089 */
3090static xmlSchemaValPtr
3091xmlSchemaDateNormalize (xmlSchemaValPtr dt, double offset)
3092{
3093 xmlSchemaValPtr dur, ret;
3094
3095 if (dt == NULL)
3096 return NULL;
3097
3098 if (((dt->type != XML_SCHEMAS_TIME) &&
3099 (dt->type != XML_SCHEMAS_DATETIME)) || (dt->value.date.tzo == 0))
3100 return xmlSchemaDupVal(dt);
3101
3102 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
3103 if (dur == NULL)
3104 return NULL;
3105
3106 dur->value.date.sec -= offset;
3107
3108 ret = _xmlSchemaDateAdd(dt, dur);
3109 if (ret == NULL)
3110 return NULL;
3111
3112 xmlSchemaFreeValue(dur);
3113
3114 /* ret->value.date.tzo = 0; */
3115 return ret;
3116}
3117
3118/**
3119 * _xmlSchemaDateCastYMToDays:
3120 * @dt: an #xmlSchemaValPtr
3121 *
3122 * Convert mon and year of @dt to total number of days. Take the
3123 * number of years since (or before) 1 AD and add the number of leap
3124 * years. This is a function because negative
3125 * years must be handled a little differently and there is no zero year.
3126 *
3127 * Returns number of days.
3128 */
3129static long
3130_xmlSchemaDateCastYMToDays (const xmlSchemaValPtr dt)
3131{
3132 long ret;
Daniel Veillard49e89632004-09-23 16:24:36 +00003133 int mon;
Daniel Veillard5a872412002-05-22 06:40:27 +00003134
Daniel Veillard49e89632004-09-23 16:24:36 +00003135 mon = dt->value.date.mon;
3136 if (mon <= 0) mon = 1; /* normalization */
3137
3138 if (dt->value.date.year <= 0)
Daniel Veillard5a872412002-05-22 06:40:27 +00003139 ret = (dt->value.date.year * 365) +
3140 (((dt->value.date.year+1)/4)-((dt->value.date.year+1)/100)+
3141 ((dt->value.date.year+1)/400)) +
Daniel Veillard49e89632004-09-23 16:24:36 +00003142 DAY_IN_YEAR(0, mon, dt->value.date.year);
Daniel Veillard5a872412002-05-22 06:40:27 +00003143 else
3144 ret = ((dt->value.date.year-1) * 365) +
3145 (((dt->value.date.year-1)/4)-((dt->value.date.year-1)/100)+
3146 ((dt->value.date.year-1)/400)) +
Daniel Veillard49e89632004-09-23 16:24:36 +00003147 DAY_IN_YEAR(0, mon, dt->value.date.year);
Daniel Veillard5a872412002-05-22 06:40:27 +00003148
3149 return ret;
3150}
3151
3152/**
3153 * TIME_TO_NUMBER:
3154 * @dt: an #xmlSchemaValPtr
3155 *
3156 * Calculates the number of seconds in the time portion of @dt.
3157 *
3158 * Returns seconds.
3159 */
3160#define TIME_TO_NUMBER(dt) \
3161 ((double)((dt->value.date.hour * SECS_PER_HOUR) + \
Daniel Veillardb3721c22003-03-31 11:22:25 +00003162 (dt->value.date.min * SECS_PER_MIN) + \
3163 (dt->value.date.tzo * SECS_PER_MIN)) + \
3164 dt->value.date.sec)
Daniel Veillard5a872412002-05-22 06:40:27 +00003165
3166/**
3167 * xmlSchemaCompareDates:
3168 * @x: a first date/time value
3169 * @y: a second date/time value
3170 *
3171 * Compare 2 date/times
3172 *
3173 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3174 * case of error
3175 */
3176static int
3177xmlSchemaCompareDates (xmlSchemaValPtr x, xmlSchemaValPtr y)
3178{
3179 unsigned char xmask, ymask, xor_mask, and_mask;
3180 xmlSchemaValPtr p1, p2, q1, q2;
3181 long p1d, p2d, q1d, q2d;
3182
3183 if ((x == NULL) || (y == NULL))
3184 return -2;
3185
3186 if (x->value.date.tz_flag) {
3187
3188 if (!y->value.date.tz_flag) {
3189 p1 = xmlSchemaDateNormalize(x, 0);
3190 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3191 /* normalize y + 14:00 */
3192 q1 = xmlSchemaDateNormalize(y, (14 * SECS_PER_HOUR));
3193
3194 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003195 if (p1d < q1d) {
3196 xmlSchemaFreeValue(p1);
3197 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003198 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003199 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003200 double sec;
3201
3202 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00003203 if (sec < 0.0) {
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 {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003208 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003209 /* normalize y - 14:00 */
3210 q2 = xmlSchemaDateNormalize(y, -(14 * SECS_PER_HOUR));
3211 q2d = _xmlSchemaDateCastYMToDays(q2) + q2->value.date.day;
3212 if (p1d > q2d)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003213 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003214 else if (p1d == q2d) {
3215 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q2);
3216 if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003217 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003218 else
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003219 ret = 2; /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00003220 }
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003221 xmlSchemaFreeValue(p1);
3222 xmlSchemaFreeValue(q1);
3223 xmlSchemaFreeValue(q2);
3224 if (ret != 0)
3225 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003226 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00003227 } else {
3228 xmlSchemaFreeValue(p1);
3229 xmlSchemaFreeValue(q1);
3230 }
Daniel Veillard5a872412002-05-22 06:40:27 +00003231 }
3232 } else if (y->value.date.tz_flag) {
3233 q1 = xmlSchemaDateNormalize(y, 0);
3234 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
3235
3236 /* normalize x - 14:00 */
3237 p1 = xmlSchemaDateNormalize(x, -(14 * SECS_PER_HOUR));
3238 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3239
Daniel Veillardfdc91562002-07-01 21:52:03 +00003240 if (p1d < q1d) {
3241 xmlSchemaFreeValue(p1);
3242 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003243 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003244 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003245 double sec;
3246
3247 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00003248 if (sec < 0.0) {
3249 xmlSchemaFreeValue(p1);
3250 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003251 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003252 } else {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003253 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003254 /* normalize x + 14:00 */
3255 p2 = xmlSchemaDateNormalize(x, (14 * SECS_PER_HOUR));
3256 p2d = _xmlSchemaDateCastYMToDays(p2) + p2->value.date.day;
3257
Daniel Veillard6560a422003-03-27 21:25:38 +00003258 if (p2d > q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003259 ret = 1;
Daniel Veillard6560a422003-03-27 21:25:38 +00003260 } else if (p2d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003261 sec = TIME_TO_NUMBER(p2) - TIME_TO_NUMBER(q1);
3262 if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003263 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003264 else
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003265 ret = 2; /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00003266 }
Daniel Veillard6560a422003-03-27 21:25:38 +00003267 xmlSchemaFreeValue(p1);
3268 xmlSchemaFreeValue(q1);
3269 xmlSchemaFreeValue(p2);
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003270 if (ret != 0)
3271 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003272 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00003273 } else {
3274 xmlSchemaFreeValue(p1);
3275 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003276 }
3277 }
3278
3279 /*
3280 * if the same type then calculate the difference
3281 */
3282 if (x->type == y->type) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003283 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003284 q1 = xmlSchemaDateNormalize(y, 0);
3285 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
3286
3287 p1 = xmlSchemaDateNormalize(x, 0);
3288 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3289
Daniel Veillardfdc91562002-07-01 21:52:03 +00003290 if (p1d < q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003291 ret = -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003292 } else if (p1d > q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003293 ret = 1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003294 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00003295 double sec;
3296
3297 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
3298 if (sec < 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003299 ret = -1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003300 else if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003301 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003302
3303 }
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003304 xmlSchemaFreeValue(p1);
3305 xmlSchemaFreeValue(q1);
3306 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003307 }
3308
3309 switch (x->type) {
3310 case XML_SCHEMAS_DATETIME:
3311 xmask = 0xf;
3312 break;
3313 case XML_SCHEMAS_DATE:
3314 xmask = 0x7;
3315 break;
3316 case XML_SCHEMAS_GYEAR:
3317 xmask = 0x1;
3318 break;
3319 case XML_SCHEMAS_GMONTH:
3320 xmask = 0x2;
3321 break;
3322 case XML_SCHEMAS_GDAY:
3323 xmask = 0x3;
3324 break;
3325 case XML_SCHEMAS_GYEARMONTH:
3326 xmask = 0x3;
3327 break;
3328 case XML_SCHEMAS_GMONTHDAY:
3329 xmask = 0x6;
3330 break;
3331 case XML_SCHEMAS_TIME:
3332 xmask = 0x8;
3333 break;
3334 default:
3335 xmask = 0;
3336 break;
3337 }
3338
3339 switch (y->type) {
3340 case XML_SCHEMAS_DATETIME:
3341 ymask = 0xf;
3342 break;
3343 case XML_SCHEMAS_DATE:
3344 ymask = 0x7;
3345 break;
3346 case XML_SCHEMAS_GYEAR:
3347 ymask = 0x1;
3348 break;
3349 case XML_SCHEMAS_GMONTH:
3350 ymask = 0x2;
3351 break;
3352 case XML_SCHEMAS_GDAY:
3353 ymask = 0x3;
3354 break;
3355 case XML_SCHEMAS_GYEARMONTH:
3356 ymask = 0x3;
3357 break;
3358 case XML_SCHEMAS_GMONTHDAY:
3359 ymask = 0x6;
3360 break;
3361 case XML_SCHEMAS_TIME:
3362 ymask = 0x8;
3363 break;
3364 default:
3365 ymask = 0;
3366 break;
3367 }
3368
3369 xor_mask = xmask ^ ymask; /* mark type differences */
3370 and_mask = xmask & ymask; /* mark field specification */
3371
3372 /* year */
3373 if (xor_mask & 1)
3374 return 2; /* indeterminate */
3375 else if (and_mask & 1) {
3376 if (x->value.date.year < y->value.date.year)
3377 return -1;
3378 else if (x->value.date.year > y->value.date.year)
3379 return 1;
3380 }
3381
3382 /* month */
3383 if (xor_mask & 2)
3384 return 2; /* indeterminate */
3385 else if (and_mask & 2) {
3386 if (x->value.date.mon < y->value.date.mon)
3387 return -1;
3388 else if (x->value.date.mon > y->value.date.mon)
3389 return 1;
3390 }
3391
3392 /* day */
3393 if (xor_mask & 4)
3394 return 2; /* indeterminate */
3395 else if (and_mask & 4) {
3396 if (x->value.date.day < y->value.date.day)
3397 return -1;
3398 else if (x->value.date.day > y->value.date.day)
3399 return 1;
3400 }
3401
3402 /* time */
3403 if (xor_mask & 8)
3404 return 2; /* indeterminate */
3405 else if (and_mask & 8) {
3406 if (x->value.date.hour < y->value.date.hour)
3407 return -1;
3408 else if (x->value.date.hour > y->value.date.hour)
3409 return 1;
3410 else if (x->value.date.min < y->value.date.min)
3411 return -1;
3412 else if (x->value.date.min > y->value.date.min)
3413 return 1;
3414 else if (x->value.date.sec < y->value.date.sec)
3415 return -1;
3416 else if (x->value.date.sec > y->value.date.sec)
3417 return 1;
3418 }
3419
Daniel Veillard070803b2002-05-03 07:29:38 +00003420 return 0;
3421}
3422
3423/**
Daniel Veillardc4c21552003-03-29 10:53:38 +00003424 * xmlSchemaCompareNormStrings:
3425 * @x: a first string value
3426 * @y: a second string value
3427 *
3428 * Compare 2 string for their normalized values.
3429 *
3430 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
3431 * case of error
3432 */
3433static int
3434xmlSchemaCompareNormStrings(xmlSchemaValPtr x, xmlSchemaValPtr y) {
3435 const xmlChar *utf1;
3436 const xmlChar *utf2;
3437 int tmp;
3438
3439 if ((x == NULL) || (y == NULL))
3440 return(-2);
3441 utf1 = x->value.str;
3442 utf2 = y->value.str;
3443
William M. Brack76e95df2003-10-18 16:20:14 +00003444 while (IS_BLANK_CH(*utf1)) utf1++;
3445 while (IS_BLANK_CH(*utf2)) utf2++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003446 while ((*utf1 != 0) && (*utf2 != 0)) {
William M. Brack76e95df2003-10-18 16:20:14 +00003447 if (IS_BLANK_CH(*utf1)) {
3448 if (!IS_BLANK_CH(*utf2)) {
Daniel Veillardc4c21552003-03-29 10:53:38 +00003449 tmp = *utf1 - *utf2;
3450 return(tmp);
3451 }
William M. Brack76e95df2003-10-18 16:20:14 +00003452 while (IS_BLANK_CH(*utf1)) utf1++;
3453 while (IS_BLANK_CH(*utf2)) utf2++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003454 } else {
3455 tmp = *utf1++ - *utf2++;
3456 if (tmp < 0)
3457 return(-1);
3458 if (tmp > 0)
3459 return(1);
3460 }
3461 }
3462 if (*utf1 != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00003463 while (IS_BLANK_CH(*utf1)) utf1++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003464 if (*utf1 != 0)
3465 return(1);
3466 }
3467 if (*utf2 != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00003468 while (IS_BLANK_CH(*utf2)) utf2++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003469 if (*utf2 != 0)
3470 return(-1);
3471 }
3472 return(0);
3473}
3474
3475/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003476 * xmlSchemaCompareFloats:
3477 * @x: a first float or double value
3478 * @y: a second float or double value
3479 *
3480 * Compare 2 values
3481 *
3482 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3483 * case of error
3484 */
3485static int
3486xmlSchemaCompareFloats(xmlSchemaValPtr x, xmlSchemaValPtr y) {
3487 double d1, d2;
3488
3489 if ((x == NULL) || (y == NULL))
3490 return(-2);
3491
3492 /*
3493 * Cast everything to doubles.
3494 */
3495 if (x->type == XML_SCHEMAS_DOUBLE)
3496 d1 = x->value.d;
3497 else if (x->type == XML_SCHEMAS_FLOAT)
3498 d1 = x->value.f;
3499 else
3500 return(-2);
3501
3502 if (y->type == XML_SCHEMAS_DOUBLE)
3503 d2 = y->value.d;
3504 else if (y->type == XML_SCHEMAS_FLOAT)
3505 d2 = y->value.f;
3506 else
3507 return(-2);
3508
3509 /*
3510 * Check for special cases.
3511 */
3512 if (xmlXPathIsNaN(d1)) {
3513 if (xmlXPathIsNaN(d2))
3514 return(0);
3515 return(1);
3516 }
3517 if (xmlXPathIsNaN(d2))
3518 return(-1);
3519 if (d1 == xmlXPathPINF) {
3520 if (d2 == xmlXPathPINF)
3521 return(0);
3522 return(1);
3523 }
3524 if (d2 == xmlXPathPINF)
3525 return(-1);
3526 if (d1 == xmlXPathNINF) {
3527 if (d2 == xmlXPathNINF)
3528 return(0);
3529 return(-1);
3530 }
3531 if (d2 == xmlXPathNINF)
3532 return(1);
3533
3534 /*
3535 * basic tests, the last one we should have equality, but
3536 * portability is more important than speed and handling
3537 * NaN or Inf in a portable way is always a challenge, so ...
3538 */
3539 if (d1 < d2)
3540 return(-1);
3541 if (d1 > d2)
3542 return(1);
3543 if (d1 == d2)
3544 return(0);
3545 return(2);
3546}
3547
3548/**
Daniel Veillard4255d502002-04-16 15:50:10 +00003549 * xmlSchemaCompareValues:
3550 * @x: a first value
3551 * @y: a second value
3552 *
3553 * Compare 2 values
3554 *
Daniel Veillard5a872412002-05-22 06:40:27 +00003555 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3556 * case of error
Daniel Veillard4255d502002-04-16 15:50:10 +00003557 */
Daniel Veillard80b19092003-03-28 13:29:53 +00003558int
Daniel Veillard4255d502002-04-16 15:50:10 +00003559xmlSchemaCompareValues(xmlSchemaValPtr x, xmlSchemaValPtr y) {
3560 if ((x == NULL) || (y == NULL))
3561 return(-2);
3562
3563 switch (x->type) {
Daniel Veillard80b19092003-03-28 13:29:53 +00003564 case XML_SCHEMAS_UNKNOWN:
William M. Brack2f2a6632004-08-20 23:09:47 +00003565 case XML_SCHEMAS_ANYTYPE:
3566 case XML_SCHEMAS_ANYSIMPLETYPE:
Daniel Veillard80b19092003-03-28 13:29:53 +00003567 return(-2);
3568 case XML_SCHEMAS_INTEGER:
3569 case XML_SCHEMAS_NPINTEGER:
3570 case XML_SCHEMAS_NINTEGER:
3571 case XML_SCHEMAS_NNINTEGER:
3572 case XML_SCHEMAS_PINTEGER:
3573 case XML_SCHEMAS_INT:
3574 case XML_SCHEMAS_UINT:
3575 case XML_SCHEMAS_LONG:
3576 case XML_SCHEMAS_ULONG:
3577 case XML_SCHEMAS_SHORT:
3578 case XML_SCHEMAS_USHORT:
3579 case XML_SCHEMAS_BYTE:
3580 case XML_SCHEMAS_UBYTE:
Daniel Veillard4255d502002-04-16 15:50:10 +00003581 case XML_SCHEMAS_DECIMAL:
Daniel Veillard80b19092003-03-28 13:29:53 +00003582 if (y->type == x->type)
3583 return(xmlSchemaCompareDecimals(x, y));
3584 if ((y->type == XML_SCHEMAS_DECIMAL) ||
3585 (y->type == XML_SCHEMAS_INTEGER) ||
3586 (y->type == XML_SCHEMAS_NPINTEGER) ||
3587 (y->type == XML_SCHEMAS_NINTEGER) ||
3588 (y->type == XML_SCHEMAS_NNINTEGER) ||
3589 (y->type == XML_SCHEMAS_PINTEGER) ||
3590 (y->type == XML_SCHEMAS_INT) ||
3591 (y->type == XML_SCHEMAS_UINT) ||
3592 (y->type == XML_SCHEMAS_LONG) ||
3593 (y->type == XML_SCHEMAS_ULONG) ||
3594 (y->type == XML_SCHEMAS_SHORT) ||
3595 (y->type == XML_SCHEMAS_USHORT) ||
3596 (y->type == XML_SCHEMAS_BYTE) ||
3597 (y->type == XML_SCHEMAS_UBYTE))
Daniel Veillard4255d502002-04-16 15:50:10 +00003598 return(xmlSchemaCompareDecimals(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00003599 return(-2);
Daniel Veillard070803b2002-05-03 07:29:38 +00003600 case XML_SCHEMAS_DURATION:
3601 if (y->type == XML_SCHEMAS_DURATION)
3602 return(xmlSchemaCompareDurations(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00003603 return(-2);
3604 case XML_SCHEMAS_TIME:
3605 case XML_SCHEMAS_GDAY:
3606 case XML_SCHEMAS_GMONTH:
3607 case XML_SCHEMAS_GMONTHDAY:
3608 case XML_SCHEMAS_GYEAR:
3609 case XML_SCHEMAS_GYEARMONTH:
3610 case XML_SCHEMAS_DATE:
3611 case XML_SCHEMAS_DATETIME:
3612 if ((y->type == XML_SCHEMAS_DATETIME) ||
3613 (y->type == XML_SCHEMAS_TIME) ||
3614 (y->type == XML_SCHEMAS_GDAY) ||
3615 (y->type == XML_SCHEMAS_GMONTH) ||
3616 (y->type == XML_SCHEMAS_GMONTHDAY) ||
3617 (y->type == XML_SCHEMAS_GYEAR) ||
3618 (y->type == XML_SCHEMAS_DATE) ||
3619 (y->type == XML_SCHEMAS_GYEARMONTH))
3620 return (xmlSchemaCompareDates(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00003621 return (-2);
Daniel Veillard80b19092003-03-28 13:29:53 +00003622 case XML_SCHEMAS_NORMSTRING:
Daniel Veillard80b19092003-03-28 13:29:53 +00003623 case XML_SCHEMAS_TOKEN:
3624 case XML_SCHEMAS_LANGUAGE:
3625 case XML_SCHEMAS_NMTOKEN:
Daniel Veillard80b19092003-03-28 13:29:53 +00003626 case XML_SCHEMAS_NAME:
Daniel Veillard80b19092003-03-28 13:29:53 +00003627 case XML_SCHEMAS_NCNAME:
3628 case XML_SCHEMAS_ID:
3629 case XML_SCHEMAS_IDREF:
Daniel Veillard80b19092003-03-28 13:29:53 +00003630 case XML_SCHEMAS_ENTITY:
Daniel Veillard80b19092003-03-28 13:29:53 +00003631 case XML_SCHEMAS_NOTATION:
3632 case XML_SCHEMAS_ANYURI:
Daniel Veillardc4c21552003-03-29 10:53:38 +00003633 if ((y->type == XML_SCHEMAS_NORMSTRING) ||
3634 (y->type == XML_SCHEMAS_TOKEN) ||
3635 (y->type == XML_SCHEMAS_LANGUAGE) ||
3636 (y->type == XML_SCHEMAS_NMTOKEN) ||
3637 (y->type == XML_SCHEMAS_NAME) ||
3638 (y->type == XML_SCHEMAS_QNAME) ||
3639 (y->type == XML_SCHEMAS_NCNAME) ||
3640 (y->type == XML_SCHEMAS_ID) ||
3641 (y->type == XML_SCHEMAS_IDREF) ||
3642 (y->type == XML_SCHEMAS_ENTITY) ||
3643 (y->type == XML_SCHEMAS_NOTATION) ||
3644 (y->type == XML_SCHEMAS_ANYURI))
3645 return (xmlSchemaCompareNormStrings(x, y));
3646 return (-2);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003647 case XML_SCHEMAS_QNAME:
3648 if (y->type == XML_SCHEMAS_QNAME) {
3649 if ((xmlStrEqual(x->value.qname.name, y->value.qname.name)) &&
3650 (xmlStrEqual(x->value.qname.uri, y->value.qname.uri)))
3651 return(0);
3652 return(2);
3653 }
3654 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00003655 case XML_SCHEMAS_FLOAT:
3656 case XML_SCHEMAS_DOUBLE:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003657 if ((y->type == XML_SCHEMAS_FLOAT) ||
3658 (y->type == XML_SCHEMAS_DOUBLE))
3659 return (xmlSchemaCompareFloats(x, y));
3660 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00003661 case XML_SCHEMAS_BOOLEAN:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003662 if (y->type == XML_SCHEMAS_BOOLEAN) {
3663 if (x->value.b == y->value.b)
3664 return(0);
3665 if (x->value.b == 0)
3666 return(-1);
3667 return(1);
3668 }
3669 return (-2);
Daniel Veillard560c2a42003-07-06 21:13:49 +00003670 case XML_SCHEMAS_HEXBINARY:
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00003671 if (y->type == XML_SCHEMAS_HEXBINARY) {
3672 if (x->value.hex.total == y->value.hex.total) {
3673 int ret = xmlStrcmp(x->value.hex.str, y->value.hex.str);
3674 if (ret > 0)
3675 return(1);
3676 else if (ret == 0)
3677 return(0);
3678 }
3679 else if (x->value.hex.total > y->value.hex.total)
3680 return(1);
3681
3682 return(-1);
3683 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00003684 return (-2);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003685 case XML_SCHEMAS_BASE64BINARY:
3686 if (y->type == XML_SCHEMAS_BASE64BINARY) {
3687 if (x->value.base64.total == y->value.base64.total) {
3688 int ret = xmlStrcmp(x->value.base64.str,
3689 y->value.base64.str);
3690 if (ret > 0)
3691 return(1);
3692 else if (ret == 0)
3693 return(0);
3694 }
3695 else if (x->value.base64.total > y->value.base64.total)
3696 return(1);
3697 else
3698 return(-1);
3699 }
3700 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00003701 case XML_SCHEMAS_STRING:
3702 case XML_SCHEMAS_IDREFS:
3703 case XML_SCHEMAS_ENTITIES:
3704 case XML_SCHEMAS_NMTOKENS:
3705 TODO
3706 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00003707 }
Daniel Veillard5a872412002-05-22 06:40:27 +00003708 return -2;
Daniel Veillard4255d502002-04-16 15:50:10 +00003709}
3710
3711/**
Daniel Veillardc4c21552003-03-29 10:53:38 +00003712 * xmlSchemaNormLen:
3713 * @value: a string
3714 *
3715 * Computes the UTF8 length of the normalized value of the string
3716 *
3717 * Returns the length or -1 in case of error.
3718 */
3719static int
3720xmlSchemaNormLen(const xmlChar *value) {
3721 const xmlChar *utf;
3722 int ret = 0;
3723
3724 if (value == NULL)
3725 return(-1);
3726 utf = value;
William M. Brack76e95df2003-10-18 16:20:14 +00003727 while (IS_BLANK_CH(*utf)) utf++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003728 while (*utf != 0) {
3729 if (utf[0] & 0x80) {
3730 if ((utf[1] & 0xc0) != 0x80)
3731 return(-1);
3732 if ((utf[0] & 0xe0) == 0xe0) {
3733 if ((utf[2] & 0xc0) != 0x80)
3734 return(-1);
3735 if ((utf[0] & 0xf0) == 0xf0) {
3736 if ((utf[0] & 0xf8) != 0xf0 || (utf[3] & 0xc0) != 0x80)
3737 return(-1);
3738 utf += 4;
3739 } else {
3740 utf += 3;
3741 }
3742 } else {
3743 utf += 2;
3744 }
William M. Brack76e95df2003-10-18 16:20:14 +00003745 } else if (IS_BLANK_CH(*utf)) {
3746 while (IS_BLANK_CH(*utf)) utf++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003747 if (*utf == 0)
3748 break;
3749 } else {
3750 utf++;
3751 }
3752 ret++;
3753 }
3754 return(ret);
3755}
3756
Daniel Veillard6927b102004-10-27 17:29:04 +00003757/**
3758 * xmlSchemaGetFacetValueAsULong:
3759 * @facet: an schemas type facet
3760 *
3761 * Extract the value of a facet
3762 *
3763 * Returns the value as a long
3764 */
Daniel Veillardc0826a72004-08-10 14:17:33 +00003765unsigned long
3766xmlSchemaGetFacetValueAsULong(xmlSchemaFacetPtr facet)
3767{
3768 /*
3769 * TODO: Check if this is a decimal.
3770 */
3771 return ((unsigned long) facet->val->value.decimal.lo);
3772}
3773
Daniel Veillardc4c21552003-03-29 10:53:38 +00003774/**
Daniel Veillard01fa6152004-06-29 17:04:39 +00003775 * xmlSchemaValidateListSimpleTypeFacet:
3776 * @facet: the facet to check
3777 * @value: the lexical repr of the value to validate
3778 * @actualLen: the number of list items
3779 * @expectedLen: the resulting expected number of list items
3780 *
3781 * Checks the value of a list simple type against a facet.
3782 *
3783 * Returns 0 if the value is valid, a positive error code
3784 * number otherwise and -1 in case of an internal error.
3785 */
3786int
3787xmlSchemaValidateListSimpleTypeFacet(xmlSchemaFacetPtr facet,
3788 const xmlChar *value,
3789 unsigned long actualLen,
3790 unsigned long *expectedLen)
3791{
3792 /*
3793 * TODO: Check if this will work with large numbers.
3794 * (compare value.decimal.mi and value.decimal.hi as well?).
3795 */
3796 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
3797 if (actualLen != facet->val->value.decimal.lo) {
Daniel Veillardc0826a72004-08-10 14:17:33 +00003798 if (expectedLen != 0)
3799 *expectedLen = facet->val->value.decimal.lo;
Daniel Veillard01fa6152004-06-29 17:04:39 +00003800 return (XML_SCHEMAV_CVC_LENGTH_VALID);
3801 }
3802 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
3803 if (actualLen < facet->val->value.decimal.lo) {
Daniel Veillardc0826a72004-08-10 14:17:33 +00003804 if (expectedLen != 0)
3805 *expectedLen = facet->val->value.decimal.lo;
Daniel Veillard01fa6152004-06-29 17:04:39 +00003806 return (XML_SCHEMAV_CVC_MINLENGTH_VALID);
3807 }
3808 } else if (facet->type == XML_SCHEMA_FACET_MAXLENGTH) {
3809 if (actualLen > facet->val->value.decimal.lo) {
Daniel Veillardc0826a72004-08-10 14:17:33 +00003810 if (expectedLen != 0)
3811 *expectedLen = facet->val->value.decimal.lo;
Daniel Veillard01fa6152004-06-29 17:04:39 +00003812 return (XML_SCHEMAV_CVC_MAXLENGTH_VALID);
3813 }
3814 } else
3815 /*
3816 * NOTE: That we can pass NULL as xmlSchemaValPtr to
3817 * xmlSchemaValidateFacet, since the remaining facet types
3818 * are: XML_SCHEMA_FACET_PATTERN, XML_SCHEMA_FACET_ENUMERATION.
3819 */
3820 return(xmlSchemaValidateFacet(NULL, facet, value, NULL));
3821 return (0);
3822}
3823
3824/**
Daniel Veillard6927b102004-10-27 17:29:04 +00003825 * xmlSchemaValidateLengthFacet:
Daniel Veillardc0826a72004-08-10 14:17:33 +00003826 * @type: the built-in type
3827 * @facet: the facet to check
3828 * @value: the lexical repr. of the value to be validated
3829 * @val: the precomputed value
3830 * @length: the actual length of the value
3831 *
3832 * Checka a value against a "length", "minLength" and "maxLength"
3833 * facet; sets @length to the computed length of @value.
3834 *
3835 * Returns 0 if the value is valid, a positive error code
3836 * otherwise and -1 in case of an internal or API error.
3837 */
3838int
3839xmlSchemaValidateLengthFacet(xmlSchemaTypePtr type,
3840 xmlSchemaFacetPtr facet,
3841 const xmlChar *value,
3842 xmlSchemaValPtr val,
3843 unsigned long *length)
3844{
3845 unsigned int len = 0;
3846
3847 *length = 0;
3848 if ((facet->type != XML_SCHEMA_FACET_LENGTH) &&
3849 (facet->type != XML_SCHEMA_FACET_MAXLENGTH) &&
3850 (facet->type != XML_SCHEMA_FACET_MINLENGTH))
3851 return (-1);
3852
3853 if ((facet->val == NULL) ||
3854 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
3855 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
3856 (facet->val->value.decimal.frac != 0)) {
3857 return(-1);
3858 }
3859 if ((val != NULL) && (val->type == XML_SCHEMAS_HEXBINARY))
3860 len = val->value.hex.total;
3861 else if ((val != NULL) && (val->type == XML_SCHEMAS_BASE64BINARY))
3862 len = val->value.base64.total;
3863 else {
3864 switch (type->builtInType) {
3865 case XML_SCHEMAS_IDREF:
3866 case XML_SCHEMAS_NORMSTRING:
3867 case XML_SCHEMAS_TOKEN:
3868 case XML_SCHEMAS_LANGUAGE:
3869 case XML_SCHEMAS_NMTOKEN:
3870 case XML_SCHEMAS_NAME:
3871 case XML_SCHEMAS_NCNAME:
3872 case XML_SCHEMAS_ID:
3873 len = xmlSchemaNormLen(value);
3874 break;
3875 case XML_SCHEMAS_STRING:
3876 /*
3877 * FIXME: What exactly to do with anyURI?
3878 */
3879 case XML_SCHEMAS_ANYURI:
3880 if (value != NULL)
3881 len = xmlUTF8Strlen(value);
3882 break;
3883 default:
3884 TODO
3885 }
3886 }
3887 *length = (unsigned long) len;
3888 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
3889 if (len != facet->val->value.decimal.lo)
3890 return(XML_SCHEMAV_CVC_LENGTH_VALID);
3891 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
3892 if (len < facet->val->value.decimal.lo)
3893 return(XML_SCHEMAV_CVC_MINLENGTH_VALID);
3894 } else {
3895 if (len > facet->val->value.decimal.lo)
3896 return(XML_SCHEMAV_CVC_MAXLENGTH_VALID);
3897 }
3898
3899 return (0);
3900}
3901
3902/**
3903 * xmlSchemaValidateFacet:
Daniel Veillard01c13b52002-12-10 15:19:08 +00003904 * @base: the base type
Daniel Veillard4255d502002-04-16 15:50:10 +00003905 * @facet: the facet to check
3906 * @value: the lexical repr of the value to validate
3907 * @val: the precomputed value
3908 *
3909 * Check a value against a facet condition
3910 *
3911 * Returns 0 if the element is schemas valid, a positive error code
3912 * number otherwise and -1 in case of internal or API error.
3913 */
3914int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00003915xmlSchemaValidateFacet(xmlSchemaTypePtr base ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +00003916 xmlSchemaFacetPtr facet,
Daniel Veillard4255d502002-04-16 15:50:10 +00003917 const xmlChar *value, xmlSchemaValPtr val)
3918{
3919 int ret;
3920
3921 switch (facet->type) {
3922 case XML_SCHEMA_FACET_PATTERN:
3923 ret = xmlRegexpExec(facet->regexp, value);
3924 if (ret == 1)
3925 return(0);
3926 if (ret == 0) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00003927 return(XML_SCHEMAV_CVC_PATTERN_VALID);
Daniel Veillard4255d502002-04-16 15:50:10 +00003928 }
3929 return(ret);
3930 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
3931 ret = xmlSchemaCompareValues(val, facet->val);
3932 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003933 /* TODO error code */
Daniel Veillard4255d502002-04-16 15:50:10 +00003934 return(-1);
3935 }
3936 if (ret == -1)
3937 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00003938 /* error code */
Daniel Veillard01fa6152004-06-29 17:04:39 +00003939 return(XML_SCHEMAV_CVC_MAXEXCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00003940 case XML_SCHEMA_FACET_MAXINCLUSIVE:
3941 ret = xmlSchemaCompareValues(val, facet->val);
3942 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003943 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00003944 return(-1);
3945 }
3946 if ((ret == -1) || (ret == 0))
3947 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00003948 /* error code */
Daniel Veillard01fa6152004-06-29 17:04:39 +00003949 return(XML_SCHEMAV_CVC_MAXINCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00003950 case XML_SCHEMA_FACET_MINEXCLUSIVE:
3951 ret = xmlSchemaCompareValues(val, facet->val);
3952 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003953 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00003954 return(-1);
3955 }
3956 if (ret == 1)
3957 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00003958 /* error code */
Daniel Veillard01fa6152004-06-29 17:04:39 +00003959 return(XML_SCHEMAV_CVC_MINEXCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00003960 case XML_SCHEMA_FACET_MININCLUSIVE:
3961 ret = xmlSchemaCompareValues(val, facet->val);
3962 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003963 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00003964 return(-1);
3965 }
3966 if ((ret == 1) || (ret == 0))
3967 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00003968 /* error code */
Daniel Veillard01fa6152004-06-29 17:04:39 +00003969 return(XML_SCHEMAV_CVC_MININCLUSIVE_VALID);
Daniel Veillard8651f532002-04-17 09:06:27 +00003970 case XML_SCHEMA_FACET_WHITESPACE:
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003971 /* TODO whitespaces */
Daniel Veillard01fa6152004-06-29 17:04:39 +00003972 /*
3973 * NOTE: Whitespace should be handled to normalize
3974 * the value to be validated against a the facets;
3975 * not to normalize the value in-between.
3976 */
Daniel Veillard8651f532002-04-17 09:06:27 +00003977 return(0);
Daniel Veillard88c58912002-04-23 07:12:20 +00003978 case XML_SCHEMA_FACET_ENUMERATION:
3979 if ((facet->value != NULL) &&
3980 (xmlStrEqual(facet->value, value)))
3981 return(0);
Daniel Veillard01fa6152004-06-29 17:04:39 +00003982 return(XML_SCHEMAV_CVC_ENUMERATION_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003983 case XML_SCHEMA_FACET_LENGTH:
3984 case XML_SCHEMA_FACET_MAXLENGTH:
3985 case XML_SCHEMA_FACET_MINLENGTH: {
3986 unsigned int len = 0;
3987
3988 if ((facet->val == NULL) ||
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003989 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
3990 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003991 (facet->val->value.decimal.frac != 0)) {
3992 return(-1);
3993 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00003994 if ((val != NULL) && (val->type == XML_SCHEMAS_HEXBINARY))
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00003995 len = val->value.hex.total;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003996 else if ((val != NULL) && (val->type == XML_SCHEMAS_BASE64BINARY))
3997 len = val->value.base64.total;
3998 else {
Daniel Veillard01fa6152004-06-29 17:04:39 +00003999 switch (base->builtInType) {
Daniel Veillard560c2a42003-07-06 21:13:49 +00004000 case XML_SCHEMAS_IDREF:
4001 case XML_SCHEMAS_NORMSTRING:
4002 case XML_SCHEMAS_TOKEN:
4003 case XML_SCHEMAS_LANGUAGE:
4004 case XML_SCHEMAS_NMTOKEN:
4005 case XML_SCHEMAS_NAME:
4006 case XML_SCHEMAS_NCNAME:
4007 case XML_SCHEMAS_ID:
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004008 len = xmlSchemaNormLen(value);
4009 break;
Daniel Veillard560c2a42003-07-06 21:13:49 +00004010 case XML_SCHEMAS_STRING:
Daniel Veillard01fa6152004-06-29 17:04:39 +00004011 /*
4012 * FIXME: What exactly to do with anyURI?
4013 */
4014 case XML_SCHEMAS_ANYURI:
William M. Brackfbf2c5e2004-02-03 17:55:56 +00004015 if (value != NULL)
4016 len = xmlUTF8Strlen(value);
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004017 break;
Daniel Veillard560c2a42003-07-06 21:13:49 +00004018 default:
4019 TODO
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004020 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004021 }
4022 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004023 if (len != facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004024 return(XML_SCHEMAV_CVC_LENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004025 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004026 if (len < facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004027 return(XML_SCHEMAV_CVC_MINLENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004028 } else {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004029 if (len > facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004030 return(XML_SCHEMAV_CVC_MAXLENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004031 }
4032 break;
4033 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00004034 case XML_SCHEMA_FACET_TOTALDIGITS:
4035 case XML_SCHEMA_FACET_FRACTIONDIGITS:
4036
4037 if ((facet->val == NULL) ||
4038 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
4039 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
4040 (facet->val->value.decimal.frac != 0)) {
4041 return(-1);
4042 }
4043 if ((val == NULL) ||
4044 ((val->type != XML_SCHEMAS_DECIMAL) &&
4045 (val->type != XML_SCHEMAS_INTEGER) &&
4046 (val->type != XML_SCHEMAS_NPINTEGER) &&
4047 (val->type != XML_SCHEMAS_NINTEGER) &&
4048 (val->type != XML_SCHEMAS_NNINTEGER) &&
4049 (val->type != XML_SCHEMAS_PINTEGER) &&
4050 (val->type != XML_SCHEMAS_INT) &&
4051 (val->type != XML_SCHEMAS_UINT) &&
4052 (val->type != XML_SCHEMAS_LONG) &&
4053 (val->type != XML_SCHEMAS_ULONG) &&
4054 (val->type != XML_SCHEMAS_SHORT) &&
4055 (val->type != XML_SCHEMAS_USHORT) &&
4056 (val->type != XML_SCHEMAS_BYTE) &&
4057 (val->type != XML_SCHEMAS_UBYTE))) {
4058 return(-1);
4059 }
4060 if (facet->type == XML_SCHEMA_FACET_TOTALDIGITS) {
4061 if (val->value.decimal.total > facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004062 return(XML_SCHEMAV_CVC_TOTALDIGITS_VALID);
Daniel Veillard560c2a42003-07-06 21:13:49 +00004063
4064 } else if (facet->type == XML_SCHEMA_FACET_FRACTIONDIGITS) {
4065 if (val->value.decimal.frac > facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004066 return(XML_SCHEMAV_CVC_FRACTIONDIGITS_VALID);
Daniel Veillard560c2a42003-07-06 21:13:49 +00004067 }
4068 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00004069 default:
4070 TODO
4071 }
4072 return(0);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00004073
Daniel Veillard4255d502002-04-16 15:50:10 +00004074}
4075
4076#endif /* LIBXML_SCHEMAS_ENABLED */