blob: 6dd8cbbf06c4b016cb3691ea6ab47a495489566a [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{
Daniel Veillardce682bc2004-11-05 17:22:25 +0000473 if (type == NULL)
474 return (-1);
Daniel Veillard01fa6152004-06-29 17:04:39 +0000475 if (type->type != XML_SCHEMA_TYPE_BASIC)
476 return (-1);
477 switch (type->builtInType) {
478 case XML_SCHEMAS_BOOLEAN:
479 if ((facetType == XML_SCHEMA_FACET_PATTERN) ||
480 (facetType == XML_SCHEMA_FACET_WHITESPACE))
481 return (1);
482 else
483 return (0);
484 case XML_SCHEMAS_STRING:
485 case XML_SCHEMAS_NOTATION:
486 case XML_SCHEMAS_QNAME:
487 case XML_SCHEMAS_ANYURI:
488 case XML_SCHEMAS_BASE64BINARY:
489 case XML_SCHEMAS_HEXBINARY:
490 if ((facetType == XML_SCHEMA_FACET_LENGTH) ||
491 (facetType == XML_SCHEMA_FACET_MINLENGTH) ||
492 (facetType == XML_SCHEMA_FACET_MAXLENGTH) ||
493 (facetType == XML_SCHEMA_FACET_PATTERN) ||
494 (facetType == XML_SCHEMA_FACET_ENUMERATION) ||
495 (facetType == XML_SCHEMA_FACET_WHITESPACE))
496 return (1);
497 else
498 return (0);
499 case XML_SCHEMAS_DECIMAL:
500 if ((facetType == XML_SCHEMA_FACET_TOTALDIGITS) ||
501 (facetType == XML_SCHEMA_FACET_FRACTIONDIGITS) ||
502 (facetType == XML_SCHEMA_FACET_PATTERN) ||
503 (facetType == XML_SCHEMA_FACET_WHITESPACE) ||
504 (facetType == XML_SCHEMA_FACET_ENUMERATION) ||
505 (facetType == XML_SCHEMA_FACET_MAXINCLUSIVE) ||
506 (facetType == XML_SCHEMA_FACET_MAXEXCLUSIVE) ||
507 (facetType == XML_SCHEMA_FACET_MININCLUSIVE) ||
508 (facetType == XML_SCHEMA_FACET_MINEXCLUSIVE))
509 return (1);
510 else
511 return (0);
512 case XML_SCHEMAS_TIME:
513 case XML_SCHEMAS_GDAY:
514 case XML_SCHEMAS_GMONTH:
515 case XML_SCHEMAS_GMONTHDAY:
516 case XML_SCHEMAS_GYEAR:
517 case XML_SCHEMAS_GYEARMONTH:
518 case XML_SCHEMAS_DATE:
519 case XML_SCHEMAS_DATETIME:
520 case XML_SCHEMAS_DURATION:
521 case XML_SCHEMAS_FLOAT:
522 case XML_SCHEMAS_DOUBLE:
523 if ((facetType == XML_SCHEMA_FACET_PATTERN) ||
524 (facetType == XML_SCHEMA_FACET_ENUMERATION) ||
525 (facetType == XML_SCHEMA_FACET_WHITESPACE) ||
526 (facetType == XML_SCHEMA_FACET_MAXINCLUSIVE) ||
527 (facetType == XML_SCHEMA_FACET_MAXEXCLUSIVE) ||
528 (facetType == XML_SCHEMA_FACET_MININCLUSIVE) ||
529 (facetType == XML_SCHEMA_FACET_MINEXCLUSIVE))
530 return (1);
531 else
532 return (0);
533 default:
Daniel Veillardc7e3cc42004-09-28 12:33:52 +0000534 break;
Daniel Veillard01fa6152004-06-29 17:04:39 +0000535 }
536 return (0);
537}
538
539/**
540 * xmlSchemaGetBuiltInType:
541 * @type: the type of the built in type
542 *
543 * Gives you the type struct for a built-in
544 * type by its type id.
545 *
546 * Returns the type if found, NULL otherwise.
547 */
548xmlSchemaTypePtr
549xmlSchemaGetBuiltInType(xmlSchemaValType type)
550{
551 if (xmlSchemaTypesInitialized == 0)
552 xmlSchemaInitTypes();
553 switch (type) {
554
555 case XML_SCHEMAS_ANYSIMPLETYPE:
556 return (xmlSchemaTypeAnySimpleTypeDef);
557 case XML_SCHEMAS_STRING:
558 return (xmlSchemaTypeStringDef);
559 case XML_SCHEMAS_NORMSTRING:
560 return (xmlSchemaTypeNormStringDef);
561 case XML_SCHEMAS_DECIMAL:
562 return (xmlSchemaTypeDecimalDef);
563 case XML_SCHEMAS_TIME:
564 return (xmlSchemaTypeTimeDef);
565 case XML_SCHEMAS_GDAY:
566 return (xmlSchemaTypeGDayDef);
567 case XML_SCHEMAS_GMONTH:
568 return (xmlSchemaTypeGMonthDef);
569 case XML_SCHEMAS_GMONTHDAY:
570 return (xmlSchemaTypeGMonthDayDef);
571 case XML_SCHEMAS_GYEAR:
572 return (xmlSchemaTypeGYearDef);
573 case XML_SCHEMAS_GYEARMONTH:
574 return (xmlSchemaTypeGYearMonthDef);
575 case XML_SCHEMAS_DATE:
576 return (xmlSchemaTypeDateDef);
577 case XML_SCHEMAS_DATETIME:
578 return (xmlSchemaTypeDatetimeDef);
579 case XML_SCHEMAS_DURATION:
580 return (xmlSchemaTypeDurationDef);
581 case XML_SCHEMAS_FLOAT:
582 return (xmlSchemaTypeFloatDef);
583 case XML_SCHEMAS_DOUBLE:
584 return (xmlSchemaTypeDoubleDef);
585 case XML_SCHEMAS_BOOLEAN:
586 return (xmlSchemaTypeBooleanDef);
587 case XML_SCHEMAS_TOKEN:
588 return (xmlSchemaTypeTokenDef);
589 case XML_SCHEMAS_LANGUAGE:
590 return (xmlSchemaTypeLanguageDef);
591 case XML_SCHEMAS_NMTOKEN:
592 return (xmlSchemaTypeNmtokenDef);
593 case XML_SCHEMAS_NMTOKENS:
594 return (xmlSchemaTypeNmtokensDef);
595 case XML_SCHEMAS_NAME:
596 return (xmlSchemaTypeNameDef);
597 case XML_SCHEMAS_QNAME:
598 return (xmlSchemaTypeQNameDef);
599 case XML_SCHEMAS_NCNAME:
600 return (xmlSchemaTypeNCNameDef);
601 case XML_SCHEMAS_ID:
602 return (xmlSchemaTypeIdDef);
603 case XML_SCHEMAS_IDREF:
604 return (xmlSchemaTypeIdrefDef);
605 case XML_SCHEMAS_IDREFS:
606 return (xmlSchemaTypeIdrefsDef);
607 case XML_SCHEMAS_ENTITY:
608 return (xmlSchemaTypeEntityDef);
609 case XML_SCHEMAS_ENTITIES:
610 return (xmlSchemaTypeEntitiesDef);
611 case XML_SCHEMAS_NOTATION:
612 return (xmlSchemaTypeNotationDef);
613 case XML_SCHEMAS_ANYURI:
614 return (xmlSchemaTypeAnyURIDef);
615 case XML_SCHEMAS_INTEGER:
616 return (xmlSchemaTypeIntegerDef);
617 case XML_SCHEMAS_NPINTEGER:
618 return (xmlSchemaTypeNonPositiveIntegerDef);
619 case XML_SCHEMAS_NINTEGER:
620 return (xmlSchemaTypeNegativeIntegerDef);
621 case XML_SCHEMAS_NNINTEGER:
622 return (xmlSchemaTypeNonNegativeIntegerDef);
623 case XML_SCHEMAS_PINTEGER:
624 return (xmlSchemaTypePositiveIntegerDef);
625 case XML_SCHEMAS_INT:
626 return (xmlSchemaTypeIntDef);
627 case XML_SCHEMAS_UINT:
628 return (xmlSchemaTypeUnsignedIntDef);
629 case XML_SCHEMAS_LONG:
630 return (xmlSchemaTypeLongDef);
631 case XML_SCHEMAS_ULONG:
632 return (xmlSchemaTypeUnsignedLongDef);
633 case XML_SCHEMAS_SHORT:
634 return (xmlSchemaTypeShortDef);
635 case XML_SCHEMAS_USHORT:
636 return (xmlSchemaTypeUnsignedShortDef);
637 case XML_SCHEMAS_BYTE:
638 return (xmlSchemaTypeByteDef);
639 case XML_SCHEMAS_UBYTE:
640 return (xmlSchemaTypeUnsignedByteDef);
641 case XML_SCHEMAS_HEXBINARY:
642 return (xmlSchemaTypeHexBinaryDef);
643 case XML_SCHEMAS_BASE64BINARY:
644 return (xmlSchemaTypeBase64BinaryDef);
645 case XML_SCHEMAS_ANYTYPE:
646 return (xmlSchemaTypeAnyTypeDef);
647 default:
648 return (NULL);
649 }
650}
651
652/**
Daniel Veillard4255d502002-04-16 15:50:10 +0000653 * xmlSchemaNewValue:
654 * @type: the value type
655 *
656 * Allocate a new simple type value
657 *
658 * Returns a pointer to the new value or NULL in case of error
659 */
660static xmlSchemaValPtr
661xmlSchemaNewValue(xmlSchemaValType type) {
662 xmlSchemaValPtr value;
663
664 value = (xmlSchemaValPtr) xmlMalloc(sizeof(xmlSchemaVal));
665 if (value == NULL) {
666 return(NULL);
667 }
668 memset(value, 0, sizeof(xmlSchemaVal));
669 value->type = type;
670 return(value);
671}
672
673/**
674 * xmlSchemaFreeValue:
675 * @value: the value to free
676 *
677 * Cleanup the default XML Schemas type library
678 */
679void
680xmlSchemaFreeValue(xmlSchemaValPtr value) {
681 if (value == NULL)
682 return;
Daniel Veillardc4c21552003-03-29 10:53:38 +0000683 switch (value->type) {
684 case XML_SCHEMAS_STRING:
685 case XML_SCHEMAS_NORMSTRING:
686 case XML_SCHEMAS_TOKEN:
687 case XML_SCHEMAS_LANGUAGE:
688 case XML_SCHEMAS_NMTOKEN:
689 case XML_SCHEMAS_NMTOKENS:
690 case XML_SCHEMAS_NAME:
Daniel Veillardc4c21552003-03-29 10:53:38 +0000691 case XML_SCHEMAS_NCNAME:
692 case XML_SCHEMAS_ID:
693 case XML_SCHEMAS_IDREF:
694 case XML_SCHEMAS_IDREFS:
695 case XML_SCHEMAS_ENTITY:
696 case XML_SCHEMAS_ENTITIES:
697 case XML_SCHEMAS_NOTATION:
698 case XML_SCHEMAS_ANYURI:
699 if (value->value.str != NULL)
700 xmlFree(value->value.str);
701 break;
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000702 case XML_SCHEMAS_QNAME:
703 if (value->value.qname.uri != NULL)
704 xmlFree(value->value.qname.uri);
705 if (value->value.qname.name != NULL)
706 xmlFree(value->value.qname.name);
707 break;
Daniel Veillard70bcb0e2003-08-08 14:00:28 +0000708 case XML_SCHEMAS_HEXBINARY:
709 if (value->value.hex.str != NULL)
710 xmlFree(value->value.hex.str);
711 break;
Daniel Veillard1ac24d32003-08-27 14:15:15 +0000712 case XML_SCHEMAS_BASE64BINARY:
713 if (value->value.base64.str != NULL)
714 xmlFree(value->value.base64.str);
715 break;
Daniel Veillardc4c21552003-03-29 10:53:38 +0000716 default:
717 break;
718 }
Daniel Veillard4255d502002-04-16 15:50:10 +0000719 xmlFree(value);
720}
721
722/**
723 * xmlSchemaGetPredefinedType:
724 * @name: the type name
725 * @ns: the URI of the namespace usually "http://www.w3.org/2001/XMLSchema"
726 *
727 * Lookup a type in the default XML Schemas type library
728 *
729 * Returns the type if found, NULL otherwise
730 */
731xmlSchemaTypePtr
732xmlSchemaGetPredefinedType(const xmlChar *name, const xmlChar *ns) {
733 if (xmlSchemaTypesInitialized == 0)
734 xmlSchemaInitTypes();
735 if (name == NULL)
736 return(NULL);
737 return((xmlSchemaTypePtr) xmlHashLookup2(xmlSchemaTypesBank, name, ns));
738}
Daniel Veillard070803b2002-05-03 07:29:38 +0000739
Daniel Veillard01fa6152004-06-29 17:04:39 +0000740/**
741 * xmlSchemaGetBuiltInListSimpleTypeItemType:
742 * @type: the built-in simple type.
743 *
Daniel Veillard6927b102004-10-27 17:29:04 +0000744 * Lookup function
745 *
Daniel Veillardc0826a72004-08-10 14:17:33 +0000746 * Returns the item type of @type as defined by the built-in datatype
747 * hierarchy of XML Schema Part 2: Datatypes, or NULL in case of an error.
Daniel Veillard01fa6152004-06-29 17:04:39 +0000748 */
749xmlSchemaTypePtr
750xmlSchemaGetBuiltInListSimpleTypeItemType(xmlSchemaTypePtr type)
751{
752 if (type->type != XML_SCHEMA_TYPE_BASIC)
753 return (NULL);
754 switch (type->builtInType) {
755 case XML_SCHEMAS_NMTOKENS:
756 return (xmlSchemaTypeNmtokenDef );
757 case XML_SCHEMAS_IDREFS:
758 return (xmlSchemaTypeIdrefDef);
759 case XML_SCHEMAS_ENTITIES:
760 return (xmlSchemaTypeEntityDef);
761 default:
762 return (NULL);
763 }
764}
765
Daniel Veillard070803b2002-05-03 07:29:38 +0000766/****************************************************************
767 * *
768 * Convenience macros and functions *
769 * *
770 ****************************************************************/
771
772#define IS_TZO_CHAR(c) \
773 ((c == 0) || (c == 'Z') || (c == '+') || (c == '-'))
774
775#define VALID_YEAR(yr) (yr != 0)
776#define VALID_MONTH(mon) ((mon >= 1) && (mon <= 12))
777/* VALID_DAY should only be used when month is unknown */
778#define VALID_DAY(day) ((day >= 1) && (day <= 31))
779#define VALID_HOUR(hr) ((hr >= 0) && (hr <= 23))
780#define VALID_MIN(min) ((min >= 0) && (min <= 59))
781#define VALID_SEC(sec) ((sec >= 0) && (sec < 60))
782#define VALID_TZO(tzo) ((tzo > -1440) && (tzo < 1440))
783#define IS_LEAP(y) \
784 (((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0))
785
Daniel Veillardebe25d42004-03-25 09:35:49 +0000786static const unsigned int daysInMonth[12] =
Daniel Veillard070803b2002-05-03 07:29:38 +0000787 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
Daniel Veillardebe25d42004-03-25 09:35:49 +0000788static const unsigned int daysInMonthLeap[12] =
Daniel Veillard070803b2002-05-03 07:29:38 +0000789 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
790
Daniel Veillard5a872412002-05-22 06:40:27 +0000791#define MAX_DAYINMONTH(yr,mon) \
792 (IS_LEAP(yr) ? daysInMonthLeap[mon - 1] : daysInMonth[mon - 1])
793
Daniel Veillard070803b2002-05-03 07:29:38 +0000794#define VALID_MDAY(dt) \
795 (IS_LEAP(dt->year) ? \
796 (dt->day <= daysInMonthLeap[dt->mon - 1]) : \
797 (dt->day <= daysInMonth[dt->mon - 1]))
798
799#define VALID_DATE(dt) \
800 (VALID_YEAR(dt->year) && VALID_MONTH(dt->mon) && VALID_MDAY(dt))
801
802#define VALID_TIME(dt) \
803 (VALID_HOUR(dt->hour) && VALID_MIN(dt->min) && \
804 VALID_SEC(dt->sec) && VALID_TZO(dt->tzo))
805
806#define VALID_DATETIME(dt) \
807 (VALID_DATE(dt) && VALID_TIME(dt))
808
809#define SECS_PER_MIN (60)
810#define SECS_PER_HOUR (60 * SECS_PER_MIN)
811#define SECS_PER_DAY (24 * SECS_PER_HOUR)
812
Daniel Veillard5a872412002-05-22 06:40:27 +0000813static const long dayInYearByMonth[12] =
814 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
815static const long dayInLeapYearByMonth[12] =
816 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 };
817
818#define DAY_IN_YEAR(day, month, year) \
819 ((IS_LEAP(year) ? \
820 dayInLeapYearByMonth[month - 1] : \
821 dayInYearByMonth[month - 1]) + day)
822
823#ifdef DEBUG
824#define DEBUG_DATE(dt) \
825 xmlGenericError(xmlGenericErrorContext, \
826 "type=%o %04ld-%02u-%02uT%02u:%02u:%03f", \
827 dt->type,dt->value.date.year,dt->value.date.mon, \
828 dt->value.date.day,dt->value.date.hour,dt->value.date.min, \
829 dt->value.date.sec); \
830 if (dt->value.date.tz_flag) \
831 if (dt->value.date.tzo != 0) \
832 xmlGenericError(xmlGenericErrorContext, \
833 "%+05d\n",dt->value.date.tzo); \
834 else \
835 xmlGenericError(xmlGenericErrorContext, "Z\n"); \
836 else \
837 xmlGenericError(xmlGenericErrorContext,"\n")
838#else
839#define DEBUG_DATE(dt)
840#endif
841
Daniel Veillard070803b2002-05-03 07:29:38 +0000842/**
843 * _xmlSchemaParseGYear:
844 * @dt: pointer to a date structure
845 * @str: pointer to the string to analyze
846 *
847 * Parses a xs:gYear without time zone and fills in the appropriate
848 * field of the @dt structure. @str is updated to point just after the
849 * xs:gYear. It is supposed that @dt->year is big enough to contain
850 * the year.
851 *
852 * Returns 0 or the error code
853 */
854static int
855_xmlSchemaParseGYear (xmlSchemaValDatePtr dt, const xmlChar **str) {
856 const xmlChar *cur = *str, *firstChar;
857 int isneg = 0, digcnt = 0;
858
859 if (((*cur < '0') || (*cur > '9')) &&
860 (*cur != '-') && (*cur != '+'))
861 return -1;
862
863 if (*cur == '-') {
864 isneg = 1;
865 cur++;
866 }
867
868 firstChar = cur;
869
870 while ((*cur >= '0') && (*cur <= '9')) {
871 dt->year = dt->year * 10 + (*cur - '0');
872 cur++;
873 digcnt++;
874 }
875
876 /* year must be at least 4 digits (CCYY); over 4
877 * digits cannot have a leading zero. */
878 if ((digcnt < 4) || ((digcnt > 4) && (*firstChar == '0')))
879 return 1;
880
881 if (isneg)
882 dt->year = - dt->year;
883
884 if (!VALID_YEAR(dt->year))
885 return 2;
886
887 *str = cur;
888 return 0;
889}
890
891/**
892 * PARSE_2_DIGITS:
893 * @num: the integer to fill in
894 * @cur: an #xmlChar *
895 * @invalid: an integer
896 *
897 * Parses a 2-digits integer and updates @num with the value. @cur is
898 * updated to point just after the integer.
899 * In case of error, @invalid is set to %TRUE, values of @num and
900 * @cur are undefined.
901 */
902#define PARSE_2_DIGITS(num, cur, invalid) \
903 if ((cur[0] < '0') || (cur[0] > '9') || \
904 (cur[1] < '0') || (cur[1] > '9')) \
905 invalid = 1; \
906 else \
907 num = (cur[0] - '0') * 10 + (cur[1] - '0'); \
908 cur += 2;
909
910/**
911 * PARSE_FLOAT:
912 * @num: the double to fill in
913 * @cur: an #xmlChar *
914 * @invalid: an integer
915 *
916 * Parses a float and updates @num with the value. @cur is
917 * updated to point just after the float. The float must have a
918 * 2-digits integer part and may or may not have a decimal part.
919 * In case of error, @invalid is set to %TRUE, values of @num and
920 * @cur are undefined.
921 */
922#define PARSE_FLOAT(num, cur, invalid) \
923 PARSE_2_DIGITS(num, cur, invalid); \
924 if (!invalid && (*cur == '.')) { \
925 double mult = 1; \
926 cur++; \
927 if ((*cur < '0') || (*cur > '9')) \
928 invalid = 1; \
929 while ((*cur >= '0') && (*cur <= '9')) { \
930 mult /= 10; \
931 num += (*cur - '0') * mult; \
932 cur++; \
933 } \
934 }
935
936/**
937 * _xmlSchemaParseGMonth:
938 * @dt: pointer to a date structure
939 * @str: pointer to the string to analyze
940 *
941 * Parses a xs:gMonth without time zone and fills in the appropriate
942 * field of the @dt structure. @str is updated to point just after the
943 * xs:gMonth.
944 *
945 * Returns 0 or the error code
946 */
947static int
948_xmlSchemaParseGMonth (xmlSchemaValDatePtr dt, const xmlChar **str) {
949 const xmlChar *cur = *str;
950 int ret = 0;
951
952 PARSE_2_DIGITS(dt->mon, cur, ret);
953 if (ret != 0)
954 return ret;
955
956 if (!VALID_MONTH(dt->mon))
957 return 2;
958
959 *str = cur;
960 return 0;
961}
962
963/**
964 * _xmlSchemaParseGDay:
965 * @dt: pointer to a date structure
966 * @str: pointer to the string to analyze
967 *
968 * Parses a xs:gDay without time zone and fills in the appropriate
969 * field of the @dt structure. @str is updated to point just after the
970 * xs:gDay.
971 *
972 * Returns 0 or the error code
973 */
974static int
975_xmlSchemaParseGDay (xmlSchemaValDatePtr dt, const xmlChar **str) {
976 const xmlChar *cur = *str;
977 int ret = 0;
978
979 PARSE_2_DIGITS(dt->day, cur, ret);
980 if (ret != 0)
981 return ret;
982
983 if (!VALID_DAY(dt->day))
984 return 2;
985
986 *str = cur;
987 return 0;
988}
989
990/**
991 * _xmlSchemaParseTime:
992 * @dt: pointer to a date structure
993 * @str: pointer to the string to analyze
994 *
995 * Parses a xs:time without time zone and fills in the appropriate
996 * fields of the @dt structure. @str is updated to point just after the
997 * xs:time.
998 * In case of error, values of @dt fields are undefined.
999 *
1000 * Returns 0 or the error code
1001 */
1002static int
1003_xmlSchemaParseTime (xmlSchemaValDatePtr dt, const xmlChar **str) {
1004 const xmlChar *cur = *str;
1005 unsigned int hour = 0; /* use temp var in case str is not xs:time */
1006 int ret = 0;
1007
1008 PARSE_2_DIGITS(hour, cur, ret);
1009 if (ret != 0)
1010 return ret;
1011
1012 if (*cur != ':')
1013 return 1;
1014 cur++;
1015
1016 /* the ':' insures this string is xs:time */
1017 dt->hour = hour;
1018
1019 PARSE_2_DIGITS(dt->min, cur, ret);
1020 if (ret != 0)
1021 return ret;
1022
1023 if (*cur != ':')
1024 return 1;
1025 cur++;
1026
1027 PARSE_FLOAT(dt->sec, cur, ret);
1028 if (ret != 0)
1029 return ret;
1030
1031 if (!VALID_TIME(dt))
1032 return 2;
1033
1034 *str = cur;
1035 return 0;
1036}
1037
1038/**
1039 * _xmlSchemaParseTimeZone:
1040 * @dt: pointer to a date structure
1041 * @str: pointer to the string to analyze
1042 *
1043 * Parses a time zone without time zone and fills in the appropriate
1044 * field of the @dt structure. @str is updated to point just after the
1045 * time zone.
1046 *
1047 * Returns 0 or the error code
1048 */
1049static int
1050_xmlSchemaParseTimeZone (xmlSchemaValDatePtr dt, const xmlChar **str) {
1051 const xmlChar *cur = *str;
1052 int ret = 0;
1053
1054 if (str == NULL)
1055 return -1;
1056
1057 switch (*cur) {
1058 case 0:
1059 dt->tz_flag = 0;
1060 dt->tzo = 0;
1061 break;
1062
1063 case 'Z':
1064 dt->tz_flag = 1;
1065 dt->tzo = 0;
1066 cur++;
1067 break;
1068
1069 case '+':
1070 case '-': {
1071 int isneg = 0, tmp = 0;
1072 isneg = (*cur == '-');
1073
1074 cur++;
1075
1076 PARSE_2_DIGITS(tmp, cur, ret);
1077 if (ret != 0)
1078 return ret;
1079 if (!VALID_HOUR(tmp))
1080 return 2;
1081
1082 if (*cur != ':')
1083 return 1;
1084 cur++;
1085
1086 dt->tzo = tmp * 60;
1087
1088 PARSE_2_DIGITS(tmp, cur, ret);
1089 if (ret != 0)
1090 return ret;
1091 if (!VALID_MIN(tmp))
1092 return 2;
1093
1094 dt->tzo += tmp;
1095 if (isneg)
1096 dt->tzo = - dt->tzo;
1097
1098 if (!VALID_TZO(dt->tzo))
1099 return 2;
1100
Daniel Veillard5a872412002-05-22 06:40:27 +00001101 dt->tz_flag = 1;
Daniel Veillard070803b2002-05-03 07:29:38 +00001102 break;
1103 }
1104 default:
1105 return 1;
1106 }
1107
1108 *str = cur;
1109 return 0;
1110}
1111
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001112/**
1113 * _xmlSchemaBase64Decode:
1114 * @ch: a character
1115 *
1116 * Converts a base64 encoded character to its base 64 value.
1117 *
1118 * Returns 0-63 (value), 64 (pad), or -1 (not recognized)
1119 */
1120static int
1121_xmlSchemaBase64Decode (const xmlChar ch) {
1122 if (('A' <= ch) && (ch <= 'Z')) return ch - 'A';
1123 if (('a' <= ch) && (ch <= 'z')) return ch - 'a' + 26;
1124 if (('0' <= ch) && (ch <= '9')) return ch - '0' + 52;
1125 if ('+' == ch) return 62;
1126 if ('/' == ch) return 63;
1127 if ('=' == ch) return 64;
1128 return -1;
1129}
1130
Daniel Veillard070803b2002-05-03 07:29:38 +00001131/****************************************************************
1132 * *
1133 * XML Schema Dates/Times Datatypes Handling *
1134 * *
1135 ****************************************************************/
1136
1137/**
1138 * PARSE_DIGITS:
1139 * @num: the integer to fill in
1140 * @cur: an #xmlChar *
1141 * @num_type: an integer flag
1142 *
1143 * Parses a digits integer and updates @num with the value. @cur is
1144 * updated to point just after the integer.
1145 * In case of error, @num_type is set to -1, values of @num and
1146 * @cur are undefined.
1147 */
1148#define PARSE_DIGITS(num, cur, num_type) \
1149 if ((*cur < '0') || (*cur > '9')) \
1150 num_type = -1; \
1151 else \
1152 while ((*cur >= '0') && (*cur <= '9')) { \
1153 num = num * 10 + (*cur - '0'); \
1154 cur++; \
1155 }
1156
1157/**
1158 * PARSE_NUM:
1159 * @num: the double to fill in
1160 * @cur: an #xmlChar *
1161 * @num_type: an integer flag
1162 *
1163 * Parses a float or integer and updates @num with the value. @cur is
1164 * updated to point just after the number. If the number is a float,
1165 * then it must have an integer part and a decimal part; @num_type will
1166 * be set to 1. If there is no decimal part, @num_type is set to zero.
1167 * In case of error, @num_type is set to -1, values of @num and
1168 * @cur are undefined.
1169 */
1170#define PARSE_NUM(num, cur, num_type) \
1171 num = 0; \
1172 PARSE_DIGITS(num, cur, num_type); \
1173 if (!num_type && (*cur == '.')) { \
1174 double mult = 1; \
1175 cur++; \
1176 if ((*cur < '0') || (*cur > '9')) \
1177 num_type = -1; \
1178 else \
1179 num_type = 1; \
1180 while ((*cur >= '0') && (*cur <= '9')) { \
1181 mult /= 10; \
1182 num += (*cur - '0') * mult; \
1183 cur++; \
1184 } \
1185 }
1186
1187/**
Daniel Veillard5a872412002-05-22 06:40:27 +00001188 * xmlSchemaValidateDates:
Daniel Veillard455cc072003-03-31 10:13:23 +00001189 * @type: the expected type or XML_SCHEMAS_UNKNOWN
Daniel Veillard070803b2002-05-03 07:29:38 +00001190 * @dateTime: string to analyze
1191 * @val: the return computed value
1192 *
1193 * Check that @dateTime conforms to the lexical space of one of the date types.
1194 * if true a value is computed and returned in @val.
1195 *
1196 * Returns 0 if this validates, a positive error code number otherwise
1197 * and -1 in case of internal or API error.
1198 */
1199static int
Daniel Veillard455cc072003-03-31 10:13:23 +00001200xmlSchemaValidateDates (xmlSchemaValType type,
Daniel Veillard118aed72002-09-24 14:13:13 +00001201 const xmlChar *dateTime, xmlSchemaValPtr *val) {
Daniel Veillard070803b2002-05-03 07:29:38 +00001202 xmlSchemaValPtr dt;
1203 int ret;
1204 const xmlChar *cur = dateTime;
1205
1206#define RETURN_TYPE_IF_VALID(t) \
1207 if (IS_TZO_CHAR(*cur)) { \
1208 ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur); \
1209 if (ret == 0) { \
1210 if (*cur != 0) \
1211 goto error; \
1212 dt->type = t; \
Daniel Veillard455cc072003-03-31 10:13:23 +00001213 goto done; \
Daniel Veillard070803b2002-05-03 07:29:38 +00001214 } \
1215 }
1216
1217 if (dateTime == NULL)
1218 return -1;
1219
1220 if ((*cur != '-') && (*cur < '0') && (*cur > '9'))
1221 return 1;
1222
1223 dt = xmlSchemaNewValue(XML_SCHEMAS_UNKNOWN);
1224 if (dt == NULL)
1225 return -1;
1226
1227 if ((cur[0] == '-') && (cur[1] == '-')) {
1228 /*
1229 * It's an incomplete date (xs:gMonthDay, xs:gMonth or
1230 * xs:gDay)
1231 */
1232 cur += 2;
1233
1234 /* is it an xs:gDay? */
1235 if (*cur == '-') {
Daniel Veillard455cc072003-03-31 10:13:23 +00001236 if (type == XML_SCHEMAS_GMONTH)
1237 goto error;
Daniel Veillard070803b2002-05-03 07:29:38 +00001238 ++cur;
1239 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
1240 if (ret != 0)
1241 goto error;
1242
1243 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GDAY);
1244
1245 goto error;
1246 }
1247
1248 /*
1249 * it should be an xs:gMonthDay or xs:gMonth
1250 */
1251 ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
1252 if (ret != 0)
1253 goto error;
1254
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001255 /*
1256 * a '-' char could indicate this type is xs:gMonthDay or
1257 * a negative time zone offset. Check for xs:gMonthDay first.
1258 * Also the first three char's of a negative tzo (-MM:SS) can
1259 * appear to be a valid day; so even if the day portion
1260 * of the xs:gMonthDay verifies, we must insure it was not
1261 * a tzo.
1262 */
1263 if (*cur == '-') {
1264 const xmlChar *rewnd = cur;
1265 cur++;
Daniel Veillard070803b2002-05-03 07:29:38 +00001266
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001267 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
1268 if ((ret == 0) && ((*cur == 0) || (*cur != ':'))) {
1269
1270 /*
1271 * we can use the VALID_MDAY macro to validate the month
1272 * and day because the leap year test will flag year zero
1273 * as a leap year (even though zero is an invalid year).
1274 */
1275 if (VALID_MDAY((&(dt->value.date)))) {
1276
1277 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTHDAY);
1278
1279 goto error;
1280 }
1281 }
1282
1283 /*
1284 * not xs:gMonthDay so rewind and check if just xs:gMonth
1285 * with an optional time zone.
1286 */
1287 cur = rewnd;
1288 }
1289
1290 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTH);
Daniel Veillard070803b2002-05-03 07:29:38 +00001291
1292 goto error;
1293 }
1294
1295 /*
1296 * It's a right-truncated date or an xs:time.
1297 * Try to parse an xs:time then fallback on right-truncated dates.
1298 */
1299 if ((*cur >= '0') && (*cur <= '9')) {
1300 ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
1301 if (ret == 0) {
1302 /* it's an xs:time */
1303 RETURN_TYPE_IF_VALID(XML_SCHEMAS_TIME);
1304 }
1305 }
1306
1307 /* fallback on date parsing */
1308 cur = dateTime;
1309
1310 ret = _xmlSchemaParseGYear(&(dt->value.date), &cur);
1311 if (ret != 0)
1312 goto error;
1313
1314 /* is it an xs:gYear? */
1315 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEAR);
1316
1317 if (*cur != '-')
1318 goto error;
1319 cur++;
1320
1321 ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
1322 if (ret != 0)
1323 goto error;
1324
1325 /* is it an xs:gYearMonth? */
1326 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEARMONTH);
1327
1328 if (*cur != '-')
1329 goto error;
1330 cur++;
1331
1332 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
1333 if ((ret != 0) || !VALID_DATE((&(dt->value.date))))
1334 goto error;
1335
1336 /* is it an xs:date? */
1337 RETURN_TYPE_IF_VALID(XML_SCHEMAS_DATE);
1338
1339 if (*cur != 'T')
1340 goto error;
1341 cur++;
1342
1343 /* it should be an xs:dateTime */
1344 ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
1345 if (ret != 0)
1346 goto error;
1347
1348 ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur);
1349 if ((ret != 0) || (*cur != 0) || !VALID_DATETIME((&(dt->value.date))))
1350 goto error;
1351
Daniel Veillard455cc072003-03-31 10:13:23 +00001352
Daniel Veillard070803b2002-05-03 07:29:38 +00001353 dt->type = XML_SCHEMAS_DATETIME;
1354
Daniel Veillard455cc072003-03-31 10:13:23 +00001355done:
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001356#if 1
1357 if ((type != XML_SCHEMAS_UNKNOWN) && (type != dt->type))
1358 goto error;
1359#else
1360 /*
1361 * insure the parsed type is equal to or less significant (right
1362 * truncated) than the desired type.
1363 */
1364 if ((type != XML_SCHEMAS_UNKNOWN) && (type != dt->type)) {
1365
1366 /* time only matches time */
1367 if ((type == XML_SCHEMAS_TIME) && (dt->type == XML_SCHEMAS_TIME))
1368 goto error;
1369
1370 if ((type == XML_SCHEMAS_DATETIME) &&
1371 ((dt->type != XML_SCHEMAS_DATE) ||
1372 (dt->type != XML_SCHEMAS_GYEARMONTH) ||
1373 (dt->type != XML_SCHEMAS_GYEAR)))
1374 goto error;
1375
1376 if ((type == XML_SCHEMAS_DATE) &&
1377 ((dt->type != XML_SCHEMAS_GYEAR) ||
1378 (dt->type != XML_SCHEMAS_GYEARMONTH)))
1379 goto error;
1380
1381 if ((type == XML_SCHEMAS_GYEARMONTH) && (dt->type != XML_SCHEMAS_GYEAR))
1382 goto error;
1383
1384 if ((type == XML_SCHEMAS_GMONTHDAY) && (dt->type != XML_SCHEMAS_GMONTH))
1385 goto error;
1386 }
Daniel Veillard455cc072003-03-31 10:13:23 +00001387#endif
1388
Daniel Veillard070803b2002-05-03 07:29:38 +00001389 if (val != NULL)
1390 *val = dt;
Daniel Veillard80b19092003-03-28 13:29:53 +00001391 else
1392 xmlSchemaFreeValue(dt);
Daniel Veillard070803b2002-05-03 07:29:38 +00001393
1394 return 0;
1395
1396error:
1397 if (dt != NULL)
1398 xmlSchemaFreeValue(dt);
1399 return 1;
1400}
1401
1402/**
Daniel Veillard5a872412002-05-22 06:40:27 +00001403 * xmlSchemaValidateDuration:
Daniel Veillard070803b2002-05-03 07:29:38 +00001404 * @type: the predefined type
1405 * @duration: string to analyze
1406 * @val: the return computed value
1407 *
1408 * Check that @duration conforms to the lexical space of the duration type.
1409 * if true a value is computed and returned in @val.
1410 *
1411 * Returns 0 if this validates, a positive error code number otherwise
1412 * and -1 in case of internal or API error.
1413 */
1414static int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00001415xmlSchemaValidateDuration (xmlSchemaTypePtr type ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +00001416 const xmlChar *duration, xmlSchemaValPtr *val) {
Daniel Veillard070803b2002-05-03 07:29:38 +00001417 const xmlChar *cur = duration;
1418 xmlSchemaValPtr dur;
1419 int isneg = 0;
1420 unsigned int seq = 0;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001421 double num;
1422 int num_type = 0; /* -1 = invalid, 0 = int, 1 = floating */
1423 const xmlChar desig[] = {'Y', 'M', 'D', 'H', 'M', 'S'};
1424 const double multi[] = { 0.0, 0.0, 86400.0, 3600.0, 60.0, 1.0, 0.0};
Daniel Veillard070803b2002-05-03 07:29:38 +00001425
1426 if (duration == NULL)
1427 return -1;
1428
1429 if (*cur == '-') {
1430 isneg = 1;
1431 cur++;
1432 }
1433
1434 /* duration must start with 'P' (after sign) */
1435 if (*cur++ != 'P')
1436 return 1;
1437
Daniel Veillard80b19092003-03-28 13:29:53 +00001438 if (*cur == 0)
1439 return 1;
1440
Daniel Veillard070803b2002-05-03 07:29:38 +00001441 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
1442 if (dur == NULL)
1443 return -1;
1444
1445 while (*cur != 0) {
Daniel Veillard070803b2002-05-03 07:29:38 +00001446
1447 /* input string should be empty or invalid date/time item */
1448 if (seq >= sizeof(desig))
1449 goto error;
1450
1451 /* T designator must be present for time items */
1452 if (*cur == 'T') {
1453 if (seq <= 3) {
1454 seq = 3;
1455 cur++;
1456 } else
1457 return 1;
1458 } else if (seq == 3)
1459 goto error;
1460
1461 /* parse the number portion of the item */
1462 PARSE_NUM(num, cur, num_type);
1463
1464 if ((num_type == -1) || (*cur == 0))
1465 goto error;
1466
1467 /* update duration based on item type */
1468 while (seq < sizeof(desig)) {
1469 if (*cur == desig[seq]) {
1470
1471 /* verify numeric type; only seconds can be float */
1472 if ((num_type != 0) && (seq < (sizeof(desig)-1)))
1473 goto error;
1474
1475 switch (seq) {
1476 case 0:
1477 dur->value.dur.mon = (long)num * 12;
1478 break;
1479 case 1:
1480 dur->value.dur.mon += (long)num;
1481 break;
1482 default:
1483 /* convert to seconds using multiplier */
1484 dur->value.dur.sec += num * multi[seq];
1485 seq++;
1486 break;
1487 }
1488
1489 break; /* exit loop */
1490 }
1491 /* no date designators found? */
1492 if (++seq == 3)
1493 goto error;
1494 }
1495 cur++;
1496 }
1497
1498 if (isneg) {
1499 dur->value.dur.mon = -dur->value.dur.mon;
1500 dur->value.dur.day = -dur->value.dur.day;
1501 dur->value.dur.sec = -dur->value.dur.sec;
1502 }
1503
1504 if (val != NULL)
1505 *val = dur;
Daniel Veillard80b19092003-03-28 13:29:53 +00001506 else
1507 xmlSchemaFreeValue(dur);
Daniel Veillard070803b2002-05-03 07:29:38 +00001508
1509 return 0;
1510
1511error:
1512 if (dur != NULL)
1513 xmlSchemaFreeValue(dur);
1514 return 1;
1515}
1516
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001517/**
1518 * xmlSchemaStrip:
1519 * @value: a value
1520 *
1521 * Removes the leading and ending spaces of a string
1522 *
1523 * Returns the new string or NULL if no change was required.
1524 */
1525static xmlChar *
1526xmlSchemaStrip(const xmlChar *value) {
1527 const xmlChar *start = value, *end, *f;
1528
1529 if (value == NULL) return(NULL);
William M. Brack76e95df2003-10-18 16:20:14 +00001530 while ((*start != 0) && (IS_BLANK_CH(*start))) start++;
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001531 end = start;
1532 while (*end != 0) end++;
1533 f = end;
1534 end--;
William M. Brack76e95df2003-10-18 16:20:14 +00001535 while ((end > start) && (IS_BLANK_CH(*end))) end--;
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001536 end++;
1537 if ((start == value) && (f == end)) return(NULL);
1538 return(xmlStrndup(start, end - start));
1539}
Daniel Veillard96a4b252003-02-06 08:22:32 +00001540
1541/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001542 * xmlSchemaCollapseString:
1543 * @value: a value
1544 *
1545 * Removes and normalize white spaces in the string
1546 *
1547 * Returns the new string or NULL if no change was required.
1548 */
Daniel Veillard01fa6152004-06-29 17:04:39 +00001549xmlChar *
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001550xmlSchemaCollapseString(const xmlChar *value) {
1551 const xmlChar *start = value, *end, *f;
1552 xmlChar *g;
1553 int col = 0;
1554
1555 if (value == NULL) return(NULL);
William M. Brack76e95df2003-10-18 16:20:14 +00001556 while ((*start != 0) && (IS_BLANK_CH(*start))) start++;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001557 end = start;
1558 while (*end != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00001559 if ((*end == ' ') && (IS_BLANK_CH(end[1]))) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001560 col = end - start;
1561 break;
1562 } else if ((*end == 0xa) || (*end == 0x9) || (*end == 0xd)) {
1563 col = end - start;
1564 break;
1565 }
1566 end++;
1567 }
1568 if (col == 0) {
1569 f = end;
1570 end--;
William M. Brack76e95df2003-10-18 16:20:14 +00001571 while ((end > start) && (IS_BLANK_CH(*end))) end--;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001572 end++;
1573 if ((start == value) && (f == end)) return(NULL);
1574 return(xmlStrndup(start, end - start));
1575 }
1576 start = xmlStrdup(start);
1577 if (start == NULL) return(NULL);
1578 g = (xmlChar *) (start + col);
1579 end = g;
1580 while (*end != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00001581 if (IS_BLANK_CH(*end)) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001582 end++;
William M. Brack76e95df2003-10-18 16:20:14 +00001583 while (IS_BLANK_CH(*end)) end++;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001584 if (*end != 0)
1585 *g++ = ' ';
1586 } else
1587 *g++ = *end++;
1588 }
1589 *g = 0;
1590 return((xmlChar *) start);
1591}
1592
1593/**
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001594 * xmlSchemaValAtomicListNode:
1595 * @type: the predefined atomic type for a token in the list
1596 * @value: the list value to check
1597 * @ret: the return computed value
1598 * @node: the node containing the value
1599 *
1600 * Check that a value conforms to the lexical space of the predefined
1601 * list type. if true a value is computed and returned in @ret.
1602 *
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001603 * Returns the number of items if this validates, a negative error code
1604 * number otherwise
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001605 */
1606static int
1607xmlSchemaValAtomicListNode(xmlSchemaTypePtr type, const xmlChar *value,
1608 xmlSchemaValPtr *ret, xmlNodePtr node) {
1609 xmlChar *val, *cur, *endval;
1610 int nb_values = 0;
Daniel Veillard580ced82003-03-21 21:22:48 +00001611 int tmp = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001612
1613 if (value == NULL) {
1614 return(-1);
1615 }
1616 val = xmlStrdup(value);
1617 if (val == NULL) {
1618 return(-1);
1619 }
1620 cur = val;
1621 /*
1622 * Split the list
1623 */
William M. Brack76e95df2003-10-18 16:20:14 +00001624 while (IS_BLANK_CH(*cur)) *cur++ = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001625 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00001626 if (IS_BLANK_CH(*cur)) {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001627 *cur = 0;
1628 cur++;
William M. Brack76e95df2003-10-18 16:20:14 +00001629 while (IS_BLANK_CH(*cur)) *cur++ = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001630 } else {
1631 nb_values++;
1632 cur++;
William M. Brack76e95df2003-10-18 16:20:14 +00001633 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001634 }
1635 }
1636 if (nb_values == 0) {
1637 if (ret != NULL) {
1638 TODO
1639 }
1640 xmlFree(val);
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001641 return(nb_values);
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001642 }
1643 endval = cur;
1644 cur = val;
1645 while ((*cur == 0) && (cur != endval)) cur++;
1646 while (cur != endval) {
1647 tmp = xmlSchemaValPredefTypeNode(type, cur, NULL, node);
1648 if (tmp != 0)
1649 break;
1650 while (*cur != 0) cur++;
1651 while ((*cur == 0) && (cur != endval)) cur++;
1652 }
1653 xmlFree(val);
1654 if (ret != NULL) {
1655 TODO
1656 }
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001657 if (tmp == 0)
1658 return(nb_values);
1659 return(-1);
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001660}
1661
1662/**
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001663 * xmlSchemaParseUInt:
1664 * @str: pointer to the string R/W
1665 * @llo: pointer to the low result
1666 * @lmi: pointer to the mid result
1667 * @lhi: pointer to the high result
1668 *
1669 * Parse an unsigned long into 3 fields.
1670 *
1671 * Returns the number of chars parsed or -1 if overflow of the capacity
1672 */
1673static int
1674xmlSchemaParseUInt(const xmlChar **str, unsigned long *llo,
1675 unsigned long *lmi, unsigned long *lhi) {
1676 unsigned long lo = 0, mi = 0, hi = 0;
1677 const xmlChar *tmp, *cur = *str;
1678 int ret = 0, i = 0;
1679
1680 while (*cur == '0') {
1681 ret++;
1682 cur++;
1683 }
1684 tmp = cur;
1685 while ((*tmp != 0) && (*tmp >= '0') && (*tmp <= '9')) {
1686 i++;tmp++;ret++;
1687 }
1688 if (i > 24) {
1689 *str = tmp;
1690 return(-1);
1691 }
1692 while (i > 16) {
1693 hi = hi * 10 + (*cur++ - '0');
1694 i--;
1695 }
1696 while (i > 8) {
1697 mi = mi * 10 + (*cur++ - '0');
1698 i--;
1699 }
1700 while (i > 0) {
1701 lo = lo * 10 + (*cur++ - '0');
1702 i--;
1703 }
1704
1705 *str = cur;
1706 *llo = lo;
1707 *lmi = mi;
1708 *lhi = hi;
1709 return(ret);
1710}
1711
1712/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001713 * xmlSchemaValAtomicType:
1714 * @type: the predefined type
1715 * @value: the value to check
1716 * @val: the return computed value
1717 * @node: the node containing the value
1718 * flags: flags to control the vlidation
1719 *
1720 * Check that a value conforms to the lexical space of the atomic type.
1721 * if true a value is computed and returned in @val.
Daniel Veillard01fa6152004-06-29 17:04:39 +00001722 * This checks the value space for list types as well (IDREFS, NMTOKENS).
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001723 *
1724 * Returns 0 if this validates, a positive error code number otherwise
1725 * and -1 in case of internal or API error.
1726 */
1727static int
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001728xmlSchemaValAtomicType(xmlSchemaTypePtr type, const xmlChar * value,
1729 xmlSchemaValPtr * val, xmlNodePtr node, int flags)
1730{
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001731 xmlSchemaValPtr v;
1732 xmlChar *norm = NULL;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001733 int ret = 0;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001734
1735 if (xmlSchemaTypesInitialized == 0)
Daniel Veillard01fa6152004-06-29 17:04:39 +00001736 xmlSchemaInitTypes();
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001737 if (type == NULL)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001738 return (-1);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001739
Daniel Veillardeebd6332004-08-26 10:30:44 +00001740 /*
1741 * validating a non existant text node is similar to validating
1742 * an empty one.
1743 */
1744 if (value == NULL)
1745 value = BAD_CAST "";
1746
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001747 if (val != NULL)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001748 *val = NULL;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001749 if ((flags == 0) && (value != NULL)) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00001750 if ((type->builtInType != XML_SCHEMAS_STRING) &&
1751 (type->builtInType != XML_SCHEMAS_NORMSTRING)) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001752 norm = xmlSchemaCollapseString(value);
1753 if (norm != NULL)
1754 value = norm;
1755 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001756 }
1757
Daniel Veillard01fa6152004-06-29 17:04:39 +00001758 switch (type->builtInType) {
William M. Brack2f2a6632004-08-20 23:09:47 +00001759 case XML_SCHEMAS_UNKNOWN:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001760 goto error;
William M. Brack2f2a6632004-08-20 23:09:47 +00001761 case XML_SCHEMAS_ANYTYPE:
1762 case XML_SCHEMAS_ANYSIMPLETYPE:
1763 goto return0;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001764 case XML_SCHEMAS_STRING:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001765 goto return0;
Daniel Veillard1516d5b2004-01-22 07:27:45 +00001766 case XML_SCHEMAS_NORMSTRING:{
1767 const xmlChar *cur = value;
1768
1769 while (*cur != 0) {
1770 if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) {
1771 goto return1;
1772 } else {
1773 cur++;
1774 }
1775 }
1776 if (val != NULL) {
1777 v = xmlSchemaNewValue(XML_SCHEMAS_NORMSTRING);
1778 if (v != NULL) {
1779 v->value.str = xmlStrdup(value);
1780 *val = v;
1781 } else {
1782 goto error;
1783 }
1784 }
1785 goto return0;
1786 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001787 case XML_SCHEMAS_DECIMAL:{
1788 const xmlChar *cur = value, *tmp;
1789 unsigned int frac = 0, len, neg = 0;
1790 unsigned long base = 0;
1791
1792 if (cur == NULL)
1793 goto return1;
1794 if (*cur == '+')
1795 cur++;
1796 else if (*cur == '-') {
1797 neg = 1;
1798 cur++;
1799 }
1800 tmp = cur;
1801 while ((*cur >= '0') && (*cur <= '9')) {
1802 base = base * 10 + (*cur - '0');
1803 cur++;
1804 }
1805 len = cur - tmp;
1806 if (*cur == '.') {
1807 cur++;
1808 tmp = cur;
1809 while ((*cur >= '0') && (*cur <= '9')) {
1810 base = base * 10 + (*cur - '0');
1811 cur++;
1812 }
1813 frac = cur - tmp;
1814 }
1815 if (*cur != 0)
1816 goto return1;
1817 if (val != NULL) {
1818 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
1819 if (v != NULL) {
1820 v->value.decimal.lo = base;
1821 v->value.decimal.sign = neg;
1822 v->value.decimal.frac = frac;
1823 v->value.decimal.total = frac + len;
1824 *val = v;
1825 }
1826 }
1827 goto return0;
1828 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001829 case XML_SCHEMAS_TIME:
1830 case XML_SCHEMAS_GDAY:
1831 case XML_SCHEMAS_GMONTH:
1832 case XML_SCHEMAS_GMONTHDAY:
1833 case XML_SCHEMAS_GYEAR:
1834 case XML_SCHEMAS_GYEARMONTH:
1835 case XML_SCHEMAS_DATE:
1836 case XML_SCHEMAS_DATETIME:
Daniel Veillard01fa6152004-06-29 17:04:39 +00001837 ret = xmlSchemaValidateDates(type->builtInType, value, val);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001838 break;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001839 case XML_SCHEMAS_DURATION:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001840 ret = xmlSchemaValidateDuration(type, value, val);
1841 break;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001842 case XML_SCHEMAS_FLOAT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001843 case XML_SCHEMAS_DOUBLE:{
1844 const xmlChar *cur = value;
1845 int neg = 0;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001846
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001847 if (cur == NULL)
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00001848 goto return1;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001849 if ((cur[0] == 'N') && (cur[1] == 'a') && (cur[2] == 'N')) {
1850 cur += 3;
1851 if (*cur != 0)
1852 goto return1;
1853 if (val != NULL) {
1854 if (type == xmlSchemaTypeFloatDef) {
1855 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1856 if (v != NULL) {
1857 v->value.f = (float) xmlXPathNAN;
1858 } else {
1859 xmlSchemaFreeValue(v);
1860 goto error;
1861 }
1862 } else {
1863 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1864 if (v != NULL) {
1865 v->value.d = xmlXPathNAN;
1866 } else {
1867 xmlSchemaFreeValue(v);
1868 goto error;
1869 }
1870 }
1871 *val = v;
1872 }
1873 goto return0;
1874 }
1875 if (*cur == '-') {
1876 neg = 1;
1877 cur++;
1878 }
1879 if ((cur[0] == 'I') && (cur[1] == 'N') && (cur[2] == 'F')) {
1880 cur += 3;
1881 if (*cur != 0)
1882 goto return1;
1883 if (val != NULL) {
1884 if (type == xmlSchemaTypeFloatDef) {
1885 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1886 if (v != NULL) {
1887 if (neg)
1888 v->value.f = (float) xmlXPathNINF;
1889 else
1890 v->value.f = (float) xmlXPathPINF;
1891 } else {
1892 xmlSchemaFreeValue(v);
1893 goto error;
1894 }
1895 } else {
1896 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1897 if (v != NULL) {
1898 if (neg)
1899 v->value.d = xmlXPathNINF;
1900 else
1901 v->value.d = xmlXPathPINF;
1902 } else {
1903 xmlSchemaFreeValue(v);
1904 goto error;
1905 }
1906 }
1907 *val = v;
1908 }
1909 goto return0;
1910 }
1911 if ((neg == 0) && (*cur == '+'))
1912 cur++;
1913 if ((cur[0] == 0) || (cur[0] == '+') || (cur[0] == '-'))
1914 goto return1;
1915 while ((*cur >= '0') && (*cur <= '9')) {
1916 cur++;
1917 }
1918 if (*cur == '.') {
1919 cur++;
1920 while ((*cur >= '0') && (*cur <= '9'))
1921 cur++;
1922 }
1923 if ((*cur == 'e') || (*cur == 'E')) {
1924 cur++;
1925 if ((*cur == '-') || (*cur == '+'))
1926 cur++;
1927 while ((*cur >= '0') && (*cur <= '9'))
1928 cur++;
1929 }
1930 if (*cur != 0)
1931 goto return1;
1932 if (val != NULL) {
1933 if (type == xmlSchemaTypeFloatDef) {
1934 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1935 if (v != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001936 if (sscanf((const char *) value, "%f",
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001937 &(v->value.f)) == 1) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00001938 *val = v;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001939 } else {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001940 xmlSchemaFreeValue(v);
1941 goto return1;
1942 }
1943 } else {
1944 goto error;
1945 }
1946 } else {
1947 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1948 if (v != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001949 if (sscanf((const char *) value, "%lf",
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001950 &(v->value.d)) == 1) {
1951 *val = v;
1952 } else {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001953 xmlSchemaFreeValue(v);
1954 goto return1;
1955 }
1956 } else {
1957 goto error;
1958 }
1959 }
1960 }
1961 goto return0;
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00001962 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001963 case XML_SCHEMAS_BOOLEAN:{
1964 const xmlChar *cur = value;
1965
1966 if ((cur[0] == '0') && (cur[1] == 0))
1967 ret = 0;
1968 else if ((cur[0] == '1') && (cur[1] == 0))
1969 ret = 1;
1970 else if ((cur[0] == 't') && (cur[1] == 'r')
1971 && (cur[2] == 'u') && (cur[3] == 'e')
1972 && (cur[4] == 0))
1973 ret = 1;
1974 else if ((cur[0] == 'f') && (cur[1] == 'a')
1975 && (cur[2] == 'l') && (cur[3] == 's')
1976 && (cur[4] == 'e') && (cur[5] == 0))
1977 ret = 0;
1978 else
1979 goto return1;
1980 if (val != NULL) {
1981 v = xmlSchemaNewValue(XML_SCHEMAS_BOOLEAN);
1982 if (v != NULL) {
1983 v->value.b = ret;
1984 *val = v;
1985 } else {
1986 goto error;
1987 }
1988 }
1989 goto return0;
1990 }
1991 case XML_SCHEMAS_TOKEN:{
1992 const xmlChar *cur = value;
1993
William M. Brack76e95df2003-10-18 16:20:14 +00001994 if (IS_BLANK_CH(*cur))
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001995 goto return1;
1996
1997 while (*cur != 0) {
1998 if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) {
1999 goto return1;
2000 } else if (*cur == ' ') {
2001 cur++;
2002 if (*cur == 0)
2003 goto return1;
2004 if (*cur == ' ')
2005 goto return1;
2006 } else {
2007 cur++;
2008 }
2009 }
2010 if (val != NULL) {
2011 v = xmlSchemaNewValue(XML_SCHEMAS_TOKEN);
2012 if (v != NULL) {
2013 v->value.str = xmlStrdup(value);
2014 *val = v;
2015 } else {
2016 goto error;
2017 }
2018 }
2019 goto return0;
2020 }
2021 case XML_SCHEMAS_LANGUAGE:
2022 if (xmlCheckLanguageID(value) == 1) {
2023 if (val != NULL) {
2024 v = xmlSchemaNewValue(XML_SCHEMAS_LANGUAGE);
2025 if (v != NULL) {
2026 v->value.str = xmlStrdup(value);
2027 *val = v;
2028 } else {
2029 goto error;
2030 }
2031 }
2032 goto return0;
2033 }
2034 goto return1;
2035 case XML_SCHEMAS_NMTOKEN:
2036 if (xmlValidateNMToken(value, 1) == 0) {
2037 if (val != NULL) {
2038 v = xmlSchemaNewValue(XML_SCHEMAS_NMTOKEN);
2039 if (v != NULL) {
2040 v->value.str = xmlStrdup(value);
2041 *val = v;
2042 } else {
2043 goto error;
2044 }
2045 }
2046 goto return0;
2047 }
2048 goto return1;
2049 case XML_SCHEMAS_NMTOKENS:
2050 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeNmtokenDef,
2051 value, val, node);
2052 if (ret > 0)
2053 ret = 0;
2054 else
2055 ret = 1;
2056 goto done;
2057 case XML_SCHEMAS_NAME:
2058 ret = xmlValidateName(value, 1);
2059 if ((ret == 0) && (val != NULL)) {
2060 TODO;
2061 }
2062 goto done;
2063 case XML_SCHEMAS_QNAME:{
2064 xmlChar *uri = NULL;
2065 xmlChar *local = NULL;
2066
2067 ret = xmlValidateQName(value, 1);
2068 if ((ret == 0) && (node != NULL)) {
2069 xmlChar *prefix;
2070
2071 local = xmlSplitQName2(value, &prefix);
2072 if (prefix != NULL) {
2073 xmlNsPtr ns;
2074
2075 ns = xmlSearchNs(node->doc, node, prefix);
2076 if (ns == NULL)
2077 ret = 1;
2078 else if (val != NULL)
2079 uri = xmlStrdup(ns->href);
2080 }
2081 if ((local != NULL) && ((val == NULL) || (ret != 0)))
2082 xmlFree(local);
2083 if (prefix != NULL)
2084 xmlFree(prefix);
2085 }
2086 if ((ret == 0) && (val != NULL)) {
2087 v = xmlSchemaNewValue(XML_SCHEMAS_QNAME);
2088 if (v != NULL) {
2089 if (local != NULL)
2090 v->value.qname.name = local;
2091 else
2092 v->value.qname.name = xmlStrdup(value);
2093 if (uri != NULL)
2094 v->value.qname.uri = uri;
2095
2096 *val = v;
2097 } else {
2098 if (local != NULL)
2099 xmlFree(local);
2100 if (uri != NULL)
2101 xmlFree(uri);
2102 goto error;
2103 }
2104 }
2105 goto done;
2106 }
2107 case XML_SCHEMAS_NCNAME:
2108 ret = xmlValidateNCName(value, 1);
2109 if ((ret == 0) && (val != NULL)) {
2110 v = xmlSchemaNewValue(XML_SCHEMAS_NCNAME);
2111 if (v != NULL) {
2112 v->value.str = xmlStrdup(value);
2113 *val = v;
2114 } else {
2115 goto error;
2116 }
2117 }
2118 goto done;
2119 case XML_SCHEMAS_ID:
2120 ret = xmlValidateNCName(value, 1);
2121 if ((ret == 0) && (val != NULL)) {
2122 v = xmlSchemaNewValue(XML_SCHEMAS_ID);
2123 if (v != NULL) {
2124 v->value.str = xmlStrdup(value);
2125 *val = v;
2126 } else {
2127 goto error;
2128 }
2129 }
2130 if ((ret == 0) && (node != NULL) &&
2131 (node->type == XML_ATTRIBUTE_NODE)) {
2132 xmlAttrPtr attr = (xmlAttrPtr) node;
2133
2134 /*
2135 * NOTE: the IDness might have already be declared in the DTD
2136 */
2137 if (attr->atype != XML_ATTRIBUTE_ID) {
2138 xmlIDPtr res;
2139 xmlChar *strip;
2140
2141 strip = xmlSchemaStrip(value);
2142 if (strip != NULL) {
2143 res = xmlAddID(NULL, node->doc, strip, attr);
2144 xmlFree(strip);
2145 } else
2146 res = xmlAddID(NULL, node->doc, value, attr);
2147 if (res == NULL) {
2148 ret = 2;
2149 } else {
2150 attr->atype = XML_ATTRIBUTE_ID;
2151 }
2152 }
2153 }
2154 goto done;
2155 case XML_SCHEMAS_IDREF:
2156 ret = xmlValidateNCName(value, 1);
2157 if ((ret == 0) && (val != NULL)) {
2158 TODO;
2159 }
2160 if ((ret == 0) && (node != NULL) &&
2161 (node->type == XML_ATTRIBUTE_NODE)) {
2162 xmlAttrPtr attr = (xmlAttrPtr) node;
2163 xmlChar *strip;
2164
2165 strip = xmlSchemaStrip(value);
2166 if (strip != NULL) {
2167 xmlAddRef(NULL, node->doc, strip, attr);
2168 xmlFree(strip);
2169 } else
2170 xmlAddRef(NULL, node->doc, value, attr);
2171 attr->atype = XML_ATTRIBUTE_IDREF;
2172 }
2173 goto done;
2174 case XML_SCHEMAS_IDREFS:
2175 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeIdrefDef,
2176 value, val, node);
2177 if (ret < 0)
2178 ret = 2;
2179 else
2180 ret = 0;
2181 if ((ret == 0) && (node != NULL) &&
2182 (node->type == XML_ATTRIBUTE_NODE)) {
2183 xmlAttrPtr attr = (xmlAttrPtr) node;
2184
2185 attr->atype = XML_ATTRIBUTE_IDREFS;
2186 }
2187 goto done;
2188 case XML_SCHEMAS_ENTITY:{
2189 xmlChar *strip;
2190
2191 ret = xmlValidateNCName(value, 1);
2192 if ((node == NULL) || (node->doc == NULL))
2193 ret = 3;
2194 if (ret == 0) {
2195 xmlEntityPtr ent;
2196
2197 strip = xmlSchemaStrip(value);
2198 if (strip != NULL) {
2199 ent = xmlGetDocEntity(node->doc, strip);
2200 xmlFree(strip);
2201 } else {
2202 ent = xmlGetDocEntity(node->doc, value);
2203 }
2204 if ((ent == NULL) ||
2205 (ent->etype !=
2206 XML_EXTERNAL_GENERAL_UNPARSED_ENTITY))
2207 ret = 4;
2208 }
2209 if ((ret == 0) && (val != NULL)) {
2210 TODO;
2211 }
2212 if ((ret == 0) && (node != NULL) &&
2213 (node->type == XML_ATTRIBUTE_NODE)) {
2214 xmlAttrPtr attr = (xmlAttrPtr) node;
2215
2216 attr->atype = XML_ATTRIBUTE_ENTITY;
2217 }
2218 goto done;
2219 }
2220 case XML_SCHEMAS_ENTITIES:
2221 if ((node == NULL) || (node->doc == NULL))
2222 goto return3;
2223 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeEntityDef,
2224 value, val, node);
2225 if (ret <= 0)
2226 ret = 1;
2227 else
2228 ret = 0;
2229 if ((ret == 0) && (node != NULL) &&
2230 (node->type == XML_ATTRIBUTE_NODE)) {
2231 xmlAttrPtr attr = (xmlAttrPtr) node;
2232
2233 attr->atype = XML_ATTRIBUTE_ENTITIES;
2234 }
2235 goto done;
2236 case XML_SCHEMAS_NOTATION:{
2237 xmlChar *uri = NULL;
2238 xmlChar *local = NULL;
2239
2240 ret = xmlValidateQName(value, 1);
2241 if ((ret == 0) && (node != NULL)) {
2242 xmlChar *prefix;
2243
2244 local = xmlSplitQName2(value, &prefix);
2245 if (prefix != NULL) {
2246 xmlNsPtr ns;
2247
2248 ns = xmlSearchNs(node->doc, node, prefix);
2249 if (ns == NULL)
2250 ret = 1;
2251 else if (val != NULL)
2252 uri = xmlStrdup(ns->href);
2253 }
2254 if ((local != NULL) && ((val == NULL) || (ret != 0)))
2255 xmlFree(local);
2256 if (prefix != NULL)
2257 xmlFree(prefix);
2258 }
2259 if ((node == NULL) || (node->doc == NULL))
2260 ret = 3;
2261 if (ret == 0) {
2262 ret = xmlValidateNotationUse(NULL, node->doc, value);
2263 if (ret == 1)
2264 ret = 0;
2265 else
2266 ret = 1;
2267 }
2268 if ((ret == 0) && (val != NULL)) {
2269 v = xmlSchemaNewValue(XML_SCHEMAS_NOTATION);
2270 if (v != NULL) {
2271 if (local != NULL)
2272 v->value.qname.name = local;
2273 else
2274 v->value.qname.name = xmlStrdup(value);
2275 if (uri != NULL)
2276 v->value.qname.uri = uri;
2277
2278 *val = v;
2279 } else {
2280 if (local != NULL)
2281 xmlFree(local);
2282 if (uri != NULL)
2283 xmlFree(uri);
2284 goto error;
2285 }
2286 }
2287 goto done;
2288 }
2289 case XML_SCHEMAS_ANYURI:{
Daniel Veillard11c466a2004-03-14 12:20:15 +00002290 if (*value != 0) {
2291 xmlURIPtr uri = xmlParseURI((const char *) value);
2292 if (uri == NULL)
2293 goto return1;
2294 xmlFreeURI(uri);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002295 }
Daniel Veillard11c466a2004-03-14 12:20:15 +00002296
2297 if (val != NULL) {
2298 v = xmlSchemaNewValue(XML_SCHEMAS_ANYURI);
2299 if (v == NULL)
2300 goto error;
2301 v->value.str = xmlStrdup(value);
2302 *val = v;
2303 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002304 goto return0;
2305 }
2306 case XML_SCHEMAS_HEXBINARY:{
2307 const xmlChar *cur = value;
2308 xmlChar *base;
2309 int total, i = 0;
2310
Daniel Veillardf34a20e2004-08-31 08:42:17 +00002311 if (cur == NULL)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002312 goto return1;
2313
2314 while (((*cur >= '0') && (*cur <= '9')) ||
2315 ((*cur >= 'A') && (*cur <= 'F')) ||
2316 ((*cur >= 'a') && (*cur <= 'f'))) {
2317 i++;
2318 cur++;
2319 }
2320
2321 if (*cur != 0)
2322 goto return1;
2323 if ((i % 2) != 0)
2324 goto return1;
2325
2326 if (val != NULL) {
2327
2328 v = xmlSchemaNewValue(XML_SCHEMAS_HEXBINARY);
2329 if (v == NULL)
2330 goto error;
2331
2332 cur = xmlStrdup(value);
2333 if (cur == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002334 xmlSchemaTypeErrMemory(node, "allocating hexbin data");
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002335 xmlFree(v);
2336 goto return1;
2337 }
2338
2339 total = i / 2; /* number of octets */
2340
2341 base = (xmlChar *) cur;
2342 while (i-- > 0) {
2343 if (*base >= 'a')
2344 *base = *base - ('a' - 'A');
2345 base++;
2346 }
2347
2348 v->value.hex.str = (xmlChar *) cur;
2349 v->value.hex.total = total;
2350 *val = v;
2351 }
2352 goto return0;
2353 }
2354 case XML_SCHEMAS_BASE64BINARY:{
2355 /* ISSUE:
2356 *
2357 * Ignore all stray characters? (yes, currently)
2358 * Worry about long lines? (no, currently)
2359 *
2360 * rfc2045.txt:
2361 *
2362 * "The encoded output stream must be represented in lines of
2363 * no more than 76 characters each. All line breaks or other
2364 * characters not found in Table 1 must be ignored by decoding
2365 * software. In base64 data, characters other than those in
2366 * Table 1, line breaks, and other white space probably
2367 * indicate a transmission error, about which a warning
2368 * message or even a message rejection might be appropriate
2369 * under some circumstances." */
2370 const xmlChar *cur = value;
2371 xmlChar *base;
2372 int total, i = 0, pad = 0;
2373
2374 if (cur == NULL)
2375 goto return1;
2376
2377 for (; *cur; ++cur) {
2378 int decc;
2379
2380 decc = _xmlSchemaBase64Decode(*cur);
2381 if (decc < 0) ;
2382 else if (decc < 64)
2383 i++;
2384 else
2385 break;
2386 }
2387 for (; *cur; ++cur) {
2388 int decc;
2389
2390 decc = _xmlSchemaBase64Decode(*cur);
2391 if (decc < 0) ;
2392 else if (decc < 64)
2393 goto return1;
2394 if (decc == 64)
2395 pad++;
2396 }
2397
2398 /* rfc2045.txt: "Special processing is performed if fewer than
2399 * 24 bits are available at the end of the data being encoded.
2400 * A full encoding quantum is always completed at the end of a
2401 * body. When fewer than 24 input bits are available in an
2402 * input group, zero bits are added (on the right) to form an
2403 * integral number of 6-bit groups. Padding at the end of the
2404 * data is performed using the "=" character. Since all
2405 * base64 input is an integral number of octets, only the
2406 * following cases can arise: (1) the final quantum of
2407 * encoding input is an integral multiple of 24 bits; here,
2408 * the final unit of encoded output will be an integral
2409 * multiple ofindent: Standard input:701: Warning:old style
2410 * assignment ambiguity in "=*". Assuming "= *" 4 characters
2411 * with no "=" padding, (2) the final
2412 * quantum of encoding input is exactly 8 bits; here, the
2413 * final unit of encoded output will be two characters
2414 * followed by two "=" padding characters, or (3) the final
2415 * quantum of encoding input is exactly 16 bits; here, the
2416 * final unit of encoded output will be three characters
2417 * followed by one "=" padding character." */
2418
2419 total = 3 * (i / 4);
2420 if (pad == 0) {
2421 if (i % 4 != 0)
2422 goto return1;
2423 } else if (pad == 1) {
2424 int decc;
2425
2426 if (i % 4 != 3)
2427 goto return1;
2428 for (decc = _xmlSchemaBase64Decode(*cur);
2429 (decc < 0) || (decc > 63);
2430 decc = _xmlSchemaBase64Decode(*cur))
2431 --cur;
2432 /* 16bits in 24bits means 2 pad bits: nnnnnn nnmmmm mmmm00*/
2433 /* 00111100 -> 0x3c */
2434 if (decc & ~0x3c)
2435 goto return1;
2436 total += 2;
2437 } else if (pad == 2) {
2438 int decc;
2439
2440 if (i % 4 != 2)
2441 goto return1;
2442 for (decc = _xmlSchemaBase64Decode(*cur);
2443 (decc < 0) || (decc > 63);
2444 decc = _xmlSchemaBase64Decode(*cur))
2445 --cur;
2446 /* 8bits in 12bits means 4 pad bits: nnnnnn nn0000 */
2447 /* 00110000 -> 0x30 */
2448 if (decc & ~0x30)
2449 goto return1;
2450 total += 1;
2451 } else
2452 goto return1;
2453
2454 if (val != NULL) {
2455 v = xmlSchemaNewValue(XML_SCHEMAS_BASE64BINARY);
2456 if (v == NULL)
2457 goto error;
2458 base =
2459 (xmlChar *) xmlMallocAtomic((i + pad + 1) *
2460 sizeof(xmlChar));
2461 if (base == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002462 xmlSchemaTypeErrMemory(node, "allocating base64 data");
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002463 xmlFree(v);
2464 goto return1;
2465 }
2466 v->value.base64.str = base;
2467 for (cur = value; *cur; ++cur)
2468 if (_xmlSchemaBase64Decode(*cur) >= 0) {
2469 *base = *cur;
2470 ++base;
2471 }
2472 *base = 0;
2473 v->value.base64.total = total;
2474 *val = v;
2475 }
2476 goto return0;
2477 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002478 case XML_SCHEMAS_INTEGER:
2479 case XML_SCHEMAS_PINTEGER:
2480 case XML_SCHEMAS_NPINTEGER:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002481 case XML_SCHEMAS_NINTEGER:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002482 case XML_SCHEMAS_NNINTEGER:{
2483 const xmlChar *cur = value;
2484 unsigned long lo, mi, hi;
2485 int sign = 0;
2486
2487 if (cur == NULL)
2488 goto return1;
2489 if (*cur == '-') {
2490 sign = 1;
2491 cur++;
2492 } else if (*cur == '+')
2493 cur++;
2494 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2495 if (ret == 0)
2496 goto return1;
2497 if (*cur != 0)
2498 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002499 if (type->builtInType == XML_SCHEMAS_NPINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002500 if ((sign == 0) &&
2501 ((hi != 0) || (mi != 0) || (lo != 0)))
2502 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002503 } else if (type->builtInType == XML_SCHEMAS_PINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002504 if (sign == 1)
2505 goto return1;
2506 if ((hi == 0) && (mi == 0) && (lo == 0))
2507 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002508 } else if (type->builtInType == XML_SCHEMAS_NINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002509 if (sign == 0)
2510 goto return1;
2511 if ((hi == 0) && (mi == 0) && (lo == 0))
2512 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002513 } else if (type->builtInType == XML_SCHEMAS_NNINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002514 if ((sign == 1) &&
2515 ((hi != 0) || (mi != 0) || (lo != 0)))
2516 goto return1;
2517 }
2518 /*
2519 * We can store a value only if no overflow occured
2520 */
2521 if ((ret > 0) && (val != NULL)) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00002522 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002523 if (v != NULL) {
2524 v->value.decimal.lo = lo;
2525 v->value.decimal.mi = lo;
2526 v->value.decimal.hi = lo;
2527 v->value.decimal.sign = sign;
2528 v->value.decimal.frac = 0;
2529 v->value.decimal.total = cur - value;
2530 *val = v;
2531 }
2532 }
2533 goto return0;
2534 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002535 case XML_SCHEMAS_LONG:
2536 case XML_SCHEMAS_BYTE:
2537 case XML_SCHEMAS_SHORT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002538 case XML_SCHEMAS_INT:{
2539 const xmlChar *cur = value;
2540 unsigned long lo, mi, hi;
2541 int total = 0;
2542 int sign = 0;
2543
2544 if (cur == NULL)
2545 goto return1;
2546 if (*cur == '-') {
2547 sign = 1;
2548 cur++;
2549 } else if (*cur == '+')
2550 cur++;
2551 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2552 if (ret <= 0)
2553 goto return1;
2554 if (*cur != 0)
2555 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002556 if (type->builtInType == XML_SCHEMAS_LONG) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002557 if (hi >= 922) {
2558 if (hi > 922)
2559 goto return1;
2560 if (mi >= 33720368) {
2561 if (mi > 33720368)
2562 goto return1;
2563 if ((sign == 0) && (lo > 54775807))
2564 goto return1;
2565 if ((sign == 1) && (lo > 54775808))
2566 goto return1;
2567 }
2568 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002569 } else if (type->builtInType == XML_SCHEMAS_INT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002570 if (hi != 0)
2571 goto return1;
2572 if (mi >= 21) {
2573 if (mi > 21)
2574 goto return1;
2575 if ((sign == 0) && (lo > 47483647))
2576 goto return1;
2577 if ((sign == 1) && (lo > 47483648))
2578 goto return1;
2579 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002580 } else if (type->builtInType == XML_SCHEMAS_SHORT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002581 if ((mi != 0) || (hi != 0))
2582 goto return1;
2583 if ((sign == 1) && (lo > 32768))
2584 goto return1;
2585 if ((sign == 0) && (lo > 32767))
2586 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002587 } else if (type->builtInType == XML_SCHEMAS_BYTE) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002588 if ((mi != 0) || (hi != 0))
2589 goto return1;
2590 if ((sign == 1) && (lo > 128))
2591 goto return1;
2592 if ((sign == 0) && (lo > 127))
2593 goto return1;
2594 }
2595 if (val != NULL) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00002596 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002597 if (v != NULL) {
2598 v->value.decimal.lo = lo;
2599 v->value.decimal.mi = lo;
2600 v->value.decimal.hi = lo;
2601 v->value.decimal.sign = sign;
2602 v->value.decimal.frac = 0;
2603 v->value.decimal.total = total;
2604 *val = v;
2605 }
2606 }
2607 goto return0;
2608 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002609 case XML_SCHEMAS_UINT:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002610 case XML_SCHEMAS_ULONG:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002611 case XML_SCHEMAS_USHORT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002612 case XML_SCHEMAS_UBYTE:{
2613 const xmlChar *cur = value;
2614 unsigned long lo, mi, hi;
2615 int total = 0;
2616
2617 if (cur == NULL)
2618 goto return1;
2619 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2620 if (ret <= 0)
2621 goto return1;
2622 if (*cur != 0)
2623 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002624 if (type->builtInType == XML_SCHEMAS_ULONG) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002625 if (hi >= 1844) {
2626 if (hi > 1844)
2627 goto return1;
2628 if (mi >= 67440737) {
2629 if (mi > 67440737)
2630 goto return1;
2631 if (lo > 9551615)
2632 goto return1;
2633 }
2634 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002635 } else if (type->builtInType == XML_SCHEMAS_UINT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002636 if (hi != 0)
2637 goto return1;
2638 if (mi >= 42) {
2639 if (mi > 42)
2640 goto return1;
2641 if (lo > 94967295)
2642 goto return1;
2643 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002644 } else if (type->builtInType == XML_SCHEMAS_USHORT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002645 if ((mi != 0) || (hi != 0))
2646 goto return1;
2647 if (lo > 65535)
2648 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002649 } else if (type->builtInType == XML_SCHEMAS_UBYTE) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002650 if ((mi != 0) || (hi != 0))
2651 goto return1;
2652 if (lo > 255)
2653 goto return1;
2654 }
2655 if (val != NULL) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00002656 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002657 if (v != NULL) {
2658 v->value.decimal.lo = lo;
2659 v->value.decimal.mi = mi;
2660 v->value.decimal.hi = hi;
2661 v->value.decimal.sign = 0;
2662 v->value.decimal.frac = 0;
2663 v->value.decimal.total = total;
2664 *val = v;
2665 }
2666 }
2667 goto return0;
2668 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002669 }
2670
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002671 done:
2672 if (norm != NULL)
2673 xmlFree(norm);
2674 return (ret);
2675 return3:
2676 if (norm != NULL)
2677 xmlFree(norm);
2678 return (3);
2679 return1:
2680 if (norm != NULL)
2681 xmlFree(norm);
2682 return (1);
2683 return0:
2684 if (norm != NULL)
2685 xmlFree(norm);
2686 return (0);
2687 error:
2688 if (norm != NULL)
2689 xmlFree(norm);
2690 return (-1);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002691}
2692
2693/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002694 * xmlSchemaValPredefTypeNode:
Daniel Veillard4255d502002-04-16 15:50:10 +00002695 * @type: the predefined type
2696 * @value: the value to check
2697 * @val: the return computed value
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002698 * @node: the node containing the value
Daniel Veillard4255d502002-04-16 15:50:10 +00002699 *
2700 * Check that a value conforms to the lexical space of the predefined type.
2701 * if true a value is computed and returned in @val.
2702 *
2703 * Returns 0 if this validates, a positive error code number otherwise
2704 * and -1 in case of internal or API error.
2705 */
2706int
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002707xmlSchemaValPredefTypeNode(xmlSchemaTypePtr type, const xmlChar *value,
2708 xmlSchemaValPtr *val, xmlNodePtr node) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002709 return(xmlSchemaValAtomicType(type, value, val, node, 0));
Daniel Veillard4255d502002-04-16 15:50:10 +00002710}
2711
2712/**
Daniel Veillardc0826a72004-08-10 14:17:33 +00002713 * xmlSchemaValPredefTypeNodeNoNorm:
2714 * @type: the predefined type
2715 * @value: the value to check
2716 * @val: the return computed value
2717 * @node: the node containing the value
2718 *
2719 * Check that a value conforms to the lexical space of the predefined type.
2720 * if true a value is computed and returned in @val.
2721 * This one does apply any normalization to the value.
2722 *
2723 * Returns 0 if this validates, a positive error code number otherwise
2724 * and -1 in case of internal or API error.
2725 */
2726int
2727xmlSchemaValPredefTypeNodeNoNorm(xmlSchemaTypePtr type, const xmlChar *value,
2728 xmlSchemaValPtr *val, xmlNodePtr node) {
2729 return(xmlSchemaValAtomicType(type, value, val, node, 1));
2730}
2731
2732/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002733 * xmlSchemaValidatePredefinedType:
2734 * @type: the predefined type
2735 * @value: the value to check
2736 * @val: the return computed value
2737 *
2738 * Check that a value conforms to the lexical space of the predefined type.
2739 * if true a value is computed and returned in @val.
2740 *
2741 * Returns 0 if this validates, a positive error code number otherwise
2742 * and -1 in case of internal or API error.
2743 */
2744int
2745xmlSchemaValidatePredefinedType(xmlSchemaTypePtr type, const xmlChar *value,
2746 xmlSchemaValPtr *val) {
2747 return(xmlSchemaValPredefTypeNode(type, value, val, NULL));
2748}
2749
2750/**
Daniel Veillard4255d502002-04-16 15:50:10 +00002751 * xmlSchemaCompareDecimals:
2752 * @x: a first decimal value
2753 * @y: a second decimal value
2754 *
2755 * Compare 2 decimals
2756 *
2757 * Returns -1 if x < y, 0 if x == y, 1 if x > y and -2 in case of error
2758 */
2759static int
2760xmlSchemaCompareDecimals(xmlSchemaValPtr x, xmlSchemaValPtr y)
2761{
2762 xmlSchemaValPtr swp;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002763 int order = 1, p;
Daniel Veillard4255d502002-04-16 15:50:10 +00002764 unsigned long tmp;
2765
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002766 if ((x->value.decimal.sign) &&
2767 ((x->value.decimal.lo != 0) ||
2768 (x->value.decimal.mi != 0) ||
2769 (x->value.decimal.hi != 0))) {
2770 if ((y->value.decimal.sign) &&
2771 ((y->value.decimal.lo != 0) ||
2772 (y->value.decimal.mi != 0) ||
2773 (y->value.decimal.hi != 0)))
Daniel Veillard80b19092003-03-28 13:29:53 +00002774 order = -1;
2775 else
2776 return (-1);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002777 } else if ((y->value.decimal.sign) &&
2778 ((y->value.decimal.lo != 0) ||
2779 (y->value.decimal.mi != 0) ||
2780 (y->value.decimal.hi != 0))) {
Daniel Veillard4255d502002-04-16 15:50:10 +00002781 return (1);
Daniel Veillard80b19092003-03-28 13:29:53 +00002782 }
Daniel Veillard4255d502002-04-16 15:50:10 +00002783 if (x->value.decimal.frac == y->value.decimal.frac) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002784 if (x->value.decimal.hi < y->value.decimal.hi)
2785 return (-order);
Daniel Veillard01fa6152004-06-29 17:04:39 +00002786 if (x->value.decimal.hi > y->value.decimal.hi)
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002787 return (order);
2788 if (x->value.decimal.mi < y->value.decimal.mi)
2789 return (-order);
Daniel Veillard01fa6152004-06-29 17:04:39 +00002790 if (x->value.decimal.mi > y->value.decimal.mi)
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002791 return (order);
2792 if (x->value.decimal.lo < y->value.decimal.lo)
Daniel Veillard80b19092003-03-28 13:29:53 +00002793 return (-order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002794 if (x->value.decimal.lo > y->value.decimal.lo)
Daniel Veillard80b19092003-03-28 13:29:53 +00002795 return(order);
2796 return(0);
Daniel Veillard4255d502002-04-16 15:50:10 +00002797 }
2798 if (y->value.decimal.frac > x->value.decimal.frac) {
2799 swp = y;
2800 y = x;
2801 x = swp;
2802 order = -order;
2803 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002804 p = powten[x->value.decimal.frac - y->value.decimal.frac];
2805 tmp = x->value.decimal.lo / p;
2806 if (tmp > y->value.decimal.lo)
Daniel Veillard4255d502002-04-16 15:50:10 +00002807 return (order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002808 if (tmp < y->value.decimal.lo)
Daniel Veillard4255d502002-04-16 15:50:10 +00002809 return (-order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002810 tmp = y->value.decimal.lo * p;
2811 if (x->value.decimal.lo < tmp)
Daniel Veillard4255d502002-04-16 15:50:10 +00002812 return (-order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002813 if (x->value.decimal.lo == tmp)
Daniel Veillard4255d502002-04-16 15:50:10 +00002814 return (0);
2815 return (order);
2816}
2817
2818/**
Daniel Veillard070803b2002-05-03 07:29:38 +00002819 * xmlSchemaCompareDurations:
2820 * @x: a first duration value
2821 * @y: a second duration value
2822 *
2823 * Compare 2 durations
2824 *
2825 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
2826 * case of error
2827 */
2828static int
2829xmlSchemaCompareDurations(xmlSchemaValPtr x, xmlSchemaValPtr y)
2830{
2831 long carry, mon, day;
2832 double sec;
Daniel Veillard80b19092003-03-28 13:29:53 +00002833 int invert = 1;
2834 long xmon, xday, myear, minday, maxday;
Daniel Veillard070803b2002-05-03 07:29:38 +00002835 static const long dayRange [2][12] = {
2836 { 0, 28, 59, 89, 120, 150, 181, 212, 242, 273, 303, 334, },
2837 { 0, 31, 62, 92, 123, 153, 184, 215, 245, 276, 306, 337} };
2838
2839 if ((x == NULL) || (y == NULL))
Daniel Veillard5a872412002-05-22 06:40:27 +00002840 return -2;
Daniel Veillard070803b2002-05-03 07:29:38 +00002841
2842 /* months */
2843 mon = x->value.dur.mon - y->value.dur.mon;
2844
2845 /* seconds */
2846 sec = x->value.dur.sec - y->value.dur.sec;
2847 carry = (long)sec / SECS_PER_DAY;
2848 sec -= (double)(carry * SECS_PER_DAY);
2849
2850 /* days */
2851 day = x->value.dur.day - y->value.dur.day + carry;
2852
2853 /* easy test */
2854 if (mon == 0) {
2855 if (day == 0)
2856 if (sec == 0.0)
2857 return 0;
2858 else if (sec < 0.0)
2859 return -1;
2860 else
2861 return 1;
2862 else if (day < 0)
2863 return -1;
2864 else
2865 return 1;
2866 }
2867
2868 if (mon > 0) {
2869 if ((day >= 0) && (sec >= 0.0))
2870 return 1;
2871 else {
2872 xmon = mon;
2873 xday = -day;
2874 }
2875 } else if ((day <= 0) && (sec <= 0.0)) {
2876 return -1;
2877 } else {
Daniel Veillard80b19092003-03-28 13:29:53 +00002878 invert = -1;
Daniel Veillard070803b2002-05-03 07:29:38 +00002879 xmon = -mon;
2880 xday = day;
2881 }
2882
2883 myear = xmon / 12;
Daniel Veillard80b19092003-03-28 13:29:53 +00002884 if (myear == 0) {
2885 minday = 0;
2886 maxday = 0;
2887 } else {
2888 maxday = 366 * ((myear + 3) / 4) +
2889 365 * ((myear - 1) % 4);
2890 minday = maxday - 1;
2891 }
2892
Daniel Veillard070803b2002-05-03 07:29:38 +00002893 xmon = xmon % 12;
2894 minday += dayRange[0][xmon];
2895 maxday += dayRange[1][xmon];
2896
Daniel Veillard80b19092003-03-28 13:29:53 +00002897 if ((maxday == minday) && (maxday == xday))
2898 return(0); /* can this really happen ? */
Daniel Veillard070803b2002-05-03 07:29:38 +00002899 if (maxday < xday)
Daniel Veillard80b19092003-03-28 13:29:53 +00002900 return(-invert);
2901 if (minday > xday)
2902 return(invert);
Daniel Veillard070803b2002-05-03 07:29:38 +00002903
2904 /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00002905 return 2;
2906}
2907
2908/*
2909 * macros for adding date/times and durations
2910 */
2911#define FQUOTIENT(a,b) (floor(((double)a/(double)b)))
2912#define MODULO(a,b) (a - FQUOTIENT(a,b) * b)
2913#define FQUOTIENT_RANGE(a,low,high) (FQUOTIENT((a-low),(high-low)))
2914#define MODULO_RANGE(a,low,high) ((MODULO((a-low),(high-low)))+low)
2915
2916/**
Daniel Veillard669adfc2004-05-29 20:12:46 +00002917 * xmlSchemaDupVal:
2918 * @v: the #xmlSchemaValPtr value to duplicate
2919 *
2920 * Makes a copy of @v. The calling program is responsible for freeing
2921 * the returned value.
2922 *
2923 * returns a pointer to a duplicated #xmlSchemaValPtr or NULL if error.
2924 */
2925static xmlSchemaValPtr
2926xmlSchemaDupVal (xmlSchemaValPtr v)
2927{
2928 xmlSchemaValPtr ret = xmlSchemaNewValue(v->type);
2929 if (ret == NULL)
2930 return NULL;
2931
2932 memcpy(ret, v, sizeof(xmlSchemaVal));
2933 return ret;
2934}
2935
2936/**
Daniel Veillard5a872412002-05-22 06:40:27 +00002937 * _xmlSchemaDateAdd:
2938 * @dt: an #xmlSchemaValPtr
2939 * @dur: an #xmlSchemaValPtr of type #XS_DURATION
2940 *
2941 * Compute a new date/time from @dt and @dur. This function assumes @dt
2942 * is either #XML_SCHEMAS_DATETIME, #XML_SCHEMAS_DATE, #XML_SCHEMAS_GYEARMONTH,
Daniel Veillard669adfc2004-05-29 20:12:46 +00002943 * or #XML_SCHEMAS_GYEAR. The returned #xmlSchemaVal is the same type as
2944 * @dt. The calling program is responsible for freeing the returned value.
Daniel Veillard5a872412002-05-22 06:40:27 +00002945 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00002946 * Returns a pointer to a new #xmlSchemaVal or NULL if error.
Daniel Veillard5a872412002-05-22 06:40:27 +00002947 */
2948static xmlSchemaValPtr
2949_xmlSchemaDateAdd (xmlSchemaValPtr dt, xmlSchemaValPtr dur)
2950{
Daniel Veillard669adfc2004-05-29 20:12:46 +00002951 xmlSchemaValPtr ret, tmp;
Daniel Veillard5a872412002-05-22 06:40:27 +00002952 long carry, tempdays, temp;
2953 xmlSchemaValDatePtr r, d;
2954 xmlSchemaValDurationPtr u;
2955
2956 if ((dt == NULL) || (dur == NULL))
2957 return NULL;
2958
2959 ret = xmlSchemaNewValue(dt->type);
2960 if (ret == NULL)
2961 return NULL;
2962
Daniel Veillard669adfc2004-05-29 20:12:46 +00002963 /* make a copy so we don't alter the original value */
2964 tmp = xmlSchemaDupVal(dt);
2965 if (tmp == NULL) {
2966 xmlSchemaFreeValue(ret);
2967 return NULL;
2968 }
2969
Daniel Veillard5a872412002-05-22 06:40:27 +00002970 r = &(ret->value.date);
Daniel Veillard669adfc2004-05-29 20:12:46 +00002971 d = &(tmp->value.date);
Daniel Veillard5a872412002-05-22 06:40:27 +00002972 u = &(dur->value.dur);
2973
2974 /* normalization */
2975 if (d->mon == 0)
2976 d->mon = 1;
2977
2978 /* normalize for time zone offset */
2979 u->sec -= (d->tzo * 60);
2980 d->tzo = 0;
2981
2982 /* normalization */
2983 if (d->day == 0)
2984 d->day = 1;
2985
2986 /* month */
2987 carry = d->mon + u->mon;
Daniel Veillardebe25d42004-03-25 09:35:49 +00002988 r->mon = (unsigned int) MODULO_RANGE(carry, 1, 13);
2989 carry = (long) FQUOTIENT_RANGE(carry, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00002990
2991 /* year (may be modified later) */
2992 r->year = d->year + carry;
2993 if (r->year == 0) {
2994 if (d->year > 0)
2995 r->year--;
2996 else
2997 r->year++;
2998 }
2999
3000 /* time zone */
3001 r->tzo = d->tzo;
3002 r->tz_flag = d->tz_flag;
3003
3004 /* seconds */
3005 r->sec = d->sec + u->sec;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003006 carry = (long) FQUOTIENT((long)r->sec, 60);
Daniel Veillard5a872412002-05-22 06:40:27 +00003007 if (r->sec != 0.0) {
3008 r->sec = MODULO(r->sec, 60.0);
3009 }
3010
3011 /* minute */
3012 carry += d->min;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003013 r->min = (unsigned int) MODULO(carry, 60);
3014 carry = (long) FQUOTIENT(carry, 60);
Daniel Veillard5a872412002-05-22 06:40:27 +00003015
3016 /* hours */
3017 carry += d->hour;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003018 r->hour = (unsigned int) MODULO(carry, 24);
3019 carry = (long)FQUOTIENT(carry, 24);
Daniel Veillard5a872412002-05-22 06:40:27 +00003020
3021 /*
3022 * days
3023 * Note we use tempdays because the temporary values may need more
3024 * than 5 bits
3025 */
3026 if ((VALID_YEAR(r->year)) && (VALID_MONTH(r->mon)) &&
3027 (d->day > MAX_DAYINMONTH(r->year, r->mon)))
3028 tempdays = MAX_DAYINMONTH(r->year, r->mon);
3029 else if (d->day < 1)
3030 tempdays = 1;
3031 else
3032 tempdays = d->day;
3033
3034 tempdays += u->day + carry;
3035
3036 while (1) {
3037 if (tempdays < 1) {
Daniel Veillardebe25d42004-03-25 09:35:49 +00003038 long tmon = (long) MODULO_RANGE(r->mon-1, 1, 13);
3039 long tyr = r->year + (long)FQUOTIENT_RANGE(r->mon-1, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00003040 if (tyr == 0)
3041 tyr--;
3042 tempdays += MAX_DAYINMONTH(tyr, tmon);
3043 carry = -1;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003044 } else if (tempdays > (long) MAX_DAYINMONTH(r->year, r->mon)) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003045 tempdays = tempdays - MAX_DAYINMONTH(r->year, r->mon);
3046 carry = 1;
3047 } else
3048 break;
3049
3050 temp = r->mon + carry;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003051 r->mon = (unsigned int) MODULO_RANGE(temp, 1, 13);
3052 r->year = r->year + (unsigned int) FQUOTIENT_RANGE(temp, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00003053 if (r->year == 0) {
3054 if (temp < 1)
3055 r->year--;
3056 else
3057 r->year++;
3058 }
3059 }
3060
3061 r->day = tempdays;
3062
3063 /*
3064 * adjust the date/time type to the date values
3065 */
3066 if (ret->type != XML_SCHEMAS_DATETIME) {
3067 if ((r->hour) || (r->min) || (r->sec))
3068 ret->type = XML_SCHEMAS_DATETIME;
3069 else if (ret->type != XML_SCHEMAS_DATE) {
3070 if ((r->mon != 1) && (r->day != 1))
3071 ret->type = XML_SCHEMAS_DATE;
3072 else if ((ret->type != XML_SCHEMAS_GYEARMONTH) && (r->mon != 1))
3073 ret->type = XML_SCHEMAS_GYEARMONTH;
3074 }
3075 }
3076
Daniel Veillard669adfc2004-05-29 20:12:46 +00003077 xmlSchemaFreeValue(tmp);
Daniel Veillard5a872412002-05-22 06:40:27 +00003078
Daniel Veillard5a872412002-05-22 06:40:27 +00003079 return ret;
3080}
3081
3082/**
3083 * xmlSchemaDateNormalize:
Daniel Veillard669adfc2004-05-29 20:12:46 +00003084 * @dt: an #xmlSchemaValPtr of a date/time type value.
3085 * @offset: number of seconds to adjust @dt by.
Daniel Veillard5a872412002-05-22 06:40:27 +00003086 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00003087 * Normalize @dt to GMT time. The @offset parameter is subtracted from
3088 * the return value is a time-zone offset is present on @dt.
Daniel Veillard5a872412002-05-22 06:40:27 +00003089 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00003090 * Returns a normalized copy of @dt or NULL if error.
Daniel Veillard5a872412002-05-22 06:40:27 +00003091 */
3092static xmlSchemaValPtr
3093xmlSchemaDateNormalize (xmlSchemaValPtr dt, double offset)
3094{
3095 xmlSchemaValPtr dur, ret;
3096
3097 if (dt == NULL)
3098 return NULL;
3099
3100 if (((dt->type != XML_SCHEMAS_TIME) &&
3101 (dt->type != XML_SCHEMAS_DATETIME)) || (dt->value.date.tzo == 0))
3102 return xmlSchemaDupVal(dt);
3103
3104 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
3105 if (dur == NULL)
3106 return NULL;
3107
3108 dur->value.date.sec -= offset;
3109
3110 ret = _xmlSchemaDateAdd(dt, dur);
3111 if (ret == NULL)
3112 return NULL;
3113
3114 xmlSchemaFreeValue(dur);
3115
3116 /* ret->value.date.tzo = 0; */
3117 return ret;
3118}
3119
3120/**
3121 * _xmlSchemaDateCastYMToDays:
3122 * @dt: an #xmlSchemaValPtr
3123 *
3124 * Convert mon and year of @dt to total number of days. Take the
3125 * number of years since (or before) 1 AD and add the number of leap
3126 * years. This is a function because negative
3127 * years must be handled a little differently and there is no zero year.
3128 *
3129 * Returns number of days.
3130 */
3131static long
3132_xmlSchemaDateCastYMToDays (const xmlSchemaValPtr dt)
3133{
3134 long ret;
Daniel Veillard49e89632004-09-23 16:24:36 +00003135 int mon;
Daniel Veillard5a872412002-05-22 06:40:27 +00003136
Daniel Veillard49e89632004-09-23 16:24:36 +00003137 mon = dt->value.date.mon;
3138 if (mon <= 0) mon = 1; /* normalization */
3139
3140 if (dt->value.date.year <= 0)
Daniel Veillard5a872412002-05-22 06:40:27 +00003141 ret = (dt->value.date.year * 365) +
3142 (((dt->value.date.year+1)/4)-((dt->value.date.year+1)/100)+
3143 ((dt->value.date.year+1)/400)) +
Daniel Veillard49e89632004-09-23 16:24:36 +00003144 DAY_IN_YEAR(0, mon, dt->value.date.year);
Daniel Veillard5a872412002-05-22 06:40:27 +00003145 else
3146 ret = ((dt->value.date.year-1) * 365) +
3147 (((dt->value.date.year-1)/4)-((dt->value.date.year-1)/100)+
3148 ((dt->value.date.year-1)/400)) +
Daniel Veillard49e89632004-09-23 16:24:36 +00003149 DAY_IN_YEAR(0, mon, dt->value.date.year);
Daniel Veillard5a872412002-05-22 06:40:27 +00003150
3151 return ret;
3152}
3153
3154/**
3155 * TIME_TO_NUMBER:
3156 * @dt: an #xmlSchemaValPtr
3157 *
3158 * Calculates the number of seconds in the time portion of @dt.
3159 *
3160 * Returns seconds.
3161 */
3162#define TIME_TO_NUMBER(dt) \
3163 ((double)((dt->value.date.hour * SECS_PER_HOUR) + \
Daniel Veillardb3721c22003-03-31 11:22:25 +00003164 (dt->value.date.min * SECS_PER_MIN) + \
3165 (dt->value.date.tzo * SECS_PER_MIN)) + \
3166 dt->value.date.sec)
Daniel Veillard5a872412002-05-22 06:40:27 +00003167
3168/**
3169 * xmlSchemaCompareDates:
3170 * @x: a first date/time value
3171 * @y: a second date/time value
3172 *
3173 * Compare 2 date/times
3174 *
3175 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3176 * case of error
3177 */
3178static int
3179xmlSchemaCompareDates (xmlSchemaValPtr x, xmlSchemaValPtr y)
3180{
3181 unsigned char xmask, ymask, xor_mask, and_mask;
3182 xmlSchemaValPtr p1, p2, q1, q2;
3183 long p1d, p2d, q1d, q2d;
3184
3185 if ((x == NULL) || (y == NULL))
3186 return -2;
3187
3188 if (x->value.date.tz_flag) {
3189
3190 if (!y->value.date.tz_flag) {
3191 p1 = xmlSchemaDateNormalize(x, 0);
3192 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3193 /* normalize y + 14:00 */
3194 q1 = xmlSchemaDateNormalize(y, (14 * SECS_PER_HOUR));
3195
3196 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003197 if (p1d < q1d) {
3198 xmlSchemaFreeValue(p1);
3199 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003200 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003201 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003202 double sec;
3203
3204 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00003205 if (sec < 0.0) {
3206 xmlSchemaFreeValue(p1);
3207 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003208 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003209 } else {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003210 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003211 /* normalize y - 14:00 */
3212 q2 = xmlSchemaDateNormalize(y, -(14 * SECS_PER_HOUR));
3213 q2d = _xmlSchemaDateCastYMToDays(q2) + q2->value.date.day;
3214 if (p1d > q2d)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003215 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003216 else if (p1d == q2d) {
3217 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q2);
3218 if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003219 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003220 else
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003221 ret = 2; /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00003222 }
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003223 xmlSchemaFreeValue(p1);
3224 xmlSchemaFreeValue(q1);
3225 xmlSchemaFreeValue(q2);
3226 if (ret != 0)
3227 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003228 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00003229 } else {
3230 xmlSchemaFreeValue(p1);
3231 xmlSchemaFreeValue(q1);
3232 }
Daniel Veillard5a872412002-05-22 06:40:27 +00003233 }
3234 } else if (y->value.date.tz_flag) {
3235 q1 = xmlSchemaDateNormalize(y, 0);
3236 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
3237
3238 /* normalize x - 14:00 */
3239 p1 = xmlSchemaDateNormalize(x, -(14 * SECS_PER_HOUR));
3240 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3241
Daniel Veillardfdc91562002-07-01 21:52:03 +00003242 if (p1d < q1d) {
3243 xmlSchemaFreeValue(p1);
3244 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003245 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003246 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003247 double sec;
3248
3249 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00003250 if (sec < 0.0) {
3251 xmlSchemaFreeValue(p1);
3252 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003253 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003254 } else {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003255 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003256 /* normalize x + 14:00 */
3257 p2 = xmlSchemaDateNormalize(x, (14 * SECS_PER_HOUR));
3258 p2d = _xmlSchemaDateCastYMToDays(p2) + p2->value.date.day;
3259
Daniel Veillard6560a422003-03-27 21:25:38 +00003260 if (p2d > q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003261 ret = 1;
Daniel Veillard6560a422003-03-27 21:25:38 +00003262 } else if (p2d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003263 sec = TIME_TO_NUMBER(p2) - TIME_TO_NUMBER(q1);
3264 if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003265 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003266 else
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003267 ret = 2; /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00003268 }
Daniel Veillard6560a422003-03-27 21:25:38 +00003269 xmlSchemaFreeValue(p1);
3270 xmlSchemaFreeValue(q1);
3271 xmlSchemaFreeValue(p2);
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003272 if (ret != 0)
3273 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003274 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00003275 } else {
3276 xmlSchemaFreeValue(p1);
3277 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003278 }
3279 }
3280
3281 /*
3282 * if the same type then calculate the difference
3283 */
3284 if (x->type == y->type) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003285 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003286 q1 = xmlSchemaDateNormalize(y, 0);
3287 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
3288
3289 p1 = xmlSchemaDateNormalize(x, 0);
3290 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3291
Daniel Veillardfdc91562002-07-01 21:52:03 +00003292 if (p1d < q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003293 ret = -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003294 } else if (p1d > q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003295 ret = 1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003296 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00003297 double sec;
3298
3299 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
3300 if (sec < 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003301 ret = -1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003302 else if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003303 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003304
3305 }
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003306 xmlSchemaFreeValue(p1);
3307 xmlSchemaFreeValue(q1);
3308 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003309 }
3310
3311 switch (x->type) {
3312 case XML_SCHEMAS_DATETIME:
3313 xmask = 0xf;
3314 break;
3315 case XML_SCHEMAS_DATE:
3316 xmask = 0x7;
3317 break;
3318 case XML_SCHEMAS_GYEAR:
3319 xmask = 0x1;
3320 break;
3321 case XML_SCHEMAS_GMONTH:
3322 xmask = 0x2;
3323 break;
3324 case XML_SCHEMAS_GDAY:
3325 xmask = 0x3;
3326 break;
3327 case XML_SCHEMAS_GYEARMONTH:
3328 xmask = 0x3;
3329 break;
3330 case XML_SCHEMAS_GMONTHDAY:
3331 xmask = 0x6;
3332 break;
3333 case XML_SCHEMAS_TIME:
3334 xmask = 0x8;
3335 break;
3336 default:
3337 xmask = 0;
3338 break;
3339 }
3340
3341 switch (y->type) {
3342 case XML_SCHEMAS_DATETIME:
3343 ymask = 0xf;
3344 break;
3345 case XML_SCHEMAS_DATE:
3346 ymask = 0x7;
3347 break;
3348 case XML_SCHEMAS_GYEAR:
3349 ymask = 0x1;
3350 break;
3351 case XML_SCHEMAS_GMONTH:
3352 ymask = 0x2;
3353 break;
3354 case XML_SCHEMAS_GDAY:
3355 ymask = 0x3;
3356 break;
3357 case XML_SCHEMAS_GYEARMONTH:
3358 ymask = 0x3;
3359 break;
3360 case XML_SCHEMAS_GMONTHDAY:
3361 ymask = 0x6;
3362 break;
3363 case XML_SCHEMAS_TIME:
3364 ymask = 0x8;
3365 break;
3366 default:
3367 ymask = 0;
3368 break;
3369 }
3370
3371 xor_mask = xmask ^ ymask; /* mark type differences */
3372 and_mask = xmask & ymask; /* mark field specification */
3373
3374 /* year */
3375 if (xor_mask & 1)
3376 return 2; /* indeterminate */
3377 else if (and_mask & 1) {
3378 if (x->value.date.year < y->value.date.year)
3379 return -1;
3380 else if (x->value.date.year > y->value.date.year)
3381 return 1;
3382 }
3383
3384 /* month */
3385 if (xor_mask & 2)
3386 return 2; /* indeterminate */
3387 else if (and_mask & 2) {
3388 if (x->value.date.mon < y->value.date.mon)
3389 return -1;
3390 else if (x->value.date.mon > y->value.date.mon)
3391 return 1;
3392 }
3393
3394 /* day */
3395 if (xor_mask & 4)
3396 return 2; /* indeterminate */
3397 else if (and_mask & 4) {
3398 if (x->value.date.day < y->value.date.day)
3399 return -1;
3400 else if (x->value.date.day > y->value.date.day)
3401 return 1;
3402 }
3403
3404 /* time */
3405 if (xor_mask & 8)
3406 return 2; /* indeterminate */
3407 else if (and_mask & 8) {
3408 if (x->value.date.hour < y->value.date.hour)
3409 return -1;
3410 else if (x->value.date.hour > y->value.date.hour)
3411 return 1;
3412 else if (x->value.date.min < y->value.date.min)
3413 return -1;
3414 else if (x->value.date.min > y->value.date.min)
3415 return 1;
3416 else if (x->value.date.sec < y->value.date.sec)
3417 return -1;
3418 else if (x->value.date.sec > y->value.date.sec)
3419 return 1;
3420 }
3421
Daniel Veillard070803b2002-05-03 07:29:38 +00003422 return 0;
3423}
3424
3425/**
Daniel Veillardc4c21552003-03-29 10:53:38 +00003426 * xmlSchemaCompareNormStrings:
3427 * @x: a first string value
3428 * @y: a second string value
3429 *
3430 * Compare 2 string for their normalized values.
3431 *
3432 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
3433 * case of error
3434 */
3435static int
3436xmlSchemaCompareNormStrings(xmlSchemaValPtr x, xmlSchemaValPtr y) {
3437 const xmlChar *utf1;
3438 const xmlChar *utf2;
3439 int tmp;
3440
3441 if ((x == NULL) || (y == NULL))
3442 return(-2);
3443 utf1 = x->value.str;
3444 utf2 = y->value.str;
3445
William M. Brack76e95df2003-10-18 16:20:14 +00003446 while (IS_BLANK_CH(*utf1)) utf1++;
3447 while (IS_BLANK_CH(*utf2)) utf2++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003448 while ((*utf1 != 0) && (*utf2 != 0)) {
William M. Brack76e95df2003-10-18 16:20:14 +00003449 if (IS_BLANK_CH(*utf1)) {
3450 if (!IS_BLANK_CH(*utf2)) {
Daniel Veillardc4c21552003-03-29 10:53:38 +00003451 tmp = *utf1 - *utf2;
3452 return(tmp);
3453 }
William M. Brack76e95df2003-10-18 16:20:14 +00003454 while (IS_BLANK_CH(*utf1)) utf1++;
3455 while (IS_BLANK_CH(*utf2)) utf2++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003456 } else {
3457 tmp = *utf1++ - *utf2++;
3458 if (tmp < 0)
3459 return(-1);
3460 if (tmp > 0)
3461 return(1);
3462 }
3463 }
3464 if (*utf1 != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00003465 while (IS_BLANK_CH(*utf1)) utf1++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003466 if (*utf1 != 0)
3467 return(1);
3468 }
3469 if (*utf2 != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00003470 while (IS_BLANK_CH(*utf2)) utf2++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003471 if (*utf2 != 0)
3472 return(-1);
3473 }
3474 return(0);
3475}
3476
3477/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003478 * xmlSchemaCompareFloats:
3479 * @x: a first float or double value
3480 * @y: a second float or double value
3481 *
3482 * Compare 2 values
3483 *
3484 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3485 * case of error
3486 */
3487static int
3488xmlSchemaCompareFloats(xmlSchemaValPtr x, xmlSchemaValPtr y) {
3489 double d1, d2;
3490
3491 if ((x == NULL) || (y == NULL))
3492 return(-2);
3493
3494 /*
3495 * Cast everything to doubles.
3496 */
3497 if (x->type == XML_SCHEMAS_DOUBLE)
3498 d1 = x->value.d;
3499 else if (x->type == XML_SCHEMAS_FLOAT)
3500 d1 = x->value.f;
3501 else
3502 return(-2);
3503
3504 if (y->type == XML_SCHEMAS_DOUBLE)
3505 d2 = y->value.d;
3506 else if (y->type == XML_SCHEMAS_FLOAT)
3507 d2 = y->value.f;
3508 else
3509 return(-2);
3510
3511 /*
3512 * Check for special cases.
3513 */
3514 if (xmlXPathIsNaN(d1)) {
3515 if (xmlXPathIsNaN(d2))
3516 return(0);
3517 return(1);
3518 }
3519 if (xmlXPathIsNaN(d2))
3520 return(-1);
3521 if (d1 == xmlXPathPINF) {
3522 if (d2 == xmlXPathPINF)
3523 return(0);
3524 return(1);
3525 }
3526 if (d2 == xmlXPathPINF)
3527 return(-1);
3528 if (d1 == xmlXPathNINF) {
3529 if (d2 == xmlXPathNINF)
3530 return(0);
3531 return(-1);
3532 }
3533 if (d2 == xmlXPathNINF)
3534 return(1);
3535
3536 /*
3537 * basic tests, the last one we should have equality, but
3538 * portability is more important than speed and handling
3539 * NaN or Inf in a portable way is always a challenge, so ...
3540 */
3541 if (d1 < d2)
3542 return(-1);
3543 if (d1 > d2)
3544 return(1);
3545 if (d1 == d2)
3546 return(0);
3547 return(2);
3548}
3549
3550/**
Daniel Veillard4255d502002-04-16 15:50:10 +00003551 * xmlSchemaCompareValues:
3552 * @x: a first value
3553 * @y: a second value
3554 *
3555 * Compare 2 values
3556 *
Daniel Veillard5a872412002-05-22 06:40:27 +00003557 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3558 * case of error
Daniel Veillard4255d502002-04-16 15:50:10 +00003559 */
Daniel Veillard80b19092003-03-28 13:29:53 +00003560int
Daniel Veillard4255d502002-04-16 15:50:10 +00003561xmlSchemaCompareValues(xmlSchemaValPtr x, xmlSchemaValPtr y) {
3562 if ((x == NULL) || (y == NULL))
3563 return(-2);
3564
3565 switch (x->type) {
Daniel Veillard80b19092003-03-28 13:29:53 +00003566 case XML_SCHEMAS_UNKNOWN:
William M. Brack2f2a6632004-08-20 23:09:47 +00003567 case XML_SCHEMAS_ANYTYPE:
3568 case XML_SCHEMAS_ANYSIMPLETYPE:
Daniel Veillard80b19092003-03-28 13:29:53 +00003569 return(-2);
3570 case XML_SCHEMAS_INTEGER:
3571 case XML_SCHEMAS_NPINTEGER:
3572 case XML_SCHEMAS_NINTEGER:
3573 case XML_SCHEMAS_NNINTEGER:
3574 case XML_SCHEMAS_PINTEGER:
3575 case XML_SCHEMAS_INT:
3576 case XML_SCHEMAS_UINT:
3577 case XML_SCHEMAS_LONG:
3578 case XML_SCHEMAS_ULONG:
3579 case XML_SCHEMAS_SHORT:
3580 case XML_SCHEMAS_USHORT:
3581 case XML_SCHEMAS_BYTE:
3582 case XML_SCHEMAS_UBYTE:
Daniel Veillard4255d502002-04-16 15:50:10 +00003583 case XML_SCHEMAS_DECIMAL:
Daniel Veillard80b19092003-03-28 13:29:53 +00003584 if (y->type == x->type)
3585 return(xmlSchemaCompareDecimals(x, y));
3586 if ((y->type == XML_SCHEMAS_DECIMAL) ||
3587 (y->type == XML_SCHEMAS_INTEGER) ||
3588 (y->type == XML_SCHEMAS_NPINTEGER) ||
3589 (y->type == XML_SCHEMAS_NINTEGER) ||
3590 (y->type == XML_SCHEMAS_NNINTEGER) ||
3591 (y->type == XML_SCHEMAS_PINTEGER) ||
3592 (y->type == XML_SCHEMAS_INT) ||
3593 (y->type == XML_SCHEMAS_UINT) ||
3594 (y->type == XML_SCHEMAS_LONG) ||
3595 (y->type == XML_SCHEMAS_ULONG) ||
3596 (y->type == XML_SCHEMAS_SHORT) ||
3597 (y->type == XML_SCHEMAS_USHORT) ||
3598 (y->type == XML_SCHEMAS_BYTE) ||
3599 (y->type == XML_SCHEMAS_UBYTE))
Daniel Veillard4255d502002-04-16 15:50:10 +00003600 return(xmlSchemaCompareDecimals(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00003601 return(-2);
Daniel Veillard070803b2002-05-03 07:29:38 +00003602 case XML_SCHEMAS_DURATION:
3603 if (y->type == XML_SCHEMAS_DURATION)
3604 return(xmlSchemaCompareDurations(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00003605 return(-2);
3606 case XML_SCHEMAS_TIME:
3607 case XML_SCHEMAS_GDAY:
3608 case XML_SCHEMAS_GMONTH:
3609 case XML_SCHEMAS_GMONTHDAY:
3610 case XML_SCHEMAS_GYEAR:
3611 case XML_SCHEMAS_GYEARMONTH:
3612 case XML_SCHEMAS_DATE:
3613 case XML_SCHEMAS_DATETIME:
3614 if ((y->type == XML_SCHEMAS_DATETIME) ||
3615 (y->type == XML_SCHEMAS_TIME) ||
3616 (y->type == XML_SCHEMAS_GDAY) ||
3617 (y->type == XML_SCHEMAS_GMONTH) ||
3618 (y->type == XML_SCHEMAS_GMONTHDAY) ||
3619 (y->type == XML_SCHEMAS_GYEAR) ||
3620 (y->type == XML_SCHEMAS_DATE) ||
3621 (y->type == XML_SCHEMAS_GYEARMONTH))
3622 return (xmlSchemaCompareDates(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00003623 return (-2);
Daniel Veillard80b19092003-03-28 13:29:53 +00003624 case XML_SCHEMAS_NORMSTRING:
Daniel Veillard80b19092003-03-28 13:29:53 +00003625 case XML_SCHEMAS_TOKEN:
3626 case XML_SCHEMAS_LANGUAGE:
3627 case XML_SCHEMAS_NMTOKEN:
Daniel Veillard80b19092003-03-28 13:29:53 +00003628 case XML_SCHEMAS_NAME:
Daniel Veillard80b19092003-03-28 13:29:53 +00003629 case XML_SCHEMAS_NCNAME:
3630 case XML_SCHEMAS_ID:
3631 case XML_SCHEMAS_IDREF:
Daniel Veillard80b19092003-03-28 13:29:53 +00003632 case XML_SCHEMAS_ENTITY:
Daniel Veillard80b19092003-03-28 13:29:53 +00003633 case XML_SCHEMAS_NOTATION:
3634 case XML_SCHEMAS_ANYURI:
Daniel Veillardc4c21552003-03-29 10:53:38 +00003635 if ((y->type == XML_SCHEMAS_NORMSTRING) ||
3636 (y->type == XML_SCHEMAS_TOKEN) ||
3637 (y->type == XML_SCHEMAS_LANGUAGE) ||
3638 (y->type == XML_SCHEMAS_NMTOKEN) ||
3639 (y->type == XML_SCHEMAS_NAME) ||
3640 (y->type == XML_SCHEMAS_QNAME) ||
3641 (y->type == XML_SCHEMAS_NCNAME) ||
3642 (y->type == XML_SCHEMAS_ID) ||
3643 (y->type == XML_SCHEMAS_IDREF) ||
3644 (y->type == XML_SCHEMAS_ENTITY) ||
3645 (y->type == XML_SCHEMAS_NOTATION) ||
3646 (y->type == XML_SCHEMAS_ANYURI))
3647 return (xmlSchemaCompareNormStrings(x, y));
3648 return (-2);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003649 case XML_SCHEMAS_QNAME:
3650 if (y->type == XML_SCHEMAS_QNAME) {
3651 if ((xmlStrEqual(x->value.qname.name, y->value.qname.name)) &&
3652 (xmlStrEqual(x->value.qname.uri, y->value.qname.uri)))
3653 return(0);
3654 return(2);
3655 }
3656 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00003657 case XML_SCHEMAS_FLOAT:
3658 case XML_SCHEMAS_DOUBLE:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003659 if ((y->type == XML_SCHEMAS_FLOAT) ||
3660 (y->type == XML_SCHEMAS_DOUBLE))
3661 return (xmlSchemaCompareFloats(x, y));
3662 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00003663 case XML_SCHEMAS_BOOLEAN:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003664 if (y->type == XML_SCHEMAS_BOOLEAN) {
3665 if (x->value.b == y->value.b)
3666 return(0);
3667 if (x->value.b == 0)
3668 return(-1);
3669 return(1);
3670 }
3671 return (-2);
Daniel Veillard560c2a42003-07-06 21:13:49 +00003672 case XML_SCHEMAS_HEXBINARY:
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00003673 if (y->type == XML_SCHEMAS_HEXBINARY) {
3674 if (x->value.hex.total == y->value.hex.total) {
3675 int ret = xmlStrcmp(x->value.hex.str, y->value.hex.str);
3676 if (ret > 0)
3677 return(1);
3678 else if (ret == 0)
3679 return(0);
3680 }
3681 else if (x->value.hex.total > y->value.hex.total)
3682 return(1);
3683
3684 return(-1);
3685 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00003686 return (-2);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003687 case XML_SCHEMAS_BASE64BINARY:
3688 if (y->type == XML_SCHEMAS_BASE64BINARY) {
3689 if (x->value.base64.total == y->value.base64.total) {
3690 int ret = xmlStrcmp(x->value.base64.str,
3691 y->value.base64.str);
3692 if (ret > 0)
3693 return(1);
3694 else if (ret == 0)
3695 return(0);
3696 }
3697 else if (x->value.base64.total > y->value.base64.total)
3698 return(1);
3699 else
3700 return(-1);
3701 }
3702 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00003703 case XML_SCHEMAS_STRING:
3704 case XML_SCHEMAS_IDREFS:
3705 case XML_SCHEMAS_ENTITIES:
3706 case XML_SCHEMAS_NMTOKENS:
3707 TODO
3708 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00003709 }
Daniel Veillard5a872412002-05-22 06:40:27 +00003710 return -2;
Daniel Veillard4255d502002-04-16 15:50:10 +00003711}
3712
3713/**
Daniel Veillardc4c21552003-03-29 10:53:38 +00003714 * xmlSchemaNormLen:
3715 * @value: a string
3716 *
3717 * Computes the UTF8 length of the normalized value of the string
3718 *
3719 * Returns the length or -1 in case of error.
3720 */
3721static int
3722xmlSchemaNormLen(const xmlChar *value) {
3723 const xmlChar *utf;
3724 int ret = 0;
3725
3726 if (value == NULL)
3727 return(-1);
3728 utf = value;
William M. Brack76e95df2003-10-18 16:20:14 +00003729 while (IS_BLANK_CH(*utf)) utf++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003730 while (*utf != 0) {
3731 if (utf[0] & 0x80) {
3732 if ((utf[1] & 0xc0) != 0x80)
3733 return(-1);
3734 if ((utf[0] & 0xe0) == 0xe0) {
3735 if ((utf[2] & 0xc0) != 0x80)
3736 return(-1);
3737 if ((utf[0] & 0xf0) == 0xf0) {
3738 if ((utf[0] & 0xf8) != 0xf0 || (utf[3] & 0xc0) != 0x80)
3739 return(-1);
3740 utf += 4;
3741 } else {
3742 utf += 3;
3743 }
3744 } else {
3745 utf += 2;
3746 }
William M. Brack76e95df2003-10-18 16:20:14 +00003747 } else if (IS_BLANK_CH(*utf)) {
3748 while (IS_BLANK_CH(*utf)) utf++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003749 if (*utf == 0)
3750 break;
3751 } else {
3752 utf++;
3753 }
3754 ret++;
3755 }
3756 return(ret);
3757}
3758
Daniel Veillard6927b102004-10-27 17:29:04 +00003759/**
3760 * xmlSchemaGetFacetValueAsULong:
3761 * @facet: an schemas type facet
3762 *
3763 * Extract the value of a facet
3764 *
3765 * Returns the value as a long
3766 */
Daniel Veillardc0826a72004-08-10 14:17:33 +00003767unsigned long
3768xmlSchemaGetFacetValueAsULong(xmlSchemaFacetPtr facet)
3769{
3770 /*
3771 * TODO: Check if this is a decimal.
3772 */
3773 return ((unsigned long) facet->val->value.decimal.lo);
3774}
3775
Daniel Veillardc4c21552003-03-29 10:53:38 +00003776/**
Daniel Veillard01fa6152004-06-29 17:04:39 +00003777 * xmlSchemaValidateListSimpleTypeFacet:
3778 * @facet: the facet to check
3779 * @value: the lexical repr of the value to validate
3780 * @actualLen: the number of list items
3781 * @expectedLen: the resulting expected number of list items
3782 *
3783 * Checks the value of a list simple type against a facet.
3784 *
3785 * Returns 0 if the value is valid, a positive error code
3786 * number otherwise and -1 in case of an internal error.
3787 */
3788int
3789xmlSchemaValidateListSimpleTypeFacet(xmlSchemaFacetPtr facet,
3790 const xmlChar *value,
3791 unsigned long actualLen,
3792 unsigned long *expectedLen)
3793{
Daniel Veillardce682bc2004-11-05 17:22:25 +00003794 if (facet == NULL)
3795 return(-1);
Daniel Veillard01fa6152004-06-29 17:04:39 +00003796 /*
3797 * TODO: Check if this will work with large numbers.
3798 * (compare value.decimal.mi and value.decimal.hi as well?).
3799 */
3800 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
3801 if (actualLen != facet->val->value.decimal.lo) {
Daniel Veillardc0826a72004-08-10 14:17:33 +00003802 if (expectedLen != 0)
3803 *expectedLen = facet->val->value.decimal.lo;
Daniel Veillard01fa6152004-06-29 17:04:39 +00003804 return (XML_SCHEMAV_CVC_LENGTH_VALID);
3805 }
3806 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
3807 if (actualLen < facet->val->value.decimal.lo) {
Daniel Veillardc0826a72004-08-10 14:17:33 +00003808 if (expectedLen != 0)
3809 *expectedLen = facet->val->value.decimal.lo;
Daniel Veillard01fa6152004-06-29 17:04:39 +00003810 return (XML_SCHEMAV_CVC_MINLENGTH_VALID);
3811 }
3812 } else if (facet->type == XML_SCHEMA_FACET_MAXLENGTH) {
3813 if (actualLen > facet->val->value.decimal.lo) {
Daniel Veillardc0826a72004-08-10 14:17:33 +00003814 if (expectedLen != 0)
3815 *expectedLen = facet->val->value.decimal.lo;
Daniel Veillard01fa6152004-06-29 17:04:39 +00003816 return (XML_SCHEMAV_CVC_MAXLENGTH_VALID);
3817 }
3818 } else
3819 /*
3820 * NOTE: That we can pass NULL as xmlSchemaValPtr to
3821 * xmlSchemaValidateFacet, since the remaining facet types
3822 * are: XML_SCHEMA_FACET_PATTERN, XML_SCHEMA_FACET_ENUMERATION.
3823 */
3824 return(xmlSchemaValidateFacet(NULL, facet, value, NULL));
3825 return (0);
3826}
3827
3828/**
Daniel Veillard6927b102004-10-27 17:29:04 +00003829 * xmlSchemaValidateLengthFacet:
Daniel Veillardc0826a72004-08-10 14:17:33 +00003830 * @type: the built-in type
3831 * @facet: the facet to check
3832 * @value: the lexical repr. of the value to be validated
3833 * @val: the precomputed value
3834 * @length: the actual length of the value
3835 *
3836 * Checka a value against a "length", "minLength" and "maxLength"
3837 * facet; sets @length to the computed length of @value.
3838 *
3839 * Returns 0 if the value is valid, a positive error code
3840 * otherwise and -1 in case of an internal or API error.
3841 */
3842int
3843xmlSchemaValidateLengthFacet(xmlSchemaTypePtr type,
3844 xmlSchemaFacetPtr facet,
3845 const xmlChar *value,
3846 xmlSchemaValPtr val,
3847 unsigned long *length)
3848{
3849 unsigned int len = 0;
3850
Daniel Veillardce682bc2004-11-05 17:22:25 +00003851 if ((length == NULL) || (facet == NULL) || (type == NULL))
3852 return (-1);
Daniel Veillardc0826a72004-08-10 14:17:33 +00003853 *length = 0;
3854 if ((facet->type != XML_SCHEMA_FACET_LENGTH) &&
3855 (facet->type != XML_SCHEMA_FACET_MAXLENGTH) &&
3856 (facet->type != XML_SCHEMA_FACET_MINLENGTH))
3857 return (-1);
3858
3859 if ((facet->val == NULL) ||
3860 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
3861 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
3862 (facet->val->value.decimal.frac != 0)) {
3863 return(-1);
3864 }
3865 if ((val != NULL) && (val->type == XML_SCHEMAS_HEXBINARY))
3866 len = val->value.hex.total;
3867 else if ((val != NULL) && (val->type == XML_SCHEMAS_BASE64BINARY))
3868 len = val->value.base64.total;
3869 else {
3870 switch (type->builtInType) {
3871 case XML_SCHEMAS_IDREF:
3872 case XML_SCHEMAS_NORMSTRING:
3873 case XML_SCHEMAS_TOKEN:
3874 case XML_SCHEMAS_LANGUAGE:
3875 case XML_SCHEMAS_NMTOKEN:
3876 case XML_SCHEMAS_NAME:
3877 case XML_SCHEMAS_NCNAME:
3878 case XML_SCHEMAS_ID:
3879 len = xmlSchemaNormLen(value);
3880 break;
3881 case XML_SCHEMAS_STRING:
3882 /*
3883 * FIXME: What exactly to do with anyURI?
3884 */
3885 case XML_SCHEMAS_ANYURI:
3886 if (value != NULL)
3887 len = xmlUTF8Strlen(value);
3888 break;
3889 default:
3890 TODO
3891 }
3892 }
3893 *length = (unsigned long) len;
3894 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
3895 if (len != facet->val->value.decimal.lo)
3896 return(XML_SCHEMAV_CVC_LENGTH_VALID);
3897 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
3898 if (len < facet->val->value.decimal.lo)
3899 return(XML_SCHEMAV_CVC_MINLENGTH_VALID);
3900 } else {
3901 if (len > facet->val->value.decimal.lo)
3902 return(XML_SCHEMAV_CVC_MAXLENGTH_VALID);
3903 }
3904
3905 return (0);
3906}
3907
3908/**
3909 * xmlSchemaValidateFacet:
Daniel Veillard01c13b52002-12-10 15:19:08 +00003910 * @base: the base type
Daniel Veillard4255d502002-04-16 15:50:10 +00003911 * @facet: the facet to check
3912 * @value: the lexical repr of the value to validate
3913 * @val: the precomputed value
3914 *
3915 * Check a value against a facet condition
3916 *
3917 * Returns 0 if the element is schemas valid, a positive error code
3918 * number otherwise and -1 in case of internal or API error.
3919 */
3920int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00003921xmlSchemaValidateFacet(xmlSchemaTypePtr base ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +00003922 xmlSchemaFacetPtr facet,
Daniel Veillard4255d502002-04-16 15:50:10 +00003923 const xmlChar *value, xmlSchemaValPtr val)
3924{
3925 int ret;
3926
Daniel Veillardce682bc2004-11-05 17:22:25 +00003927 if ((facet == NULL) || (value == NULL))
3928 return(-1);
Daniel Veillard4255d502002-04-16 15:50:10 +00003929 switch (facet->type) {
3930 case XML_SCHEMA_FACET_PATTERN:
3931 ret = xmlRegexpExec(facet->regexp, value);
3932 if (ret == 1)
3933 return(0);
3934 if (ret == 0) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00003935 return(XML_SCHEMAV_CVC_PATTERN_VALID);
Daniel Veillard4255d502002-04-16 15:50:10 +00003936 }
3937 return(ret);
3938 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
3939 ret = xmlSchemaCompareValues(val, facet->val);
3940 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003941 /* TODO error code */
Daniel Veillard4255d502002-04-16 15:50:10 +00003942 return(-1);
3943 }
3944 if (ret == -1)
3945 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00003946 /* error code */
Daniel Veillard01fa6152004-06-29 17:04:39 +00003947 return(XML_SCHEMAV_CVC_MAXEXCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00003948 case XML_SCHEMA_FACET_MAXINCLUSIVE:
3949 ret = xmlSchemaCompareValues(val, facet->val);
3950 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003951 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00003952 return(-1);
3953 }
3954 if ((ret == -1) || (ret == 0))
3955 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00003956 /* error code */
Daniel Veillard01fa6152004-06-29 17:04:39 +00003957 return(XML_SCHEMAV_CVC_MAXINCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00003958 case XML_SCHEMA_FACET_MINEXCLUSIVE:
3959 ret = xmlSchemaCompareValues(val, facet->val);
3960 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003961 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00003962 return(-1);
3963 }
3964 if (ret == 1)
3965 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00003966 /* error code */
Daniel Veillard01fa6152004-06-29 17:04:39 +00003967 return(XML_SCHEMAV_CVC_MINEXCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00003968 case XML_SCHEMA_FACET_MININCLUSIVE:
3969 ret = xmlSchemaCompareValues(val, facet->val);
3970 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003971 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00003972 return(-1);
3973 }
3974 if ((ret == 1) || (ret == 0))
3975 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00003976 /* error code */
Daniel Veillard01fa6152004-06-29 17:04:39 +00003977 return(XML_SCHEMAV_CVC_MININCLUSIVE_VALID);
Daniel Veillard8651f532002-04-17 09:06:27 +00003978 case XML_SCHEMA_FACET_WHITESPACE:
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003979 /* TODO whitespaces */
Daniel Veillard01fa6152004-06-29 17:04:39 +00003980 /*
3981 * NOTE: Whitespace should be handled to normalize
3982 * the value to be validated against a the facets;
3983 * not to normalize the value in-between.
3984 */
Daniel Veillard8651f532002-04-17 09:06:27 +00003985 return(0);
Daniel Veillard88c58912002-04-23 07:12:20 +00003986 case XML_SCHEMA_FACET_ENUMERATION:
3987 if ((facet->value != NULL) &&
3988 (xmlStrEqual(facet->value, value)))
3989 return(0);
Daniel Veillard01fa6152004-06-29 17:04:39 +00003990 return(XML_SCHEMAV_CVC_ENUMERATION_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003991 case XML_SCHEMA_FACET_LENGTH:
3992 case XML_SCHEMA_FACET_MAXLENGTH:
3993 case XML_SCHEMA_FACET_MINLENGTH: {
3994 unsigned int len = 0;
3995
3996 if ((facet->val == NULL) ||
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003997 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
3998 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003999 (facet->val->value.decimal.frac != 0)) {
4000 return(-1);
4001 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00004002 if ((val != NULL) && (val->type == XML_SCHEMAS_HEXBINARY))
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004003 len = val->value.hex.total;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00004004 else if ((val != NULL) && (val->type == XML_SCHEMAS_BASE64BINARY))
4005 len = val->value.base64.total;
4006 else {
Daniel Veillard01fa6152004-06-29 17:04:39 +00004007 switch (base->builtInType) {
Daniel Veillard560c2a42003-07-06 21:13:49 +00004008 case XML_SCHEMAS_IDREF:
4009 case XML_SCHEMAS_NORMSTRING:
4010 case XML_SCHEMAS_TOKEN:
4011 case XML_SCHEMAS_LANGUAGE:
4012 case XML_SCHEMAS_NMTOKEN:
4013 case XML_SCHEMAS_NAME:
4014 case XML_SCHEMAS_NCNAME:
4015 case XML_SCHEMAS_ID:
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004016 len = xmlSchemaNormLen(value);
4017 break;
Daniel Veillard560c2a42003-07-06 21:13:49 +00004018 case XML_SCHEMAS_STRING:
Daniel Veillard01fa6152004-06-29 17:04:39 +00004019 /*
4020 * FIXME: What exactly to do with anyURI?
4021 */
4022 case XML_SCHEMAS_ANYURI:
William M. Brackfbf2c5e2004-02-03 17:55:56 +00004023 if (value != NULL)
4024 len = xmlUTF8Strlen(value);
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004025 break;
Daniel Veillard560c2a42003-07-06 21:13:49 +00004026 default:
4027 TODO
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004028 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004029 }
4030 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004031 if (len != facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004032 return(XML_SCHEMAV_CVC_LENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004033 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004034 if (len < facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004035 return(XML_SCHEMAV_CVC_MINLENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004036 } else {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004037 if (len > facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004038 return(XML_SCHEMAV_CVC_MAXLENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004039 }
4040 break;
4041 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00004042 case XML_SCHEMA_FACET_TOTALDIGITS:
4043 case XML_SCHEMA_FACET_FRACTIONDIGITS:
4044
4045 if ((facet->val == NULL) ||
4046 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
4047 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
4048 (facet->val->value.decimal.frac != 0)) {
4049 return(-1);
4050 }
4051 if ((val == NULL) ||
4052 ((val->type != XML_SCHEMAS_DECIMAL) &&
4053 (val->type != XML_SCHEMAS_INTEGER) &&
4054 (val->type != XML_SCHEMAS_NPINTEGER) &&
4055 (val->type != XML_SCHEMAS_NINTEGER) &&
4056 (val->type != XML_SCHEMAS_NNINTEGER) &&
4057 (val->type != XML_SCHEMAS_PINTEGER) &&
4058 (val->type != XML_SCHEMAS_INT) &&
4059 (val->type != XML_SCHEMAS_UINT) &&
4060 (val->type != XML_SCHEMAS_LONG) &&
4061 (val->type != XML_SCHEMAS_ULONG) &&
4062 (val->type != XML_SCHEMAS_SHORT) &&
4063 (val->type != XML_SCHEMAS_USHORT) &&
4064 (val->type != XML_SCHEMAS_BYTE) &&
4065 (val->type != XML_SCHEMAS_UBYTE))) {
4066 return(-1);
4067 }
4068 if (facet->type == XML_SCHEMA_FACET_TOTALDIGITS) {
4069 if (val->value.decimal.total > facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004070 return(XML_SCHEMAV_CVC_TOTALDIGITS_VALID);
Daniel Veillard560c2a42003-07-06 21:13:49 +00004071
4072 } else if (facet->type == XML_SCHEMA_FACET_FRACTIONDIGITS) {
4073 if (val->value.decimal.frac > facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004074 return(XML_SCHEMAV_CVC_FRACTIONDIGITS_VALID);
Daniel Veillard560c2a42003-07-06 21:13:49 +00004075 }
4076 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00004077 default:
4078 TODO
4079 }
4080 return(0);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00004081
Daniel Veillard4255d502002-04-16 15:50:10 +00004082}
4083
4084#endif /* LIBXML_SCHEMAS_ENABLED */