blob: c5a0342755d3786de11f2caeed82900741437362 [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 Veillardc0826a72004-08-10 14:17:33 +0000460 * xmlSchemaGetBuiltInType:
Daniel Veillard01fa6152004-06-29 17:04:39 +0000461 * @type: the built-in type
462 * @facetType: the facet type
463 *
464 * Evaluates if a specific facet can be
465 * used in conjunction with a type.
466 *
467 * Returns 1 if the facet can be used with the given built-in type,
468 * 0 otherwise and -1 in case the type is not a built-in type.
469 */
470int
471xmlSchemaIsBuiltInTypeFacet(xmlSchemaTypePtr type, int facetType)
472{
473 if (type->type != XML_SCHEMA_TYPE_BASIC)
474 return (-1);
475 switch (type->builtInType) {
476 case XML_SCHEMAS_BOOLEAN:
477 if ((facetType == XML_SCHEMA_FACET_PATTERN) ||
478 (facetType == XML_SCHEMA_FACET_WHITESPACE))
479 return (1);
480 else
481 return (0);
482 case XML_SCHEMAS_STRING:
483 case XML_SCHEMAS_NOTATION:
484 case XML_SCHEMAS_QNAME:
485 case XML_SCHEMAS_ANYURI:
486 case XML_SCHEMAS_BASE64BINARY:
487 case XML_SCHEMAS_HEXBINARY:
488 if ((facetType == XML_SCHEMA_FACET_LENGTH) ||
489 (facetType == XML_SCHEMA_FACET_MINLENGTH) ||
490 (facetType == XML_SCHEMA_FACET_MAXLENGTH) ||
491 (facetType == XML_SCHEMA_FACET_PATTERN) ||
492 (facetType == XML_SCHEMA_FACET_ENUMERATION) ||
493 (facetType == XML_SCHEMA_FACET_WHITESPACE))
494 return (1);
495 else
496 return (0);
497 case XML_SCHEMAS_DECIMAL:
498 if ((facetType == XML_SCHEMA_FACET_TOTALDIGITS) ||
499 (facetType == XML_SCHEMA_FACET_FRACTIONDIGITS) ||
500 (facetType == XML_SCHEMA_FACET_PATTERN) ||
501 (facetType == XML_SCHEMA_FACET_WHITESPACE) ||
502 (facetType == XML_SCHEMA_FACET_ENUMERATION) ||
503 (facetType == XML_SCHEMA_FACET_MAXINCLUSIVE) ||
504 (facetType == XML_SCHEMA_FACET_MAXEXCLUSIVE) ||
505 (facetType == XML_SCHEMA_FACET_MININCLUSIVE) ||
506 (facetType == XML_SCHEMA_FACET_MINEXCLUSIVE))
507 return (1);
508 else
509 return (0);
510 case XML_SCHEMAS_TIME:
511 case XML_SCHEMAS_GDAY:
512 case XML_SCHEMAS_GMONTH:
513 case XML_SCHEMAS_GMONTHDAY:
514 case XML_SCHEMAS_GYEAR:
515 case XML_SCHEMAS_GYEARMONTH:
516 case XML_SCHEMAS_DATE:
517 case XML_SCHEMAS_DATETIME:
518 case XML_SCHEMAS_DURATION:
519 case XML_SCHEMAS_FLOAT:
520 case XML_SCHEMAS_DOUBLE:
521 if ((facetType == XML_SCHEMA_FACET_PATTERN) ||
522 (facetType == XML_SCHEMA_FACET_ENUMERATION) ||
523 (facetType == XML_SCHEMA_FACET_WHITESPACE) ||
524 (facetType == XML_SCHEMA_FACET_MAXINCLUSIVE) ||
525 (facetType == XML_SCHEMA_FACET_MAXEXCLUSIVE) ||
526 (facetType == XML_SCHEMA_FACET_MININCLUSIVE) ||
527 (facetType == XML_SCHEMA_FACET_MINEXCLUSIVE))
528 return (1);
529 else
530 return (0);
531 default:
Daniel Veillardc7e3cc42004-09-28 12:33:52 +0000532 break;
Daniel Veillard01fa6152004-06-29 17:04:39 +0000533 }
534 return (0);
535}
536
537/**
538 * xmlSchemaGetBuiltInType:
539 * @type: the type of the built in type
540 *
541 * Gives you the type struct for a built-in
542 * type by its type id.
543 *
544 * Returns the type if found, NULL otherwise.
545 */
546xmlSchemaTypePtr
547xmlSchemaGetBuiltInType(xmlSchemaValType type)
548{
549 if (xmlSchemaTypesInitialized == 0)
550 xmlSchemaInitTypes();
551 switch (type) {
552
553 case XML_SCHEMAS_ANYSIMPLETYPE:
554 return (xmlSchemaTypeAnySimpleTypeDef);
555 case XML_SCHEMAS_STRING:
556 return (xmlSchemaTypeStringDef);
557 case XML_SCHEMAS_NORMSTRING:
558 return (xmlSchemaTypeNormStringDef);
559 case XML_SCHEMAS_DECIMAL:
560 return (xmlSchemaTypeDecimalDef);
561 case XML_SCHEMAS_TIME:
562 return (xmlSchemaTypeTimeDef);
563 case XML_SCHEMAS_GDAY:
564 return (xmlSchemaTypeGDayDef);
565 case XML_SCHEMAS_GMONTH:
566 return (xmlSchemaTypeGMonthDef);
567 case XML_SCHEMAS_GMONTHDAY:
568 return (xmlSchemaTypeGMonthDayDef);
569 case XML_SCHEMAS_GYEAR:
570 return (xmlSchemaTypeGYearDef);
571 case XML_SCHEMAS_GYEARMONTH:
572 return (xmlSchemaTypeGYearMonthDef);
573 case XML_SCHEMAS_DATE:
574 return (xmlSchemaTypeDateDef);
575 case XML_SCHEMAS_DATETIME:
576 return (xmlSchemaTypeDatetimeDef);
577 case XML_SCHEMAS_DURATION:
578 return (xmlSchemaTypeDurationDef);
579 case XML_SCHEMAS_FLOAT:
580 return (xmlSchemaTypeFloatDef);
581 case XML_SCHEMAS_DOUBLE:
582 return (xmlSchemaTypeDoubleDef);
583 case XML_SCHEMAS_BOOLEAN:
584 return (xmlSchemaTypeBooleanDef);
585 case XML_SCHEMAS_TOKEN:
586 return (xmlSchemaTypeTokenDef);
587 case XML_SCHEMAS_LANGUAGE:
588 return (xmlSchemaTypeLanguageDef);
589 case XML_SCHEMAS_NMTOKEN:
590 return (xmlSchemaTypeNmtokenDef);
591 case XML_SCHEMAS_NMTOKENS:
592 return (xmlSchemaTypeNmtokensDef);
593 case XML_SCHEMAS_NAME:
594 return (xmlSchemaTypeNameDef);
595 case XML_SCHEMAS_QNAME:
596 return (xmlSchemaTypeQNameDef);
597 case XML_SCHEMAS_NCNAME:
598 return (xmlSchemaTypeNCNameDef);
599 case XML_SCHEMAS_ID:
600 return (xmlSchemaTypeIdDef);
601 case XML_SCHEMAS_IDREF:
602 return (xmlSchemaTypeIdrefDef);
603 case XML_SCHEMAS_IDREFS:
604 return (xmlSchemaTypeIdrefsDef);
605 case XML_SCHEMAS_ENTITY:
606 return (xmlSchemaTypeEntityDef);
607 case XML_SCHEMAS_ENTITIES:
608 return (xmlSchemaTypeEntitiesDef);
609 case XML_SCHEMAS_NOTATION:
610 return (xmlSchemaTypeNotationDef);
611 case XML_SCHEMAS_ANYURI:
612 return (xmlSchemaTypeAnyURIDef);
613 case XML_SCHEMAS_INTEGER:
614 return (xmlSchemaTypeIntegerDef);
615 case XML_SCHEMAS_NPINTEGER:
616 return (xmlSchemaTypeNonPositiveIntegerDef);
617 case XML_SCHEMAS_NINTEGER:
618 return (xmlSchemaTypeNegativeIntegerDef);
619 case XML_SCHEMAS_NNINTEGER:
620 return (xmlSchemaTypeNonNegativeIntegerDef);
621 case XML_SCHEMAS_PINTEGER:
622 return (xmlSchemaTypePositiveIntegerDef);
623 case XML_SCHEMAS_INT:
624 return (xmlSchemaTypeIntDef);
625 case XML_SCHEMAS_UINT:
626 return (xmlSchemaTypeUnsignedIntDef);
627 case XML_SCHEMAS_LONG:
628 return (xmlSchemaTypeLongDef);
629 case XML_SCHEMAS_ULONG:
630 return (xmlSchemaTypeUnsignedLongDef);
631 case XML_SCHEMAS_SHORT:
632 return (xmlSchemaTypeShortDef);
633 case XML_SCHEMAS_USHORT:
634 return (xmlSchemaTypeUnsignedShortDef);
635 case XML_SCHEMAS_BYTE:
636 return (xmlSchemaTypeByteDef);
637 case XML_SCHEMAS_UBYTE:
638 return (xmlSchemaTypeUnsignedByteDef);
639 case XML_SCHEMAS_HEXBINARY:
640 return (xmlSchemaTypeHexBinaryDef);
641 case XML_SCHEMAS_BASE64BINARY:
642 return (xmlSchemaTypeBase64BinaryDef);
643 case XML_SCHEMAS_ANYTYPE:
644 return (xmlSchemaTypeAnyTypeDef);
645 default:
646 return (NULL);
647 }
648}
649
650/**
Daniel Veillard4255d502002-04-16 15:50:10 +0000651 * xmlSchemaNewValue:
652 * @type: the value type
653 *
654 * Allocate a new simple type value
655 *
656 * Returns a pointer to the new value or NULL in case of error
657 */
658static xmlSchemaValPtr
659xmlSchemaNewValue(xmlSchemaValType type) {
660 xmlSchemaValPtr value;
661
662 value = (xmlSchemaValPtr) xmlMalloc(sizeof(xmlSchemaVal));
663 if (value == NULL) {
664 return(NULL);
665 }
666 memset(value, 0, sizeof(xmlSchemaVal));
667 value->type = type;
668 return(value);
669}
670
671/**
672 * xmlSchemaFreeValue:
673 * @value: the value to free
674 *
675 * Cleanup the default XML Schemas type library
676 */
677void
678xmlSchemaFreeValue(xmlSchemaValPtr value) {
679 if (value == NULL)
680 return;
Daniel Veillardc4c21552003-03-29 10:53:38 +0000681 switch (value->type) {
682 case XML_SCHEMAS_STRING:
683 case XML_SCHEMAS_NORMSTRING:
684 case XML_SCHEMAS_TOKEN:
685 case XML_SCHEMAS_LANGUAGE:
686 case XML_SCHEMAS_NMTOKEN:
687 case XML_SCHEMAS_NMTOKENS:
688 case XML_SCHEMAS_NAME:
Daniel Veillardc4c21552003-03-29 10:53:38 +0000689 case XML_SCHEMAS_NCNAME:
690 case XML_SCHEMAS_ID:
691 case XML_SCHEMAS_IDREF:
692 case XML_SCHEMAS_IDREFS:
693 case XML_SCHEMAS_ENTITY:
694 case XML_SCHEMAS_ENTITIES:
695 case XML_SCHEMAS_NOTATION:
696 case XML_SCHEMAS_ANYURI:
697 if (value->value.str != NULL)
698 xmlFree(value->value.str);
699 break;
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000700 case XML_SCHEMAS_QNAME:
701 if (value->value.qname.uri != NULL)
702 xmlFree(value->value.qname.uri);
703 if (value->value.qname.name != NULL)
704 xmlFree(value->value.qname.name);
705 break;
Daniel Veillard70bcb0e2003-08-08 14:00:28 +0000706 case XML_SCHEMAS_HEXBINARY:
707 if (value->value.hex.str != NULL)
708 xmlFree(value->value.hex.str);
709 break;
Daniel Veillard1ac24d32003-08-27 14:15:15 +0000710 case XML_SCHEMAS_BASE64BINARY:
711 if (value->value.base64.str != NULL)
712 xmlFree(value->value.base64.str);
713 break;
Daniel Veillardc4c21552003-03-29 10:53:38 +0000714 default:
715 break;
716 }
Daniel Veillard4255d502002-04-16 15:50:10 +0000717 xmlFree(value);
718}
719
720/**
721 * xmlSchemaGetPredefinedType:
722 * @name: the type name
723 * @ns: the URI of the namespace usually "http://www.w3.org/2001/XMLSchema"
724 *
725 * Lookup a type in the default XML Schemas type library
726 *
727 * Returns the type if found, NULL otherwise
728 */
729xmlSchemaTypePtr
730xmlSchemaGetPredefinedType(const xmlChar *name, const xmlChar *ns) {
731 if (xmlSchemaTypesInitialized == 0)
732 xmlSchemaInitTypes();
733 if (name == NULL)
734 return(NULL);
735 return((xmlSchemaTypePtr) xmlHashLookup2(xmlSchemaTypesBank, name, ns));
736}
Daniel Veillard070803b2002-05-03 07:29:38 +0000737
Daniel Veillard01fa6152004-06-29 17:04:39 +0000738/**
739 * xmlSchemaGetBuiltInListSimpleTypeItemType:
740 * @type: the built-in simple type.
741 *
Daniel Veillardc0826a72004-08-10 14:17:33 +0000742 * Returns the item type of @type as defined by the built-in datatype
743 * hierarchy of XML Schema Part 2: Datatypes, or NULL in case of an error.
Daniel Veillard01fa6152004-06-29 17:04:39 +0000744 */
745xmlSchemaTypePtr
746xmlSchemaGetBuiltInListSimpleTypeItemType(xmlSchemaTypePtr type)
747{
748 if (type->type != XML_SCHEMA_TYPE_BASIC)
749 return (NULL);
750 switch (type->builtInType) {
751 case XML_SCHEMAS_NMTOKENS:
752 return (xmlSchemaTypeNmtokenDef );
753 case XML_SCHEMAS_IDREFS:
754 return (xmlSchemaTypeIdrefDef);
755 case XML_SCHEMAS_ENTITIES:
756 return (xmlSchemaTypeEntityDef);
757 default:
758 return (NULL);
759 }
760}
761
Daniel Veillard070803b2002-05-03 07:29:38 +0000762/****************************************************************
763 * *
764 * Convenience macros and functions *
765 * *
766 ****************************************************************/
767
768#define IS_TZO_CHAR(c) \
769 ((c == 0) || (c == 'Z') || (c == '+') || (c == '-'))
770
771#define VALID_YEAR(yr) (yr != 0)
772#define VALID_MONTH(mon) ((mon >= 1) && (mon <= 12))
773/* VALID_DAY should only be used when month is unknown */
774#define VALID_DAY(day) ((day >= 1) && (day <= 31))
775#define VALID_HOUR(hr) ((hr >= 0) && (hr <= 23))
776#define VALID_MIN(min) ((min >= 0) && (min <= 59))
777#define VALID_SEC(sec) ((sec >= 0) && (sec < 60))
778#define VALID_TZO(tzo) ((tzo > -1440) && (tzo < 1440))
779#define IS_LEAP(y) \
780 (((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0))
781
Daniel Veillardebe25d42004-03-25 09:35:49 +0000782static const unsigned int daysInMonth[12] =
Daniel Veillard070803b2002-05-03 07:29:38 +0000783 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
Daniel Veillardebe25d42004-03-25 09:35:49 +0000784static const unsigned int daysInMonthLeap[12] =
Daniel Veillard070803b2002-05-03 07:29:38 +0000785 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
786
Daniel Veillard5a872412002-05-22 06:40:27 +0000787#define MAX_DAYINMONTH(yr,mon) \
788 (IS_LEAP(yr) ? daysInMonthLeap[mon - 1] : daysInMonth[mon - 1])
789
Daniel Veillard070803b2002-05-03 07:29:38 +0000790#define VALID_MDAY(dt) \
791 (IS_LEAP(dt->year) ? \
792 (dt->day <= daysInMonthLeap[dt->mon - 1]) : \
793 (dt->day <= daysInMonth[dt->mon - 1]))
794
795#define VALID_DATE(dt) \
796 (VALID_YEAR(dt->year) && VALID_MONTH(dt->mon) && VALID_MDAY(dt))
797
798#define VALID_TIME(dt) \
799 (VALID_HOUR(dt->hour) && VALID_MIN(dt->min) && \
800 VALID_SEC(dt->sec) && VALID_TZO(dt->tzo))
801
802#define VALID_DATETIME(dt) \
803 (VALID_DATE(dt) && VALID_TIME(dt))
804
805#define SECS_PER_MIN (60)
806#define SECS_PER_HOUR (60 * SECS_PER_MIN)
807#define SECS_PER_DAY (24 * SECS_PER_HOUR)
808
Daniel Veillard5a872412002-05-22 06:40:27 +0000809static const long dayInYearByMonth[12] =
810 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
811static const long dayInLeapYearByMonth[12] =
812 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 };
813
814#define DAY_IN_YEAR(day, month, year) \
815 ((IS_LEAP(year) ? \
816 dayInLeapYearByMonth[month - 1] : \
817 dayInYearByMonth[month - 1]) + day)
818
819#ifdef DEBUG
820#define DEBUG_DATE(dt) \
821 xmlGenericError(xmlGenericErrorContext, \
822 "type=%o %04ld-%02u-%02uT%02u:%02u:%03f", \
823 dt->type,dt->value.date.year,dt->value.date.mon, \
824 dt->value.date.day,dt->value.date.hour,dt->value.date.min, \
825 dt->value.date.sec); \
826 if (dt->value.date.tz_flag) \
827 if (dt->value.date.tzo != 0) \
828 xmlGenericError(xmlGenericErrorContext, \
829 "%+05d\n",dt->value.date.tzo); \
830 else \
831 xmlGenericError(xmlGenericErrorContext, "Z\n"); \
832 else \
833 xmlGenericError(xmlGenericErrorContext,"\n")
834#else
835#define DEBUG_DATE(dt)
836#endif
837
Daniel Veillard070803b2002-05-03 07:29:38 +0000838/**
839 * _xmlSchemaParseGYear:
840 * @dt: pointer to a date structure
841 * @str: pointer to the string to analyze
842 *
843 * Parses a xs:gYear without time zone and fills in the appropriate
844 * field of the @dt structure. @str is updated to point just after the
845 * xs:gYear. It is supposed that @dt->year is big enough to contain
846 * the year.
847 *
848 * Returns 0 or the error code
849 */
850static int
851_xmlSchemaParseGYear (xmlSchemaValDatePtr dt, const xmlChar **str) {
852 const xmlChar *cur = *str, *firstChar;
853 int isneg = 0, digcnt = 0;
854
855 if (((*cur < '0') || (*cur > '9')) &&
856 (*cur != '-') && (*cur != '+'))
857 return -1;
858
859 if (*cur == '-') {
860 isneg = 1;
861 cur++;
862 }
863
864 firstChar = cur;
865
866 while ((*cur >= '0') && (*cur <= '9')) {
867 dt->year = dt->year * 10 + (*cur - '0');
868 cur++;
869 digcnt++;
870 }
871
872 /* year must be at least 4 digits (CCYY); over 4
873 * digits cannot have a leading zero. */
874 if ((digcnt < 4) || ((digcnt > 4) && (*firstChar == '0')))
875 return 1;
876
877 if (isneg)
878 dt->year = - dt->year;
879
880 if (!VALID_YEAR(dt->year))
881 return 2;
882
883 *str = cur;
884 return 0;
885}
886
887/**
888 * PARSE_2_DIGITS:
889 * @num: the integer to fill in
890 * @cur: an #xmlChar *
891 * @invalid: an integer
892 *
893 * Parses a 2-digits integer and updates @num with the value. @cur is
894 * updated to point just after the integer.
895 * In case of error, @invalid is set to %TRUE, values of @num and
896 * @cur are undefined.
897 */
898#define PARSE_2_DIGITS(num, cur, invalid) \
899 if ((cur[0] < '0') || (cur[0] > '9') || \
900 (cur[1] < '0') || (cur[1] > '9')) \
901 invalid = 1; \
902 else \
903 num = (cur[0] - '0') * 10 + (cur[1] - '0'); \
904 cur += 2;
905
906/**
907 * PARSE_FLOAT:
908 * @num: the double to fill in
909 * @cur: an #xmlChar *
910 * @invalid: an integer
911 *
912 * Parses a float and updates @num with the value. @cur is
913 * updated to point just after the float. The float must have a
914 * 2-digits integer part and may or may not have a decimal part.
915 * In case of error, @invalid is set to %TRUE, values of @num and
916 * @cur are undefined.
917 */
918#define PARSE_FLOAT(num, cur, invalid) \
919 PARSE_2_DIGITS(num, cur, invalid); \
920 if (!invalid && (*cur == '.')) { \
921 double mult = 1; \
922 cur++; \
923 if ((*cur < '0') || (*cur > '9')) \
924 invalid = 1; \
925 while ((*cur >= '0') && (*cur <= '9')) { \
926 mult /= 10; \
927 num += (*cur - '0') * mult; \
928 cur++; \
929 } \
930 }
931
932/**
933 * _xmlSchemaParseGMonth:
934 * @dt: pointer to a date structure
935 * @str: pointer to the string to analyze
936 *
937 * Parses a xs:gMonth without time zone and fills in the appropriate
938 * field of the @dt structure. @str is updated to point just after the
939 * xs:gMonth.
940 *
941 * Returns 0 or the error code
942 */
943static int
944_xmlSchemaParseGMonth (xmlSchemaValDatePtr dt, const xmlChar **str) {
945 const xmlChar *cur = *str;
946 int ret = 0;
947
948 PARSE_2_DIGITS(dt->mon, cur, ret);
949 if (ret != 0)
950 return ret;
951
952 if (!VALID_MONTH(dt->mon))
953 return 2;
954
955 *str = cur;
956 return 0;
957}
958
959/**
960 * _xmlSchemaParseGDay:
961 * @dt: pointer to a date structure
962 * @str: pointer to the string to analyze
963 *
964 * Parses a xs:gDay without time zone and fills in the appropriate
965 * field of the @dt structure. @str is updated to point just after the
966 * xs:gDay.
967 *
968 * Returns 0 or the error code
969 */
970static int
971_xmlSchemaParseGDay (xmlSchemaValDatePtr dt, const xmlChar **str) {
972 const xmlChar *cur = *str;
973 int ret = 0;
974
975 PARSE_2_DIGITS(dt->day, cur, ret);
976 if (ret != 0)
977 return ret;
978
979 if (!VALID_DAY(dt->day))
980 return 2;
981
982 *str = cur;
983 return 0;
984}
985
986/**
987 * _xmlSchemaParseTime:
988 * @dt: pointer to a date structure
989 * @str: pointer to the string to analyze
990 *
991 * Parses a xs:time without time zone and fills in the appropriate
992 * fields of the @dt structure. @str is updated to point just after the
993 * xs:time.
994 * In case of error, values of @dt fields are undefined.
995 *
996 * Returns 0 or the error code
997 */
998static int
999_xmlSchemaParseTime (xmlSchemaValDatePtr dt, const xmlChar **str) {
1000 const xmlChar *cur = *str;
1001 unsigned int hour = 0; /* use temp var in case str is not xs:time */
1002 int ret = 0;
1003
1004 PARSE_2_DIGITS(hour, cur, ret);
1005 if (ret != 0)
1006 return ret;
1007
1008 if (*cur != ':')
1009 return 1;
1010 cur++;
1011
1012 /* the ':' insures this string is xs:time */
1013 dt->hour = hour;
1014
1015 PARSE_2_DIGITS(dt->min, cur, ret);
1016 if (ret != 0)
1017 return ret;
1018
1019 if (*cur != ':')
1020 return 1;
1021 cur++;
1022
1023 PARSE_FLOAT(dt->sec, cur, ret);
1024 if (ret != 0)
1025 return ret;
1026
1027 if (!VALID_TIME(dt))
1028 return 2;
1029
1030 *str = cur;
1031 return 0;
1032}
1033
1034/**
1035 * _xmlSchemaParseTimeZone:
1036 * @dt: pointer to a date structure
1037 * @str: pointer to the string to analyze
1038 *
1039 * Parses a time zone without time zone and fills in the appropriate
1040 * field of the @dt structure. @str is updated to point just after the
1041 * time zone.
1042 *
1043 * Returns 0 or the error code
1044 */
1045static int
1046_xmlSchemaParseTimeZone (xmlSchemaValDatePtr dt, const xmlChar **str) {
1047 const xmlChar *cur = *str;
1048 int ret = 0;
1049
1050 if (str == NULL)
1051 return -1;
1052
1053 switch (*cur) {
1054 case 0:
1055 dt->tz_flag = 0;
1056 dt->tzo = 0;
1057 break;
1058
1059 case 'Z':
1060 dt->tz_flag = 1;
1061 dt->tzo = 0;
1062 cur++;
1063 break;
1064
1065 case '+':
1066 case '-': {
1067 int isneg = 0, tmp = 0;
1068 isneg = (*cur == '-');
1069
1070 cur++;
1071
1072 PARSE_2_DIGITS(tmp, cur, ret);
1073 if (ret != 0)
1074 return ret;
1075 if (!VALID_HOUR(tmp))
1076 return 2;
1077
1078 if (*cur != ':')
1079 return 1;
1080 cur++;
1081
1082 dt->tzo = tmp * 60;
1083
1084 PARSE_2_DIGITS(tmp, cur, ret);
1085 if (ret != 0)
1086 return ret;
1087 if (!VALID_MIN(tmp))
1088 return 2;
1089
1090 dt->tzo += tmp;
1091 if (isneg)
1092 dt->tzo = - dt->tzo;
1093
1094 if (!VALID_TZO(dt->tzo))
1095 return 2;
1096
Daniel Veillard5a872412002-05-22 06:40:27 +00001097 dt->tz_flag = 1;
Daniel Veillard070803b2002-05-03 07:29:38 +00001098 break;
1099 }
1100 default:
1101 return 1;
1102 }
1103
1104 *str = cur;
1105 return 0;
1106}
1107
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001108/**
1109 * _xmlSchemaBase64Decode:
1110 * @ch: a character
1111 *
1112 * Converts a base64 encoded character to its base 64 value.
1113 *
1114 * Returns 0-63 (value), 64 (pad), or -1 (not recognized)
1115 */
1116static int
1117_xmlSchemaBase64Decode (const xmlChar ch) {
1118 if (('A' <= ch) && (ch <= 'Z')) return ch - 'A';
1119 if (('a' <= ch) && (ch <= 'z')) return ch - 'a' + 26;
1120 if (('0' <= ch) && (ch <= '9')) return ch - '0' + 52;
1121 if ('+' == ch) return 62;
1122 if ('/' == ch) return 63;
1123 if ('=' == ch) return 64;
1124 return -1;
1125}
1126
Daniel Veillard070803b2002-05-03 07:29:38 +00001127/****************************************************************
1128 * *
1129 * XML Schema Dates/Times Datatypes Handling *
1130 * *
1131 ****************************************************************/
1132
1133/**
1134 * PARSE_DIGITS:
1135 * @num: the integer to fill in
1136 * @cur: an #xmlChar *
1137 * @num_type: an integer flag
1138 *
1139 * Parses a digits integer and updates @num with the value. @cur is
1140 * updated to point just after the integer.
1141 * In case of error, @num_type is set to -1, values of @num and
1142 * @cur are undefined.
1143 */
1144#define PARSE_DIGITS(num, cur, num_type) \
1145 if ((*cur < '0') || (*cur > '9')) \
1146 num_type = -1; \
1147 else \
1148 while ((*cur >= '0') && (*cur <= '9')) { \
1149 num = num * 10 + (*cur - '0'); \
1150 cur++; \
1151 }
1152
1153/**
1154 * PARSE_NUM:
1155 * @num: the double to fill in
1156 * @cur: an #xmlChar *
1157 * @num_type: an integer flag
1158 *
1159 * Parses a float or integer and updates @num with the value. @cur is
1160 * updated to point just after the number. If the number is a float,
1161 * then it must have an integer part and a decimal part; @num_type will
1162 * be set to 1. If there is no decimal part, @num_type is set to zero.
1163 * In case of error, @num_type is set to -1, values of @num and
1164 * @cur are undefined.
1165 */
1166#define PARSE_NUM(num, cur, num_type) \
1167 num = 0; \
1168 PARSE_DIGITS(num, cur, num_type); \
1169 if (!num_type && (*cur == '.')) { \
1170 double mult = 1; \
1171 cur++; \
1172 if ((*cur < '0') || (*cur > '9')) \
1173 num_type = -1; \
1174 else \
1175 num_type = 1; \
1176 while ((*cur >= '0') && (*cur <= '9')) { \
1177 mult /= 10; \
1178 num += (*cur - '0') * mult; \
1179 cur++; \
1180 } \
1181 }
1182
1183/**
Daniel Veillard5a872412002-05-22 06:40:27 +00001184 * xmlSchemaValidateDates:
Daniel Veillard455cc072003-03-31 10:13:23 +00001185 * @type: the expected type or XML_SCHEMAS_UNKNOWN
Daniel Veillard070803b2002-05-03 07:29:38 +00001186 * @dateTime: string to analyze
1187 * @val: the return computed value
1188 *
1189 * Check that @dateTime conforms to the lexical space of one of the date types.
1190 * if true a value is computed and returned in @val.
1191 *
1192 * Returns 0 if this validates, a positive error code number otherwise
1193 * and -1 in case of internal or API error.
1194 */
1195static int
Daniel Veillard455cc072003-03-31 10:13:23 +00001196xmlSchemaValidateDates (xmlSchemaValType type,
Daniel Veillard118aed72002-09-24 14:13:13 +00001197 const xmlChar *dateTime, xmlSchemaValPtr *val) {
Daniel Veillard070803b2002-05-03 07:29:38 +00001198 xmlSchemaValPtr dt;
1199 int ret;
1200 const xmlChar *cur = dateTime;
1201
1202#define RETURN_TYPE_IF_VALID(t) \
1203 if (IS_TZO_CHAR(*cur)) { \
1204 ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur); \
1205 if (ret == 0) { \
1206 if (*cur != 0) \
1207 goto error; \
1208 dt->type = t; \
Daniel Veillard455cc072003-03-31 10:13:23 +00001209 goto done; \
Daniel Veillard070803b2002-05-03 07:29:38 +00001210 } \
1211 }
1212
1213 if (dateTime == NULL)
1214 return -1;
1215
1216 if ((*cur != '-') && (*cur < '0') && (*cur > '9'))
1217 return 1;
1218
1219 dt = xmlSchemaNewValue(XML_SCHEMAS_UNKNOWN);
1220 if (dt == NULL)
1221 return -1;
1222
1223 if ((cur[0] == '-') && (cur[1] == '-')) {
1224 /*
1225 * It's an incomplete date (xs:gMonthDay, xs:gMonth or
1226 * xs:gDay)
1227 */
1228 cur += 2;
1229
1230 /* is it an xs:gDay? */
1231 if (*cur == '-') {
Daniel Veillard455cc072003-03-31 10:13:23 +00001232 if (type == XML_SCHEMAS_GMONTH)
1233 goto error;
Daniel Veillard070803b2002-05-03 07:29:38 +00001234 ++cur;
1235 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
1236 if (ret != 0)
1237 goto error;
1238
1239 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GDAY);
1240
1241 goto error;
1242 }
1243
1244 /*
1245 * it should be an xs:gMonthDay or xs:gMonth
1246 */
1247 ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
1248 if (ret != 0)
1249 goto error;
1250
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001251 /*
1252 * a '-' char could indicate this type is xs:gMonthDay or
1253 * a negative time zone offset. Check for xs:gMonthDay first.
1254 * Also the first three char's of a negative tzo (-MM:SS) can
1255 * appear to be a valid day; so even if the day portion
1256 * of the xs:gMonthDay verifies, we must insure it was not
1257 * a tzo.
1258 */
1259 if (*cur == '-') {
1260 const xmlChar *rewnd = cur;
1261 cur++;
Daniel Veillard070803b2002-05-03 07:29:38 +00001262
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001263 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
1264 if ((ret == 0) && ((*cur == 0) || (*cur != ':'))) {
1265
1266 /*
1267 * we can use the VALID_MDAY macro to validate the month
1268 * and day because the leap year test will flag year zero
1269 * as a leap year (even though zero is an invalid year).
1270 */
1271 if (VALID_MDAY((&(dt->value.date)))) {
1272
1273 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTHDAY);
1274
1275 goto error;
1276 }
1277 }
1278
1279 /*
1280 * not xs:gMonthDay so rewind and check if just xs:gMonth
1281 * with an optional time zone.
1282 */
1283 cur = rewnd;
1284 }
1285
1286 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTH);
Daniel Veillard070803b2002-05-03 07:29:38 +00001287
1288 goto error;
1289 }
1290
1291 /*
1292 * It's a right-truncated date or an xs:time.
1293 * Try to parse an xs:time then fallback on right-truncated dates.
1294 */
1295 if ((*cur >= '0') && (*cur <= '9')) {
1296 ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
1297 if (ret == 0) {
1298 /* it's an xs:time */
1299 RETURN_TYPE_IF_VALID(XML_SCHEMAS_TIME);
1300 }
1301 }
1302
1303 /* fallback on date parsing */
1304 cur = dateTime;
1305
1306 ret = _xmlSchemaParseGYear(&(dt->value.date), &cur);
1307 if (ret != 0)
1308 goto error;
1309
1310 /* is it an xs:gYear? */
1311 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEAR);
1312
1313 if (*cur != '-')
1314 goto error;
1315 cur++;
1316
1317 ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
1318 if (ret != 0)
1319 goto error;
1320
1321 /* is it an xs:gYearMonth? */
1322 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEARMONTH);
1323
1324 if (*cur != '-')
1325 goto error;
1326 cur++;
1327
1328 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
1329 if ((ret != 0) || !VALID_DATE((&(dt->value.date))))
1330 goto error;
1331
1332 /* is it an xs:date? */
1333 RETURN_TYPE_IF_VALID(XML_SCHEMAS_DATE);
1334
1335 if (*cur != 'T')
1336 goto error;
1337 cur++;
1338
1339 /* it should be an xs:dateTime */
1340 ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
1341 if (ret != 0)
1342 goto error;
1343
1344 ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur);
1345 if ((ret != 0) || (*cur != 0) || !VALID_DATETIME((&(dt->value.date))))
1346 goto error;
1347
Daniel Veillard455cc072003-03-31 10:13:23 +00001348
Daniel Veillard070803b2002-05-03 07:29:38 +00001349 dt->type = XML_SCHEMAS_DATETIME;
1350
Daniel Veillard455cc072003-03-31 10:13:23 +00001351done:
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001352#if 1
1353 if ((type != XML_SCHEMAS_UNKNOWN) && (type != dt->type))
1354 goto error;
1355#else
1356 /*
1357 * insure the parsed type is equal to or less significant (right
1358 * truncated) than the desired type.
1359 */
1360 if ((type != XML_SCHEMAS_UNKNOWN) && (type != dt->type)) {
1361
1362 /* time only matches time */
1363 if ((type == XML_SCHEMAS_TIME) && (dt->type == XML_SCHEMAS_TIME))
1364 goto error;
1365
1366 if ((type == XML_SCHEMAS_DATETIME) &&
1367 ((dt->type != XML_SCHEMAS_DATE) ||
1368 (dt->type != XML_SCHEMAS_GYEARMONTH) ||
1369 (dt->type != XML_SCHEMAS_GYEAR)))
1370 goto error;
1371
1372 if ((type == XML_SCHEMAS_DATE) &&
1373 ((dt->type != XML_SCHEMAS_GYEAR) ||
1374 (dt->type != XML_SCHEMAS_GYEARMONTH)))
1375 goto error;
1376
1377 if ((type == XML_SCHEMAS_GYEARMONTH) && (dt->type != XML_SCHEMAS_GYEAR))
1378 goto error;
1379
1380 if ((type == XML_SCHEMAS_GMONTHDAY) && (dt->type != XML_SCHEMAS_GMONTH))
1381 goto error;
1382 }
Daniel Veillard455cc072003-03-31 10:13:23 +00001383#endif
1384
Daniel Veillard070803b2002-05-03 07:29:38 +00001385 if (val != NULL)
1386 *val = dt;
Daniel Veillard80b19092003-03-28 13:29:53 +00001387 else
1388 xmlSchemaFreeValue(dt);
Daniel Veillard070803b2002-05-03 07:29:38 +00001389
1390 return 0;
1391
1392error:
1393 if (dt != NULL)
1394 xmlSchemaFreeValue(dt);
1395 return 1;
1396}
1397
1398/**
Daniel Veillard5a872412002-05-22 06:40:27 +00001399 * xmlSchemaValidateDuration:
Daniel Veillard070803b2002-05-03 07:29:38 +00001400 * @type: the predefined type
1401 * @duration: string to analyze
1402 * @val: the return computed value
1403 *
1404 * Check that @duration conforms to the lexical space of the duration type.
1405 * if true a value is computed and returned in @val.
1406 *
1407 * Returns 0 if this validates, a positive error code number otherwise
1408 * and -1 in case of internal or API error.
1409 */
1410static int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00001411xmlSchemaValidateDuration (xmlSchemaTypePtr type ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +00001412 const xmlChar *duration, xmlSchemaValPtr *val) {
Daniel Veillard070803b2002-05-03 07:29:38 +00001413 const xmlChar *cur = duration;
1414 xmlSchemaValPtr dur;
1415 int isneg = 0;
1416 unsigned int seq = 0;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001417 double num;
1418 int num_type = 0; /* -1 = invalid, 0 = int, 1 = floating */
1419 const xmlChar desig[] = {'Y', 'M', 'D', 'H', 'M', 'S'};
1420 const double multi[] = { 0.0, 0.0, 86400.0, 3600.0, 60.0, 1.0, 0.0};
Daniel Veillard070803b2002-05-03 07:29:38 +00001421
1422 if (duration == NULL)
1423 return -1;
1424
1425 if (*cur == '-') {
1426 isneg = 1;
1427 cur++;
1428 }
1429
1430 /* duration must start with 'P' (after sign) */
1431 if (*cur++ != 'P')
1432 return 1;
1433
Daniel Veillard80b19092003-03-28 13:29:53 +00001434 if (*cur == 0)
1435 return 1;
1436
Daniel Veillard070803b2002-05-03 07:29:38 +00001437 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
1438 if (dur == NULL)
1439 return -1;
1440
1441 while (*cur != 0) {
Daniel Veillard070803b2002-05-03 07:29:38 +00001442
1443 /* input string should be empty or invalid date/time item */
1444 if (seq >= sizeof(desig))
1445 goto error;
1446
1447 /* T designator must be present for time items */
1448 if (*cur == 'T') {
1449 if (seq <= 3) {
1450 seq = 3;
1451 cur++;
1452 } else
1453 return 1;
1454 } else if (seq == 3)
1455 goto error;
1456
1457 /* parse the number portion of the item */
1458 PARSE_NUM(num, cur, num_type);
1459
1460 if ((num_type == -1) || (*cur == 0))
1461 goto error;
1462
1463 /* update duration based on item type */
1464 while (seq < sizeof(desig)) {
1465 if (*cur == desig[seq]) {
1466
1467 /* verify numeric type; only seconds can be float */
1468 if ((num_type != 0) && (seq < (sizeof(desig)-1)))
1469 goto error;
1470
1471 switch (seq) {
1472 case 0:
1473 dur->value.dur.mon = (long)num * 12;
1474 break;
1475 case 1:
1476 dur->value.dur.mon += (long)num;
1477 break;
1478 default:
1479 /* convert to seconds using multiplier */
1480 dur->value.dur.sec += num * multi[seq];
1481 seq++;
1482 break;
1483 }
1484
1485 break; /* exit loop */
1486 }
1487 /* no date designators found? */
1488 if (++seq == 3)
1489 goto error;
1490 }
1491 cur++;
1492 }
1493
1494 if (isneg) {
1495 dur->value.dur.mon = -dur->value.dur.mon;
1496 dur->value.dur.day = -dur->value.dur.day;
1497 dur->value.dur.sec = -dur->value.dur.sec;
1498 }
1499
1500 if (val != NULL)
1501 *val = dur;
Daniel Veillard80b19092003-03-28 13:29:53 +00001502 else
1503 xmlSchemaFreeValue(dur);
Daniel Veillard070803b2002-05-03 07:29:38 +00001504
1505 return 0;
1506
1507error:
1508 if (dur != NULL)
1509 xmlSchemaFreeValue(dur);
1510 return 1;
1511}
1512
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001513/**
1514 * xmlSchemaStrip:
1515 * @value: a value
1516 *
1517 * Removes the leading and ending spaces of a string
1518 *
1519 * Returns the new string or NULL if no change was required.
1520 */
1521static xmlChar *
1522xmlSchemaStrip(const xmlChar *value) {
1523 const xmlChar *start = value, *end, *f;
1524
1525 if (value == NULL) return(NULL);
William M. Brack76e95df2003-10-18 16:20:14 +00001526 while ((*start != 0) && (IS_BLANK_CH(*start))) start++;
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001527 end = start;
1528 while (*end != 0) end++;
1529 f = end;
1530 end--;
William M. Brack76e95df2003-10-18 16:20:14 +00001531 while ((end > start) && (IS_BLANK_CH(*end))) end--;
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001532 end++;
1533 if ((start == value) && (f == end)) return(NULL);
1534 return(xmlStrndup(start, end - start));
1535}
Daniel Veillard96a4b252003-02-06 08:22:32 +00001536
1537/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001538 * xmlSchemaCollapseString:
1539 * @value: a value
1540 *
1541 * Removes and normalize white spaces in the string
1542 *
1543 * Returns the new string or NULL if no change was required.
1544 */
Daniel Veillard01fa6152004-06-29 17:04:39 +00001545xmlChar *
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001546xmlSchemaCollapseString(const xmlChar *value) {
1547 const xmlChar *start = value, *end, *f;
1548 xmlChar *g;
1549 int col = 0;
1550
1551 if (value == NULL) return(NULL);
William M. Brack76e95df2003-10-18 16:20:14 +00001552 while ((*start != 0) && (IS_BLANK_CH(*start))) start++;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001553 end = start;
1554 while (*end != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00001555 if ((*end == ' ') && (IS_BLANK_CH(end[1]))) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001556 col = end - start;
1557 break;
1558 } else if ((*end == 0xa) || (*end == 0x9) || (*end == 0xd)) {
1559 col = end - start;
1560 break;
1561 }
1562 end++;
1563 }
1564 if (col == 0) {
1565 f = end;
1566 end--;
William M. Brack76e95df2003-10-18 16:20:14 +00001567 while ((end > start) && (IS_BLANK_CH(*end))) end--;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001568 end++;
1569 if ((start == value) && (f == end)) return(NULL);
1570 return(xmlStrndup(start, end - start));
1571 }
1572 start = xmlStrdup(start);
1573 if (start == NULL) return(NULL);
1574 g = (xmlChar *) (start + col);
1575 end = g;
1576 while (*end != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00001577 if (IS_BLANK_CH(*end)) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001578 end++;
William M. Brack76e95df2003-10-18 16:20:14 +00001579 while (IS_BLANK_CH(*end)) end++;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001580 if (*end != 0)
1581 *g++ = ' ';
1582 } else
1583 *g++ = *end++;
1584 }
1585 *g = 0;
1586 return((xmlChar *) start);
1587}
1588
1589/**
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001590 * xmlSchemaValAtomicListNode:
1591 * @type: the predefined atomic type for a token in the list
1592 * @value: the list value to check
1593 * @ret: the return computed value
1594 * @node: the node containing the value
1595 *
1596 * Check that a value conforms to the lexical space of the predefined
1597 * list type. if true a value is computed and returned in @ret.
1598 *
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001599 * Returns the number of items if this validates, a negative error code
1600 * number otherwise
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001601 */
1602static int
1603xmlSchemaValAtomicListNode(xmlSchemaTypePtr type, const xmlChar *value,
1604 xmlSchemaValPtr *ret, xmlNodePtr node) {
1605 xmlChar *val, *cur, *endval;
1606 int nb_values = 0;
Daniel Veillard580ced82003-03-21 21:22:48 +00001607 int tmp = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001608
1609 if (value == NULL) {
1610 return(-1);
1611 }
1612 val = xmlStrdup(value);
1613 if (val == NULL) {
1614 return(-1);
1615 }
1616 cur = val;
1617 /*
1618 * Split the list
1619 */
William M. Brack76e95df2003-10-18 16:20:14 +00001620 while (IS_BLANK_CH(*cur)) *cur++ = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001621 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00001622 if (IS_BLANK_CH(*cur)) {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001623 *cur = 0;
1624 cur++;
William M. Brack76e95df2003-10-18 16:20:14 +00001625 while (IS_BLANK_CH(*cur)) *cur++ = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001626 } else {
1627 nb_values++;
1628 cur++;
William M. Brack76e95df2003-10-18 16:20:14 +00001629 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001630 }
1631 }
1632 if (nb_values == 0) {
1633 if (ret != NULL) {
1634 TODO
1635 }
1636 xmlFree(val);
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001637 return(nb_values);
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001638 }
1639 endval = cur;
1640 cur = val;
1641 while ((*cur == 0) && (cur != endval)) cur++;
1642 while (cur != endval) {
1643 tmp = xmlSchemaValPredefTypeNode(type, cur, NULL, node);
1644 if (tmp != 0)
1645 break;
1646 while (*cur != 0) cur++;
1647 while ((*cur == 0) && (cur != endval)) cur++;
1648 }
1649 xmlFree(val);
1650 if (ret != NULL) {
1651 TODO
1652 }
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001653 if (tmp == 0)
1654 return(nb_values);
1655 return(-1);
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001656}
1657
1658/**
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001659 * xmlSchemaParseUInt:
1660 * @str: pointer to the string R/W
1661 * @llo: pointer to the low result
1662 * @lmi: pointer to the mid result
1663 * @lhi: pointer to the high result
1664 *
1665 * Parse an unsigned long into 3 fields.
1666 *
1667 * Returns the number of chars parsed or -1 if overflow of the capacity
1668 */
1669static int
1670xmlSchemaParseUInt(const xmlChar **str, unsigned long *llo,
1671 unsigned long *lmi, unsigned long *lhi) {
1672 unsigned long lo = 0, mi = 0, hi = 0;
1673 const xmlChar *tmp, *cur = *str;
1674 int ret = 0, i = 0;
1675
1676 while (*cur == '0') {
1677 ret++;
1678 cur++;
1679 }
1680 tmp = cur;
1681 while ((*tmp != 0) && (*tmp >= '0') && (*tmp <= '9')) {
1682 i++;tmp++;ret++;
1683 }
1684 if (i > 24) {
1685 *str = tmp;
1686 return(-1);
1687 }
1688 while (i > 16) {
1689 hi = hi * 10 + (*cur++ - '0');
1690 i--;
1691 }
1692 while (i > 8) {
1693 mi = mi * 10 + (*cur++ - '0');
1694 i--;
1695 }
1696 while (i > 0) {
1697 lo = lo * 10 + (*cur++ - '0');
1698 i--;
1699 }
1700
1701 *str = cur;
1702 *llo = lo;
1703 *lmi = mi;
1704 *lhi = hi;
1705 return(ret);
1706}
1707
1708/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001709 * xmlSchemaValAtomicType:
1710 * @type: the predefined type
1711 * @value: the value to check
1712 * @val: the return computed value
1713 * @node: the node containing the value
1714 * flags: flags to control the vlidation
1715 *
1716 * Check that a value conforms to the lexical space of the atomic type.
1717 * if true a value is computed and returned in @val.
Daniel Veillard01fa6152004-06-29 17:04:39 +00001718 * This checks the value space for list types as well (IDREFS, NMTOKENS).
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001719 *
1720 * Returns 0 if this validates, a positive error code number otherwise
1721 * and -1 in case of internal or API error.
1722 */
1723static int
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001724xmlSchemaValAtomicType(xmlSchemaTypePtr type, const xmlChar * value,
1725 xmlSchemaValPtr * val, xmlNodePtr node, int flags)
1726{
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001727 xmlSchemaValPtr v;
1728 xmlChar *norm = NULL;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001729 int ret = 0;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001730
1731 if (xmlSchemaTypesInitialized == 0)
Daniel Veillard01fa6152004-06-29 17:04:39 +00001732 xmlSchemaInitTypes();
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001733 if (type == NULL)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001734 return (-1);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001735
Daniel Veillardeebd6332004-08-26 10:30:44 +00001736 /*
1737 * validating a non existant text node is similar to validating
1738 * an empty one.
1739 */
1740 if (value == NULL)
1741 value = BAD_CAST "";
1742
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001743 if (val != NULL)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001744 *val = NULL;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001745 if ((flags == 0) && (value != NULL)) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00001746 if ((type->builtInType != XML_SCHEMAS_STRING) &&
1747 (type->builtInType != XML_SCHEMAS_NORMSTRING)) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001748 norm = xmlSchemaCollapseString(value);
1749 if (norm != NULL)
1750 value = norm;
1751 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001752 }
1753
Daniel Veillard01fa6152004-06-29 17:04:39 +00001754 switch (type->builtInType) {
William M. Brack2f2a6632004-08-20 23:09:47 +00001755 case XML_SCHEMAS_UNKNOWN:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001756 goto error;
William M. Brack2f2a6632004-08-20 23:09:47 +00001757 case XML_SCHEMAS_ANYTYPE:
1758 case XML_SCHEMAS_ANYSIMPLETYPE:
1759 goto return0;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001760 case XML_SCHEMAS_STRING:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001761 goto return0;
Daniel Veillard1516d5b2004-01-22 07:27:45 +00001762 case XML_SCHEMAS_NORMSTRING:{
1763 const xmlChar *cur = value;
1764
1765 while (*cur != 0) {
1766 if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) {
1767 goto return1;
1768 } else {
1769 cur++;
1770 }
1771 }
1772 if (val != NULL) {
1773 v = xmlSchemaNewValue(XML_SCHEMAS_NORMSTRING);
1774 if (v != NULL) {
1775 v->value.str = xmlStrdup(value);
1776 *val = v;
1777 } else {
1778 goto error;
1779 }
1780 }
1781 goto return0;
1782 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001783 case XML_SCHEMAS_DECIMAL:{
1784 const xmlChar *cur = value, *tmp;
1785 unsigned int frac = 0, len, neg = 0;
1786 unsigned long base = 0;
1787
1788 if (cur == NULL)
1789 goto return1;
1790 if (*cur == '+')
1791 cur++;
1792 else if (*cur == '-') {
1793 neg = 1;
1794 cur++;
1795 }
1796 tmp = cur;
1797 while ((*cur >= '0') && (*cur <= '9')) {
1798 base = base * 10 + (*cur - '0');
1799 cur++;
1800 }
1801 len = cur - tmp;
1802 if (*cur == '.') {
1803 cur++;
1804 tmp = cur;
1805 while ((*cur >= '0') && (*cur <= '9')) {
1806 base = base * 10 + (*cur - '0');
1807 cur++;
1808 }
1809 frac = cur - tmp;
1810 }
1811 if (*cur != 0)
1812 goto return1;
1813 if (val != NULL) {
1814 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
1815 if (v != NULL) {
1816 v->value.decimal.lo = base;
1817 v->value.decimal.sign = neg;
1818 v->value.decimal.frac = frac;
1819 v->value.decimal.total = frac + len;
1820 *val = v;
1821 }
1822 }
1823 goto return0;
1824 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001825 case XML_SCHEMAS_TIME:
1826 case XML_SCHEMAS_GDAY:
1827 case XML_SCHEMAS_GMONTH:
1828 case XML_SCHEMAS_GMONTHDAY:
1829 case XML_SCHEMAS_GYEAR:
1830 case XML_SCHEMAS_GYEARMONTH:
1831 case XML_SCHEMAS_DATE:
1832 case XML_SCHEMAS_DATETIME:
Daniel Veillard01fa6152004-06-29 17:04:39 +00001833 ret = xmlSchemaValidateDates(type->builtInType, value, val);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001834 break;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001835 case XML_SCHEMAS_DURATION:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001836 ret = xmlSchemaValidateDuration(type, value, val);
1837 break;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001838 case XML_SCHEMAS_FLOAT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001839 case XML_SCHEMAS_DOUBLE:{
1840 const xmlChar *cur = value;
1841 int neg = 0;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001842
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001843 if (cur == NULL)
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00001844 goto return1;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001845 if ((cur[0] == 'N') && (cur[1] == 'a') && (cur[2] == 'N')) {
1846 cur += 3;
1847 if (*cur != 0)
1848 goto return1;
1849 if (val != NULL) {
1850 if (type == xmlSchemaTypeFloatDef) {
1851 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1852 if (v != NULL) {
1853 v->value.f = (float) xmlXPathNAN;
1854 } else {
1855 xmlSchemaFreeValue(v);
1856 goto error;
1857 }
1858 } else {
1859 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1860 if (v != NULL) {
1861 v->value.d = xmlXPathNAN;
1862 } else {
1863 xmlSchemaFreeValue(v);
1864 goto error;
1865 }
1866 }
1867 *val = v;
1868 }
1869 goto return0;
1870 }
1871 if (*cur == '-') {
1872 neg = 1;
1873 cur++;
1874 }
1875 if ((cur[0] == 'I') && (cur[1] == 'N') && (cur[2] == 'F')) {
1876 cur += 3;
1877 if (*cur != 0)
1878 goto return1;
1879 if (val != NULL) {
1880 if (type == xmlSchemaTypeFloatDef) {
1881 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1882 if (v != NULL) {
1883 if (neg)
1884 v->value.f = (float) xmlXPathNINF;
1885 else
1886 v->value.f = (float) xmlXPathPINF;
1887 } else {
1888 xmlSchemaFreeValue(v);
1889 goto error;
1890 }
1891 } else {
1892 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1893 if (v != NULL) {
1894 if (neg)
1895 v->value.d = xmlXPathNINF;
1896 else
1897 v->value.d = xmlXPathPINF;
1898 } else {
1899 xmlSchemaFreeValue(v);
1900 goto error;
1901 }
1902 }
1903 *val = v;
1904 }
1905 goto return0;
1906 }
1907 if ((neg == 0) && (*cur == '+'))
1908 cur++;
1909 if ((cur[0] == 0) || (cur[0] == '+') || (cur[0] == '-'))
1910 goto return1;
1911 while ((*cur >= '0') && (*cur <= '9')) {
1912 cur++;
1913 }
1914 if (*cur == '.') {
1915 cur++;
1916 while ((*cur >= '0') && (*cur <= '9'))
1917 cur++;
1918 }
1919 if ((*cur == 'e') || (*cur == 'E')) {
1920 cur++;
1921 if ((*cur == '-') || (*cur == '+'))
1922 cur++;
1923 while ((*cur >= '0') && (*cur <= '9'))
1924 cur++;
1925 }
1926 if (*cur != 0)
1927 goto return1;
1928 if (val != NULL) {
1929 if (type == xmlSchemaTypeFloatDef) {
1930 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1931 if (v != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001932 if (sscanf((const char *) value, "%f",
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001933 &(v->value.f)) == 1) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00001934 *val = v;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001935 } else {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001936 xmlSchemaFreeValue(v);
1937 goto return1;
1938 }
1939 } else {
1940 goto error;
1941 }
1942 } else {
1943 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1944 if (v != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001945 if (sscanf((const char *) value, "%lf",
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001946 &(v->value.d)) == 1) {
1947 *val = v;
1948 } else {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001949 xmlSchemaFreeValue(v);
1950 goto return1;
1951 }
1952 } else {
1953 goto error;
1954 }
1955 }
1956 }
1957 goto return0;
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00001958 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001959 case XML_SCHEMAS_BOOLEAN:{
1960 const xmlChar *cur = value;
1961
1962 if ((cur[0] == '0') && (cur[1] == 0))
1963 ret = 0;
1964 else if ((cur[0] == '1') && (cur[1] == 0))
1965 ret = 1;
1966 else if ((cur[0] == 't') && (cur[1] == 'r')
1967 && (cur[2] == 'u') && (cur[3] == 'e')
1968 && (cur[4] == 0))
1969 ret = 1;
1970 else if ((cur[0] == 'f') && (cur[1] == 'a')
1971 && (cur[2] == 'l') && (cur[3] == 's')
1972 && (cur[4] == 'e') && (cur[5] == 0))
1973 ret = 0;
1974 else
1975 goto return1;
1976 if (val != NULL) {
1977 v = xmlSchemaNewValue(XML_SCHEMAS_BOOLEAN);
1978 if (v != NULL) {
1979 v->value.b = ret;
1980 *val = v;
1981 } else {
1982 goto error;
1983 }
1984 }
1985 goto return0;
1986 }
1987 case XML_SCHEMAS_TOKEN:{
1988 const xmlChar *cur = value;
1989
William M. Brack76e95df2003-10-18 16:20:14 +00001990 if (IS_BLANK_CH(*cur))
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001991 goto return1;
1992
1993 while (*cur != 0) {
1994 if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) {
1995 goto return1;
1996 } else if (*cur == ' ') {
1997 cur++;
1998 if (*cur == 0)
1999 goto return1;
2000 if (*cur == ' ')
2001 goto return1;
2002 } else {
2003 cur++;
2004 }
2005 }
2006 if (val != NULL) {
2007 v = xmlSchemaNewValue(XML_SCHEMAS_TOKEN);
2008 if (v != NULL) {
2009 v->value.str = xmlStrdup(value);
2010 *val = v;
2011 } else {
2012 goto error;
2013 }
2014 }
2015 goto return0;
2016 }
2017 case XML_SCHEMAS_LANGUAGE:
2018 if (xmlCheckLanguageID(value) == 1) {
2019 if (val != NULL) {
2020 v = xmlSchemaNewValue(XML_SCHEMAS_LANGUAGE);
2021 if (v != NULL) {
2022 v->value.str = xmlStrdup(value);
2023 *val = v;
2024 } else {
2025 goto error;
2026 }
2027 }
2028 goto return0;
2029 }
2030 goto return1;
2031 case XML_SCHEMAS_NMTOKEN:
2032 if (xmlValidateNMToken(value, 1) == 0) {
2033 if (val != NULL) {
2034 v = xmlSchemaNewValue(XML_SCHEMAS_NMTOKEN);
2035 if (v != NULL) {
2036 v->value.str = xmlStrdup(value);
2037 *val = v;
2038 } else {
2039 goto error;
2040 }
2041 }
2042 goto return0;
2043 }
2044 goto return1;
2045 case XML_SCHEMAS_NMTOKENS:
2046 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeNmtokenDef,
2047 value, val, node);
2048 if (ret > 0)
2049 ret = 0;
2050 else
2051 ret = 1;
2052 goto done;
2053 case XML_SCHEMAS_NAME:
2054 ret = xmlValidateName(value, 1);
2055 if ((ret == 0) && (val != NULL)) {
2056 TODO;
2057 }
2058 goto done;
2059 case XML_SCHEMAS_QNAME:{
2060 xmlChar *uri = NULL;
2061 xmlChar *local = NULL;
2062
2063 ret = xmlValidateQName(value, 1);
2064 if ((ret == 0) && (node != NULL)) {
2065 xmlChar *prefix;
2066
2067 local = xmlSplitQName2(value, &prefix);
2068 if (prefix != NULL) {
2069 xmlNsPtr ns;
2070
2071 ns = xmlSearchNs(node->doc, node, prefix);
2072 if (ns == NULL)
2073 ret = 1;
2074 else if (val != NULL)
2075 uri = xmlStrdup(ns->href);
2076 }
2077 if ((local != NULL) && ((val == NULL) || (ret != 0)))
2078 xmlFree(local);
2079 if (prefix != NULL)
2080 xmlFree(prefix);
2081 }
2082 if ((ret == 0) && (val != NULL)) {
2083 v = xmlSchemaNewValue(XML_SCHEMAS_QNAME);
2084 if (v != NULL) {
2085 if (local != NULL)
2086 v->value.qname.name = local;
2087 else
2088 v->value.qname.name = xmlStrdup(value);
2089 if (uri != NULL)
2090 v->value.qname.uri = uri;
2091
2092 *val = v;
2093 } else {
2094 if (local != NULL)
2095 xmlFree(local);
2096 if (uri != NULL)
2097 xmlFree(uri);
2098 goto error;
2099 }
2100 }
2101 goto done;
2102 }
2103 case XML_SCHEMAS_NCNAME:
2104 ret = xmlValidateNCName(value, 1);
2105 if ((ret == 0) && (val != NULL)) {
2106 v = xmlSchemaNewValue(XML_SCHEMAS_NCNAME);
2107 if (v != NULL) {
2108 v->value.str = xmlStrdup(value);
2109 *val = v;
2110 } else {
2111 goto error;
2112 }
2113 }
2114 goto done;
2115 case XML_SCHEMAS_ID:
2116 ret = xmlValidateNCName(value, 1);
2117 if ((ret == 0) && (val != NULL)) {
2118 v = xmlSchemaNewValue(XML_SCHEMAS_ID);
2119 if (v != NULL) {
2120 v->value.str = xmlStrdup(value);
2121 *val = v;
2122 } else {
2123 goto error;
2124 }
2125 }
2126 if ((ret == 0) && (node != NULL) &&
2127 (node->type == XML_ATTRIBUTE_NODE)) {
2128 xmlAttrPtr attr = (xmlAttrPtr) node;
2129
2130 /*
2131 * NOTE: the IDness might have already be declared in the DTD
2132 */
2133 if (attr->atype != XML_ATTRIBUTE_ID) {
2134 xmlIDPtr res;
2135 xmlChar *strip;
2136
2137 strip = xmlSchemaStrip(value);
2138 if (strip != NULL) {
2139 res = xmlAddID(NULL, node->doc, strip, attr);
2140 xmlFree(strip);
2141 } else
2142 res = xmlAddID(NULL, node->doc, value, attr);
2143 if (res == NULL) {
2144 ret = 2;
2145 } else {
2146 attr->atype = XML_ATTRIBUTE_ID;
2147 }
2148 }
2149 }
2150 goto done;
2151 case XML_SCHEMAS_IDREF:
2152 ret = xmlValidateNCName(value, 1);
2153 if ((ret == 0) && (val != NULL)) {
2154 TODO;
2155 }
2156 if ((ret == 0) && (node != NULL) &&
2157 (node->type == XML_ATTRIBUTE_NODE)) {
2158 xmlAttrPtr attr = (xmlAttrPtr) node;
2159 xmlChar *strip;
2160
2161 strip = xmlSchemaStrip(value);
2162 if (strip != NULL) {
2163 xmlAddRef(NULL, node->doc, strip, attr);
2164 xmlFree(strip);
2165 } else
2166 xmlAddRef(NULL, node->doc, value, attr);
2167 attr->atype = XML_ATTRIBUTE_IDREF;
2168 }
2169 goto done;
2170 case XML_SCHEMAS_IDREFS:
2171 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeIdrefDef,
2172 value, val, node);
2173 if (ret < 0)
2174 ret = 2;
2175 else
2176 ret = 0;
2177 if ((ret == 0) && (node != NULL) &&
2178 (node->type == XML_ATTRIBUTE_NODE)) {
2179 xmlAttrPtr attr = (xmlAttrPtr) node;
2180
2181 attr->atype = XML_ATTRIBUTE_IDREFS;
2182 }
2183 goto done;
2184 case XML_SCHEMAS_ENTITY:{
2185 xmlChar *strip;
2186
2187 ret = xmlValidateNCName(value, 1);
2188 if ((node == NULL) || (node->doc == NULL))
2189 ret = 3;
2190 if (ret == 0) {
2191 xmlEntityPtr ent;
2192
2193 strip = xmlSchemaStrip(value);
2194 if (strip != NULL) {
2195 ent = xmlGetDocEntity(node->doc, strip);
2196 xmlFree(strip);
2197 } else {
2198 ent = xmlGetDocEntity(node->doc, value);
2199 }
2200 if ((ent == NULL) ||
2201 (ent->etype !=
2202 XML_EXTERNAL_GENERAL_UNPARSED_ENTITY))
2203 ret = 4;
2204 }
2205 if ((ret == 0) && (val != NULL)) {
2206 TODO;
2207 }
2208 if ((ret == 0) && (node != NULL) &&
2209 (node->type == XML_ATTRIBUTE_NODE)) {
2210 xmlAttrPtr attr = (xmlAttrPtr) node;
2211
2212 attr->atype = XML_ATTRIBUTE_ENTITY;
2213 }
2214 goto done;
2215 }
2216 case XML_SCHEMAS_ENTITIES:
2217 if ((node == NULL) || (node->doc == NULL))
2218 goto return3;
2219 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeEntityDef,
2220 value, val, node);
2221 if (ret <= 0)
2222 ret = 1;
2223 else
2224 ret = 0;
2225 if ((ret == 0) && (node != NULL) &&
2226 (node->type == XML_ATTRIBUTE_NODE)) {
2227 xmlAttrPtr attr = (xmlAttrPtr) node;
2228
2229 attr->atype = XML_ATTRIBUTE_ENTITIES;
2230 }
2231 goto done;
2232 case XML_SCHEMAS_NOTATION:{
2233 xmlChar *uri = NULL;
2234 xmlChar *local = NULL;
2235
2236 ret = xmlValidateQName(value, 1);
2237 if ((ret == 0) && (node != NULL)) {
2238 xmlChar *prefix;
2239
2240 local = xmlSplitQName2(value, &prefix);
2241 if (prefix != NULL) {
2242 xmlNsPtr ns;
2243
2244 ns = xmlSearchNs(node->doc, node, prefix);
2245 if (ns == NULL)
2246 ret = 1;
2247 else if (val != NULL)
2248 uri = xmlStrdup(ns->href);
2249 }
2250 if ((local != NULL) && ((val == NULL) || (ret != 0)))
2251 xmlFree(local);
2252 if (prefix != NULL)
2253 xmlFree(prefix);
2254 }
2255 if ((node == NULL) || (node->doc == NULL))
2256 ret = 3;
2257 if (ret == 0) {
2258 ret = xmlValidateNotationUse(NULL, node->doc, value);
2259 if (ret == 1)
2260 ret = 0;
2261 else
2262 ret = 1;
2263 }
2264 if ((ret == 0) && (val != NULL)) {
2265 v = xmlSchemaNewValue(XML_SCHEMAS_NOTATION);
2266 if (v != NULL) {
2267 if (local != NULL)
2268 v->value.qname.name = local;
2269 else
2270 v->value.qname.name = xmlStrdup(value);
2271 if (uri != NULL)
2272 v->value.qname.uri = uri;
2273
2274 *val = v;
2275 } else {
2276 if (local != NULL)
2277 xmlFree(local);
2278 if (uri != NULL)
2279 xmlFree(uri);
2280 goto error;
2281 }
2282 }
2283 goto done;
2284 }
2285 case XML_SCHEMAS_ANYURI:{
Daniel Veillard11c466a2004-03-14 12:20:15 +00002286 if (*value != 0) {
2287 xmlURIPtr uri = xmlParseURI((const char *) value);
2288 if (uri == NULL)
2289 goto return1;
2290 xmlFreeURI(uri);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002291 }
Daniel Veillard11c466a2004-03-14 12:20:15 +00002292
2293 if (val != NULL) {
2294 v = xmlSchemaNewValue(XML_SCHEMAS_ANYURI);
2295 if (v == NULL)
2296 goto error;
2297 v->value.str = xmlStrdup(value);
2298 *val = v;
2299 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002300 goto return0;
2301 }
2302 case XML_SCHEMAS_HEXBINARY:{
2303 const xmlChar *cur = value;
2304 xmlChar *base;
2305 int total, i = 0;
2306
Daniel Veillardf34a20e2004-08-31 08:42:17 +00002307 if (cur == NULL)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002308 goto return1;
2309
2310 while (((*cur >= '0') && (*cur <= '9')) ||
2311 ((*cur >= 'A') && (*cur <= 'F')) ||
2312 ((*cur >= 'a') && (*cur <= 'f'))) {
2313 i++;
2314 cur++;
2315 }
2316
2317 if (*cur != 0)
2318 goto return1;
2319 if ((i % 2) != 0)
2320 goto return1;
2321
2322 if (val != NULL) {
2323
2324 v = xmlSchemaNewValue(XML_SCHEMAS_HEXBINARY);
2325 if (v == NULL)
2326 goto error;
2327
2328 cur = xmlStrdup(value);
2329 if (cur == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002330 xmlSchemaTypeErrMemory(node, "allocating hexbin data");
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002331 xmlFree(v);
2332 goto return1;
2333 }
2334
2335 total = i / 2; /* number of octets */
2336
2337 base = (xmlChar *) cur;
2338 while (i-- > 0) {
2339 if (*base >= 'a')
2340 *base = *base - ('a' - 'A');
2341 base++;
2342 }
2343
2344 v->value.hex.str = (xmlChar *) cur;
2345 v->value.hex.total = total;
2346 *val = v;
2347 }
2348 goto return0;
2349 }
2350 case XML_SCHEMAS_BASE64BINARY:{
2351 /* ISSUE:
2352 *
2353 * Ignore all stray characters? (yes, currently)
2354 * Worry about long lines? (no, currently)
2355 *
2356 * rfc2045.txt:
2357 *
2358 * "The encoded output stream must be represented in lines of
2359 * no more than 76 characters each. All line breaks or other
2360 * characters not found in Table 1 must be ignored by decoding
2361 * software. In base64 data, characters other than those in
2362 * Table 1, line breaks, and other white space probably
2363 * indicate a transmission error, about which a warning
2364 * message or even a message rejection might be appropriate
2365 * under some circumstances." */
2366 const xmlChar *cur = value;
2367 xmlChar *base;
2368 int total, i = 0, pad = 0;
2369
2370 if (cur == NULL)
2371 goto return1;
2372
2373 for (; *cur; ++cur) {
2374 int decc;
2375
2376 decc = _xmlSchemaBase64Decode(*cur);
2377 if (decc < 0) ;
2378 else if (decc < 64)
2379 i++;
2380 else
2381 break;
2382 }
2383 for (; *cur; ++cur) {
2384 int decc;
2385
2386 decc = _xmlSchemaBase64Decode(*cur);
2387 if (decc < 0) ;
2388 else if (decc < 64)
2389 goto return1;
2390 if (decc == 64)
2391 pad++;
2392 }
2393
2394 /* rfc2045.txt: "Special processing is performed if fewer than
2395 * 24 bits are available at the end of the data being encoded.
2396 * A full encoding quantum is always completed at the end of a
2397 * body. When fewer than 24 input bits are available in an
2398 * input group, zero bits are added (on the right) to form an
2399 * integral number of 6-bit groups. Padding at the end of the
2400 * data is performed using the "=" character. Since all
2401 * base64 input is an integral number of octets, only the
2402 * following cases can arise: (1) the final quantum of
2403 * encoding input is an integral multiple of 24 bits; here,
2404 * the final unit of encoded output will be an integral
2405 * multiple ofindent: Standard input:701: Warning:old style
2406 * assignment ambiguity in "=*". Assuming "= *" 4 characters
2407 * with no "=" padding, (2) the final
2408 * quantum of encoding input is exactly 8 bits; here, the
2409 * final unit of encoded output will be two characters
2410 * followed by two "=" padding characters, or (3) the final
2411 * quantum of encoding input is exactly 16 bits; here, the
2412 * final unit of encoded output will be three characters
2413 * followed by one "=" padding character." */
2414
2415 total = 3 * (i / 4);
2416 if (pad == 0) {
2417 if (i % 4 != 0)
2418 goto return1;
2419 } else if (pad == 1) {
2420 int decc;
2421
2422 if (i % 4 != 3)
2423 goto return1;
2424 for (decc = _xmlSchemaBase64Decode(*cur);
2425 (decc < 0) || (decc > 63);
2426 decc = _xmlSchemaBase64Decode(*cur))
2427 --cur;
2428 /* 16bits in 24bits means 2 pad bits: nnnnnn nnmmmm mmmm00*/
2429 /* 00111100 -> 0x3c */
2430 if (decc & ~0x3c)
2431 goto return1;
2432 total += 2;
2433 } else if (pad == 2) {
2434 int decc;
2435
2436 if (i % 4 != 2)
2437 goto return1;
2438 for (decc = _xmlSchemaBase64Decode(*cur);
2439 (decc < 0) || (decc > 63);
2440 decc = _xmlSchemaBase64Decode(*cur))
2441 --cur;
2442 /* 8bits in 12bits means 4 pad bits: nnnnnn nn0000 */
2443 /* 00110000 -> 0x30 */
2444 if (decc & ~0x30)
2445 goto return1;
2446 total += 1;
2447 } else
2448 goto return1;
2449
2450 if (val != NULL) {
2451 v = xmlSchemaNewValue(XML_SCHEMAS_BASE64BINARY);
2452 if (v == NULL)
2453 goto error;
2454 base =
2455 (xmlChar *) xmlMallocAtomic((i + pad + 1) *
2456 sizeof(xmlChar));
2457 if (base == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002458 xmlSchemaTypeErrMemory(node, "allocating base64 data");
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002459 xmlFree(v);
2460 goto return1;
2461 }
2462 v->value.base64.str = base;
2463 for (cur = value; *cur; ++cur)
2464 if (_xmlSchemaBase64Decode(*cur) >= 0) {
2465 *base = *cur;
2466 ++base;
2467 }
2468 *base = 0;
2469 v->value.base64.total = total;
2470 *val = v;
2471 }
2472 goto return0;
2473 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002474 case XML_SCHEMAS_INTEGER:
2475 case XML_SCHEMAS_PINTEGER:
2476 case XML_SCHEMAS_NPINTEGER:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002477 case XML_SCHEMAS_NINTEGER:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002478 case XML_SCHEMAS_NNINTEGER:{
2479 const xmlChar *cur = value;
2480 unsigned long lo, mi, hi;
2481 int sign = 0;
2482
2483 if (cur == NULL)
2484 goto return1;
2485 if (*cur == '-') {
2486 sign = 1;
2487 cur++;
2488 } else if (*cur == '+')
2489 cur++;
2490 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2491 if (ret == 0)
2492 goto return1;
2493 if (*cur != 0)
2494 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002495 if (type->builtInType == XML_SCHEMAS_NPINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002496 if ((sign == 0) &&
2497 ((hi != 0) || (mi != 0) || (lo != 0)))
2498 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002499 } else if (type->builtInType == XML_SCHEMAS_PINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002500 if (sign == 1)
2501 goto return1;
2502 if ((hi == 0) && (mi == 0) && (lo == 0))
2503 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002504 } else if (type->builtInType == XML_SCHEMAS_NINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002505 if (sign == 0)
2506 goto return1;
2507 if ((hi == 0) && (mi == 0) && (lo == 0))
2508 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002509 } else if (type->builtInType == XML_SCHEMAS_NNINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002510 if ((sign == 1) &&
2511 ((hi != 0) || (mi != 0) || (lo != 0)))
2512 goto return1;
2513 }
2514 /*
2515 * We can store a value only if no overflow occured
2516 */
2517 if ((ret > 0) && (val != NULL)) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00002518 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002519 if (v != NULL) {
2520 v->value.decimal.lo = lo;
2521 v->value.decimal.mi = lo;
2522 v->value.decimal.hi = lo;
2523 v->value.decimal.sign = sign;
2524 v->value.decimal.frac = 0;
2525 v->value.decimal.total = cur - value;
2526 *val = v;
2527 }
2528 }
2529 goto return0;
2530 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002531 case XML_SCHEMAS_LONG:
2532 case XML_SCHEMAS_BYTE:
2533 case XML_SCHEMAS_SHORT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002534 case XML_SCHEMAS_INT:{
2535 const xmlChar *cur = value;
2536 unsigned long lo, mi, hi;
2537 int total = 0;
2538 int sign = 0;
2539
2540 if (cur == NULL)
2541 goto return1;
2542 if (*cur == '-') {
2543 sign = 1;
2544 cur++;
2545 } else if (*cur == '+')
2546 cur++;
2547 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2548 if (ret <= 0)
2549 goto return1;
2550 if (*cur != 0)
2551 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002552 if (type->builtInType == XML_SCHEMAS_LONG) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002553 if (hi >= 922) {
2554 if (hi > 922)
2555 goto return1;
2556 if (mi >= 33720368) {
2557 if (mi > 33720368)
2558 goto return1;
2559 if ((sign == 0) && (lo > 54775807))
2560 goto return1;
2561 if ((sign == 1) && (lo > 54775808))
2562 goto return1;
2563 }
2564 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002565 } else if (type->builtInType == XML_SCHEMAS_INT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002566 if (hi != 0)
2567 goto return1;
2568 if (mi >= 21) {
2569 if (mi > 21)
2570 goto return1;
2571 if ((sign == 0) && (lo > 47483647))
2572 goto return1;
2573 if ((sign == 1) && (lo > 47483648))
2574 goto return1;
2575 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002576 } else if (type->builtInType == XML_SCHEMAS_SHORT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002577 if ((mi != 0) || (hi != 0))
2578 goto return1;
2579 if ((sign == 1) && (lo > 32768))
2580 goto return1;
2581 if ((sign == 0) && (lo > 32767))
2582 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002583 } else if (type->builtInType == XML_SCHEMAS_BYTE) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002584 if ((mi != 0) || (hi != 0))
2585 goto return1;
2586 if ((sign == 1) && (lo > 128))
2587 goto return1;
2588 if ((sign == 0) && (lo > 127))
2589 goto return1;
2590 }
2591 if (val != NULL) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00002592 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002593 if (v != NULL) {
2594 v->value.decimal.lo = lo;
2595 v->value.decimal.mi = lo;
2596 v->value.decimal.hi = lo;
2597 v->value.decimal.sign = sign;
2598 v->value.decimal.frac = 0;
2599 v->value.decimal.total = total;
2600 *val = v;
2601 }
2602 }
2603 goto return0;
2604 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002605 case XML_SCHEMAS_UINT:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002606 case XML_SCHEMAS_ULONG:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002607 case XML_SCHEMAS_USHORT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002608 case XML_SCHEMAS_UBYTE:{
2609 const xmlChar *cur = value;
2610 unsigned long lo, mi, hi;
2611 int total = 0;
2612
2613 if (cur == NULL)
2614 goto return1;
2615 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2616 if (ret <= 0)
2617 goto return1;
2618 if (*cur != 0)
2619 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002620 if (type->builtInType == XML_SCHEMAS_ULONG) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002621 if (hi >= 1844) {
2622 if (hi > 1844)
2623 goto return1;
2624 if (mi >= 67440737) {
2625 if (mi > 67440737)
2626 goto return1;
2627 if (lo > 9551615)
2628 goto return1;
2629 }
2630 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002631 } else if (type->builtInType == XML_SCHEMAS_UINT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002632 if (hi != 0)
2633 goto return1;
2634 if (mi >= 42) {
2635 if (mi > 42)
2636 goto return1;
2637 if (lo > 94967295)
2638 goto return1;
2639 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002640 } else if (type->builtInType == XML_SCHEMAS_USHORT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002641 if ((mi != 0) || (hi != 0))
2642 goto return1;
2643 if (lo > 65535)
2644 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002645 } else if (type->builtInType == XML_SCHEMAS_UBYTE) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002646 if ((mi != 0) || (hi != 0))
2647 goto return1;
2648 if (lo > 255)
2649 goto return1;
2650 }
2651 if (val != NULL) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00002652 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002653 if (v != NULL) {
2654 v->value.decimal.lo = lo;
2655 v->value.decimal.mi = mi;
2656 v->value.decimal.hi = hi;
2657 v->value.decimal.sign = 0;
2658 v->value.decimal.frac = 0;
2659 v->value.decimal.total = total;
2660 *val = v;
2661 }
2662 }
2663 goto return0;
2664 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002665 }
2666
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002667 done:
2668 if (norm != NULL)
2669 xmlFree(norm);
2670 return (ret);
2671 return3:
2672 if (norm != NULL)
2673 xmlFree(norm);
2674 return (3);
2675 return1:
2676 if (norm != NULL)
2677 xmlFree(norm);
2678 return (1);
2679 return0:
2680 if (norm != NULL)
2681 xmlFree(norm);
2682 return (0);
2683 error:
2684 if (norm != NULL)
2685 xmlFree(norm);
2686 return (-1);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002687}
2688
2689/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002690 * xmlSchemaValPredefTypeNode:
Daniel Veillard4255d502002-04-16 15:50:10 +00002691 * @type: the predefined type
2692 * @value: the value to check
2693 * @val: the return computed value
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002694 * @node: the node containing the value
Daniel Veillard4255d502002-04-16 15:50:10 +00002695 *
2696 * Check that a value conforms to the lexical space of the predefined type.
2697 * if true a value is computed and returned in @val.
2698 *
2699 * Returns 0 if this validates, a positive error code number otherwise
2700 * and -1 in case of internal or API error.
2701 */
2702int
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002703xmlSchemaValPredefTypeNode(xmlSchemaTypePtr type, const xmlChar *value,
2704 xmlSchemaValPtr *val, xmlNodePtr node) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002705 return(xmlSchemaValAtomicType(type, value, val, node, 0));
Daniel Veillard4255d502002-04-16 15:50:10 +00002706}
2707
2708/**
Daniel Veillardc0826a72004-08-10 14:17:33 +00002709 * xmlSchemaValPredefTypeNodeNoNorm:
2710 * @type: the predefined type
2711 * @value: the value to check
2712 * @val: the return computed value
2713 * @node: the node containing the value
2714 *
2715 * Check that a value conforms to the lexical space of the predefined type.
2716 * if true a value is computed and returned in @val.
2717 * This one does apply any normalization to the value.
2718 *
2719 * Returns 0 if this validates, a positive error code number otherwise
2720 * and -1 in case of internal or API error.
2721 */
2722int
2723xmlSchemaValPredefTypeNodeNoNorm(xmlSchemaTypePtr type, const xmlChar *value,
2724 xmlSchemaValPtr *val, xmlNodePtr node) {
2725 return(xmlSchemaValAtomicType(type, value, val, node, 1));
2726}
2727
2728/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002729 * xmlSchemaValidatePredefinedType:
2730 * @type: the predefined type
2731 * @value: the value to check
2732 * @val: the return computed value
2733 *
2734 * Check that a value conforms to the lexical space of the predefined type.
2735 * if true a value is computed and returned in @val.
2736 *
2737 * Returns 0 if this validates, a positive error code number otherwise
2738 * and -1 in case of internal or API error.
2739 */
2740int
2741xmlSchemaValidatePredefinedType(xmlSchemaTypePtr type, const xmlChar *value,
2742 xmlSchemaValPtr *val) {
2743 return(xmlSchemaValPredefTypeNode(type, value, val, NULL));
2744}
2745
2746/**
Daniel Veillard4255d502002-04-16 15:50:10 +00002747 * xmlSchemaCompareDecimals:
2748 * @x: a first decimal value
2749 * @y: a second decimal value
2750 *
2751 * Compare 2 decimals
2752 *
2753 * Returns -1 if x < y, 0 if x == y, 1 if x > y and -2 in case of error
2754 */
2755static int
2756xmlSchemaCompareDecimals(xmlSchemaValPtr x, xmlSchemaValPtr y)
2757{
2758 xmlSchemaValPtr swp;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002759 int order = 1, p;
Daniel Veillard4255d502002-04-16 15:50:10 +00002760 unsigned long tmp;
2761
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002762 if ((x->value.decimal.sign) &&
2763 ((x->value.decimal.lo != 0) ||
2764 (x->value.decimal.mi != 0) ||
2765 (x->value.decimal.hi != 0))) {
2766 if ((y->value.decimal.sign) &&
2767 ((y->value.decimal.lo != 0) ||
2768 (y->value.decimal.mi != 0) ||
2769 (y->value.decimal.hi != 0)))
Daniel Veillard80b19092003-03-28 13:29:53 +00002770 order = -1;
2771 else
2772 return (-1);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002773 } else if ((y->value.decimal.sign) &&
2774 ((y->value.decimal.lo != 0) ||
2775 (y->value.decimal.mi != 0) ||
2776 (y->value.decimal.hi != 0))) {
Daniel Veillard4255d502002-04-16 15:50:10 +00002777 return (1);
Daniel Veillard80b19092003-03-28 13:29:53 +00002778 }
Daniel Veillard4255d502002-04-16 15:50:10 +00002779 if (x->value.decimal.frac == y->value.decimal.frac) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002780 if (x->value.decimal.hi < y->value.decimal.hi)
2781 return (-order);
Daniel Veillard01fa6152004-06-29 17:04:39 +00002782 if (x->value.decimal.hi > y->value.decimal.hi)
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002783 return (order);
2784 if (x->value.decimal.mi < y->value.decimal.mi)
2785 return (-order);
Daniel Veillard01fa6152004-06-29 17:04:39 +00002786 if (x->value.decimal.mi > y->value.decimal.mi)
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002787 return (order);
2788 if (x->value.decimal.lo < y->value.decimal.lo)
Daniel Veillard80b19092003-03-28 13:29:53 +00002789 return (-order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002790 if (x->value.decimal.lo > y->value.decimal.lo)
Daniel Veillard80b19092003-03-28 13:29:53 +00002791 return(order);
2792 return(0);
Daniel Veillard4255d502002-04-16 15:50:10 +00002793 }
2794 if (y->value.decimal.frac > x->value.decimal.frac) {
2795 swp = y;
2796 y = x;
2797 x = swp;
2798 order = -order;
2799 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002800 p = powten[x->value.decimal.frac - y->value.decimal.frac];
2801 tmp = x->value.decimal.lo / p;
2802 if (tmp > y->value.decimal.lo)
Daniel Veillard4255d502002-04-16 15:50:10 +00002803 return (order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002804 if (tmp < y->value.decimal.lo)
Daniel Veillard4255d502002-04-16 15:50:10 +00002805 return (-order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002806 tmp = y->value.decimal.lo * p;
2807 if (x->value.decimal.lo < tmp)
Daniel Veillard4255d502002-04-16 15:50:10 +00002808 return (-order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002809 if (x->value.decimal.lo == tmp)
Daniel Veillard4255d502002-04-16 15:50:10 +00002810 return (0);
2811 return (order);
2812}
2813
2814/**
Daniel Veillard070803b2002-05-03 07:29:38 +00002815 * xmlSchemaCompareDurations:
2816 * @x: a first duration value
2817 * @y: a second duration value
2818 *
2819 * Compare 2 durations
2820 *
2821 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
2822 * case of error
2823 */
2824static int
2825xmlSchemaCompareDurations(xmlSchemaValPtr x, xmlSchemaValPtr y)
2826{
2827 long carry, mon, day;
2828 double sec;
Daniel Veillard80b19092003-03-28 13:29:53 +00002829 int invert = 1;
2830 long xmon, xday, myear, minday, maxday;
Daniel Veillard070803b2002-05-03 07:29:38 +00002831 static const long dayRange [2][12] = {
2832 { 0, 28, 59, 89, 120, 150, 181, 212, 242, 273, 303, 334, },
2833 { 0, 31, 62, 92, 123, 153, 184, 215, 245, 276, 306, 337} };
2834
2835 if ((x == NULL) || (y == NULL))
Daniel Veillard5a872412002-05-22 06:40:27 +00002836 return -2;
Daniel Veillard070803b2002-05-03 07:29:38 +00002837
2838 /* months */
2839 mon = x->value.dur.mon - y->value.dur.mon;
2840
2841 /* seconds */
2842 sec = x->value.dur.sec - y->value.dur.sec;
2843 carry = (long)sec / SECS_PER_DAY;
2844 sec -= (double)(carry * SECS_PER_DAY);
2845
2846 /* days */
2847 day = x->value.dur.day - y->value.dur.day + carry;
2848
2849 /* easy test */
2850 if (mon == 0) {
2851 if (day == 0)
2852 if (sec == 0.0)
2853 return 0;
2854 else if (sec < 0.0)
2855 return -1;
2856 else
2857 return 1;
2858 else if (day < 0)
2859 return -1;
2860 else
2861 return 1;
2862 }
2863
2864 if (mon > 0) {
2865 if ((day >= 0) && (sec >= 0.0))
2866 return 1;
2867 else {
2868 xmon = mon;
2869 xday = -day;
2870 }
2871 } else if ((day <= 0) && (sec <= 0.0)) {
2872 return -1;
2873 } else {
Daniel Veillard80b19092003-03-28 13:29:53 +00002874 invert = -1;
Daniel Veillard070803b2002-05-03 07:29:38 +00002875 xmon = -mon;
2876 xday = day;
2877 }
2878
2879 myear = xmon / 12;
Daniel Veillard80b19092003-03-28 13:29:53 +00002880 if (myear == 0) {
2881 minday = 0;
2882 maxday = 0;
2883 } else {
2884 maxday = 366 * ((myear + 3) / 4) +
2885 365 * ((myear - 1) % 4);
2886 minday = maxday - 1;
2887 }
2888
Daniel Veillard070803b2002-05-03 07:29:38 +00002889 xmon = xmon % 12;
2890 minday += dayRange[0][xmon];
2891 maxday += dayRange[1][xmon];
2892
Daniel Veillard80b19092003-03-28 13:29:53 +00002893 if ((maxday == minday) && (maxday == xday))
2894 return(0); /* can this really happen ? */
Daniel Veillard070803b2002-05-03 07:29:38 +00002895 if (maxday < xday)
Daniel Veillard80b19092003-03-28 13:29:53 +00002896 return(-invert);
2897 if (minday > xday)
2898 return(invert);
Daniel Veillard070803b2002-05-03 07:29:38 +00002899
2900 /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00002901 return 2;
2902}
2903
2904/*
2905 * macros for adding date/times and durations
2906 */
2907#define FQUOTIENT(a,b) (floor(((double)a/(double)b)))
2908#define MODULO(a,b) (a - FQUOTIENT(a,b) * b)
2909#define FQUOTIENT_RANGE(a,low,high) (FQUOTIENT((a-low),(high-low)))
2910#define MODULO_RANGE(a,low,high) ((MODULO((a-low),(high-low)))+low)
2911
2912/**
Daniel Veillard669adfc2004-05-29 20:12:46 +00002913 * xmlSchemaDupVal:
2914 * @v: the #xmlSchemaValPtr value to duplicate
2915 *
2916 * Makes a copy of @v. The calling program is responsible for freeing
2917 * the returned value.
2918 *
2919 * returns a pointer to a duplicated #xmlSchemaValPtr or NULL if error.
2920 */
2921static xmlSchemaValPtr
2922xmlSchemaDupVal (xmlSchemaValPtr v)
2923{
2924 xmlSchemaValPtr ret = xmlSchemaNewValue(v->type);
2925 if (ret == NULL)
2926 return NULL;
2927
2928 memcpy(ret, v, sizeof(xmlSchemaVal));
2929 return ret;
2930}
2931
2932/**
Daniel Veillard5a872412002-05-22 06:40:27 +00002933 * _xmlSchemaDateAdd:
2934 * @dt: an #xmlSchemaValPtr
2935 * @dur: an #xmlSchemaValPtr of type #XS_DURATION
2936 *
2937 * Compute a new date/time from @dt and @dur. This function assumes @dt
2938 * is either #XML_SCHEMAS_DATETIME, #XML_SCHEMAS_DATE, #XML_SCHEMAS_GYEARMONTH,
Daniel Veillard669adfc2004-05-29 20:12:46 +00002939 * or #XML_SCHEMAS_GYEAR. The returned #xmlSchemaVal is the same type as
2940 * @dt. The calling program is responsible for freeing the returned value.
Daniel Veillard5a872412002-05-22 06:40:27 +00002941 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00002942 * Returns a pointer to a new #xmlSchemaVal or NULL if error.
Daniel Veillard5a872412002-05-22 06:40:27 +00002943 */
2944static xmlSchemaValPtr
2945_xmlSchemaDateAdd (xmlSchemaValPtr dt, xmlSchemaValPtr dur)
2946{
Daniel Veillard669adfc2004-05-29 20:12:46 +00002947 xmlSchemaValPtr ret, tmp;
Daniel Veillard5a872412002-05-22 06:40:27 +00002948 long carry, tempdays, temp;
2949 xmlSchemaValDatePtr r, d;
2950 xmlSchemaValDurationPtr u;
2951
2952 if ((dt == NULL) || (dur == NULL))
2953 return NULL;
2954
2955 ret = xmlSchemaNewValue(dt->type);
2956 if (ret == NULL)
2957 return NULL;
2958
Daniel Veillard669adfc2004-05-29 20:12:46 +00002959 /* make a copy so we don't alter the original value */
2960 tmp = xmlSchemaDupVal(dt);
2961 if (tmp == NULL) {
2962 xmlSchemaFreeValue(ret);
2963 return NULL;
2964 }
2965
Daniel Veillard5a872412002-05-22 06:40:27 +00002966 r = &(ret->value.date);
Daniel Veillard669adfc2004-05-29 20:12:46 +00002967 d = &(tmp->value.date);
Daniel Veillard5a872412002-05-22 06:40:27 +00002968 u = &(dur->value.dur);
2969
2970 /* normalization */
2971 if (d->mon == 0)
2972 d->mon = 1;
2973
2974 /* normalize for time zone offset */
2975 u->sec -= (d->tzo * 60);
2976 d->tzo = 0;
2977
2978 /* normalization */
2979 if (d->day == 0)
2980 d->day = 1;
2981
2982 /* month */
2983 carry = d->mon + u->mon;
Daniel Veillardebe25d42004-03-25 09:35:49 +00002984 r->mon = (unsigned int) MODULO_RANGE(carry, 1, 13);
2985 carry = (long) FQUOTIENT_RANGE(carry, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00002986
2987 /* year (may be modified later) */
2988 r->year = d->year + carry;
2989 if (r->year == 0) {
2990 if (d->year > 0)
2991 r->year--;
2992 else
2993 r->year++;
2994 }
2995
2996 /* time zone */
2997 r->tzo = d->tzo;
2998 r->tz_flag = d->tz_flag;
2999
3000 /* seconds */
3001 r->sec = d->sec + u->sec;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003002 carry = (long) FQUOTIENT((long)r->sec, 60);
Daniel Veillard5a872412002-05-22 06:40:27 +00003003 if (r->sec != 0.0) {
3004 r->sec = MODULO(r->sec, 60.0);
3005 }
3006
3007 /* minute */
3008 carry += d->min;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003009 r->min = (unsigned int) MODULO(carry, 60);
3010 carry = (long) FQUOTIENT(carry, 60);
Daniel Veillard5a872412002-05-22 06:40:27 +00003011
3012 /* hours */
3013 carry += d->hour;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003014 r->hour = (unsigned int) MODULO(carry, 24);
3015 carry = (long)FQUOTIENT(carry, 24);
Daniel Veillard5a872412002-05-22 06:40:27 +00003016
3017 /*
3018 * days
3019 * Note we use tempdays because the temporary values may need more
3020 * than 5 bits
3021 */
3022 if ((VALID_YEAR(r->year)) && (VALID_MONTH(r->mon)) &&
3023 (d->day > MAX_DAYINMONTH(r->year, r->mon)))
3024 tempdays = MAX_DAYINMONTH(r->year, r->mon);
3025 else if (d->day < 1)
3026 tempdays = 1;
3027 else
3028 tempdays = d->day;
3029
3030 tempdays += u->day + carry;
3031
3032 while (1) {
3033 if (tempdays < 1) {
Daniel Veillardebe25d42004-03-25 09:35:49 +00003034 long tmon = (long) MODULO_RANGE(r->mon-1, 1, 13);
3035 long tyr = r->year + (long)FQUOTIENT_RANGE(r->mon-1, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00003036 if (tyr == 0)
3037 tyr--;
3038 tempdays += MAX_DAYINMONTH(tyr, tmon);
3039 carry = -1;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003040 } else if (tempdays > (long) MAX_DAYINMONTH(r->year, r->mon)) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003041 tempdays = tempdays - MAX_DAYINMONTH(r->year, r->mon);
3042 carry = 1;
3043 } else
3044 break;
3045
3046 temp = r->mon + carry;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003047 r->mon = (unsigned int) MODULO_RANGE(temp, 1, 13);
3048 r->year = r->year + (unsigned int) FQUOTIENT_RANGE(temp, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00003049 if (r->year == 0) {
3050 if (temp < 1)
3051 r->year--;
3052 else
3053 r->year++;
3054 }
3055 }
3056
3057 r->day = tempdays;
3058
3059 /*
3060 * adjust the date/time type to the date values
3061 */
3062 if (ret->type != XML_SCHEMAS_DATETIME) {
3063 if ((r->hour) || (r->min) || (r->sec))
3064 ret->type = XML_SCHEMAS_DATETIME;
3065 else if (ret->type != XML_SCHEMAS_DATE) {
3066 if ((r->mon != 1) && (r->day != 1))
3067 ret->type = XML_SCHEMAS_DATE;
3068 else if ((ret->type != XML_SCHEMAS_GYEARMONTH) && (r->mon != 1))
3069 ret->type = XML_SCHEMAS_GYEARMONTH;
3070 }
3071 }
3072
Daniel Veillard669adfc2004-05-29 20:12:46 +00003073 xmlSchemaFreeValue(tmp);
Daniel Veillard5a872412002-05-22 06:40:27 +00003074
Daniel Veillard5a872412002-05-22 06:40:27 +00003075 return ret;
3076}
3077
3078/**
3079 * xmlSchemaDateNormalize:
Daniel Veillard669adfc2004-05-29 20:12:46 +00003080 * @dt: an #xmlSchemaValPtr of a date/time type value.
3081 * @offset: number of seconds to adjust @dt by.
Daniel Veillard5a872412002-05-22 06:40:27 +00003082 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00003083 * Normalize @dt to GMT time. The @offset parameter is subtracted from
3084 * the return value is a time-zone offset is present on @dt.
Daniel Veillard5a872412002-05-22 06:40:27 +00003085 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00003086 * Returns a normalized copy of @dt or NULL if error.
Daniel Veillard5a872412002-05-22 06:40:27 +00003087 */
3088static xmlSchemaValPtr
3089xmlSchemaDateNormalize (xmlSchemaValPtr dt, double offset)
3090{
3091 xmlSchemaValPtr dur, ret;
3092
3093 if (dt == NULL)
3094 return NULL;
3095
3096 if (((dt->type != XML_SCHEMAS_TIME) &&
3097 (dt->type != XML_SCHEMAS_DATETIME)) || (dt->value.date.tzo == 0))
3098 return xmlSchemaDupVal(dt);
3099
3100 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
3101 if (dur == NULL)
3102 return NULL;
3103
3104 dur->value.date.sec -= offset;
3105
3106 ret = _xmlSchemaDateAdd(dt, dur);
3107 if (ret == NULL)
3108 return NULL;
3109
3110 xmlSchemaFreeValue(dur);
3111
3112 /* ret->value.date.tzo = 0; */
3113 return ret;
3114}
3115
3116/**
3117 * _xmlSchemaDateCastYMToDays:
3118 * @dt: an #xmlSchemaValPtr
3119 *
3120 * Convert mon and year of @dt to total number of days. Take the
3121 * number of years since (or before) 1 AD and add the number of leap
3122 * years. This is a function because negative
3123 * years must be handled a little differently and there is no zero year.
3124 *
3125 * Returns number of days.
3126 */
3127static long
3128_xmlSchemaDateCastYMToDays (const xmlSchemaValPtr dt)
3129{
3130 long ret;
Daniel Veillard49e89632004-09-23 16:24:36 +00003131 int mon;
Daniel Veillard5a872412002-05-22 06:40:27 +00003132
Daniel Veillard49e89632004-09-23 16:24:36 +00003133 mon = dt->value.date.mon;
3134 if (mon <= 0) mon = 1; /* normalization */
3135
3136 if (dt->value.date.year <= 0)
Daniel Veillard5a872412002-05-22 06:40:27 +00003137 ret = (dt->value.date.year * 365) +
3138 (((dt->value.date.year+1)/4)-((dt->value.date.year+1)/100)+
3139 ((dt->value.date.year+1)/400)) +
Daniel Veillard49e89632004-09-23 16:24:36 +00003140 DAY_IN_YEAR(0, mon, dt->value.date.year);
Daniel Veillard5a872412002-05-22 06:40:27 +00003141 else
3142 ret = ((dt->value.date.year-1) * 365) +
3143 (((dt->value.date.year-1)/4)-((dt->value.date.year-1)/100)+
3144 ((dt->value.date.year-1)/400)) +
Daniel Veillard49e89632004-09-23 16:24:36 +00003145 DAY_IN_YEAR(0, mon, dt->value.date.year);
Daniel Veillard5a872412002-05-22 06:40:27 +00003146
3147 return ret;
3148}
3149
3150/**
3151 * TIME_TO_NUMBER:
3152 * @dt: an #xmlSchemaValPtr
3153 *
3154 * Calculates the number of seconds in the time portion of @dt.
3155 *
3156 * Returns seconds.
3157 */
3158#define TIME_TO_NUMBER(dt) \
3159 ((double)((dt->value.date.hour * SECS_PER_HOUR) + \
Daniel Veillardb3721c22003-03-31 11:22:25 +00003160 (dt->value.date.min * SECS_PER_MIN) + \
3161 (dt->value.date.tzo * SECS_PER_MIN)) + \
3162 dt->value.date.sec)
Daniel Veillard5a872412002-05-22 06:40:27 +00003163
3164/**
3165 * xmlSchemaCompareDates:
3166 * @x: a first date/time value
3167 * @y: a second date/time value
3168 *
3169 * Compare 2 date/times
3170 *
3171 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3172 * case of error
3173 */
3174static int
3175xmlSchemaCompareDates (xmlSchemaValPtr x, xmlSchemaValPtr y)
3176{
3177 unsigned char xmask, ymask, xor_mask, and_mask;
3178 xmlSchemaValPtr p1, p2, q1, q2;
3179 long p1d, p2d, q1d, q2d;
3180
3181 if ((x == NULL) || (y == NULL))
3182 return -2;
3183
3184 if (x->value.date.tz_flag) {
3185
3186 if (!y->value.date.tz_flag) {
3187 p1 = xmlSchemaDateNormalize(x, 0);
3188 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3189 /* normalize y + 14:00 */
3190 q1 = xmlSchemaDateNormalize(y, (14 * SECS_PER_HOUR));
3191
3192 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003193 if (p1d < q1d) {
3194 xmlSchemaFreeValue(p1);
3195 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003196 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003197 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003198 double sec;
3199
3200 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00003201 if (sec < 0.0) {
3202 xmlSchemaFreeValue(p1);
3203 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003204 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003205 } else {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003206 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003207 /* normalize y - 14:00 */
3208 q2 = xmlSchemaDateNormalize(y, -(14 * SECS_PER_HOUR));
3209 q2d = _xmlSchemaDateCastYMToDays(q2) + q2->value.date.day;
3210 if (p1d > q2d)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003211 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003212 else if (p1d == q2d) {
3213 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q2);
3214 if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003215 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003216 else
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003217 ret = 2; /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00003218 }
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003219 xmlSchemaFreeValue(p1);
3220 xmlSchemaFreeValue(q1);
3221 xmlSchemaFreeValue(q2);
3222 if (ret != 0)
3223 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003224 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00003225 } else {
3226 xmlSchemaFreeValue(p1);
3227 xmlSchemaFreeValue(q1);
3228 }
Daniel Veillard5a872412002-05-22 06:40:27 +00003229 }
3230 } else if (y->value.date.tz_flag) {
3231 q1 = xmlSchemaDateNormalize(y, 0);
3232 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
3233
3234 /* normalize x - 14:00 */
3235 p1 = xmlSchemaDateNormalize(x, -(14 * SECS_PER_HOUR));
3236 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3237
Daniel Veillardfdc91562002-07-01 21:52:03 +00003238 if (p1d < q1d) {
3239 xmlSchemaFreeValue(p1);
3240 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003241 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003242 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003243 double sec;
3244
3245 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00003246 if (sec < 0.0) {
3247 xmlSchemaFreeValue(p1);
3248 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003249 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003250 } else {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003251 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003252 /* normalize x + 14:00 */
3253 p2 = xmlSchemaDateNormalize(x, (14 * SECS_PER_HOUR));
3254 p2d = _xmlSchemaDateCastYMToDays(p2) + p2->value.date.day;
3255
Daniel Veillard6560a422003-03-27 21:25:38 +00003256 if (p2d > q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003257 ret = 1;
Daniel Veillard6560a422003-03-27 21:25:38 +00003258 } else if (p2d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003259 sec = TIME_TO_NUMBER(p2) - TIME_TO_NUMBER(q1);
3260 if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003261 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003262 else
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003263 ret = 2; /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00003264 }
Daniel Veillard6560a422003-03-27 21:25:38 +00003265 xmlSchemaFreeValue(p1);
3266 xmlSchemaFreeValue(q1);
3267 xmlSchemaFreeValue(p2);
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003268 if (ret != 0)
3269 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003270 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00003271 } else {
3272 xmlSchemaFreeValue(p1);
3273 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003274 }
3275 }
3276
3277 /*
3278 * if the same type then calculate the difference
3279 */
3280 if (x->type == y->type) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003281 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003282 q1 = xmlSchemaDateNormalize(y, 0);
3283 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
3284
3285 p1 = xmlSchemaDateNormalize(x, 0);
3286 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3287
Daniel Veillardfdc91562002-07-01 21:52:03 +00003288 if (p1d < q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003289 ret = -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003290 } else if (p1d > q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003291 ret = 1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003292 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00003293 double sec;
3294
3295 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
3296 if (sec < 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003297 ret = -1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003298 else if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003299 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003300
3301 }
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003302 xmlSchemaFreeValue(p1);
3303 xmlSchemaFreeValue(q1);
3304 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003305 }
3306
3307 switch (x->type) {
3308 case XML_SCHEMAS_DATETIME:
3309 xmask = 0xf;
3310 break;
3311 case XML_SCHEMAS_DATE:
3312 xmask = 0x7;
3313 break;
3314 case XML_SCHEMAS_GYEAR:
3315 xmask = 0x1;
3316 break;
3317 case XML_SCHEMAS_GMONTH:
3318 xmask = 0x2;
3319 break;
3320 case XML_SCHEMAS_GDAY:
3321 xmask = 0x3;
3322 break;
3323 case XML_SCHEMAS_GYEARMONTH:
3324 xmask = 0x3;
3325 break;
3326 case XML_SCHEMAS_GMONTHDAY:
3327 xmask = 0x6;
3328 break;
3329 case XML_SCHEMAS_TIME:
3330 xmask = 0x8;
3331 break;
3332 default:
3333 xmask = 0;
3334 break;
3335 }
3336
3337 switch (y->type) {
3338 case XML_SCHEMAS_DATETIME:
3339 ymask = 0xf;
3340 break;
3341 case XML_SCHEMAS_DATE:
3342 ymask = 0x7;
3343 break;
3344 case XML_SCHEMAS_GYEAR:
3345 ymask = 0x1;
3346 break;
3347 case XML_SCHEMAS_GMONTH:
3348 ymask = 0x2;
3349 break;
3350 case XML_SCHEMAS_GDAY:
3351 ymask = 0x3;
3352 break;
3353 case XML_SCHEMAS_GYEARMONTH:
3354 ymask = 0x3;
3355 break;
3356 case XML_SCHEMAS_GMONTHDAY:
3357 ymask = 0x6;
3358 break;
3359 case XML_SCHEMAS_TIME:
3360 ymask = 0x8;
3361 break;
3362 default:
3363 ymask = 0;
3364 break;
3365 }
3366
3367 xor_mask = xmask ^ ymask; /* mark type differences */
3368 and_mask = xmask & ymask; /* mark field specification */
3369
3370 /* year */
3371 if (xor_mask & 1)
3372 return 2; /* indeterminate */
3373 else if (and_mask & 1) {
3374 if (x->value.date.year < y->value.date.year)
3375 return -1;
3376 else if (x->value.date.year > y->value.date.year)
3377 return 1;
3378 }
3379
3380 /* month */
3381 if (xor_mask & 2)
3382 return 2; /* indeterminate */
3383 else if (and_mask & 2) {
3384 if (x->value.date.mon < y->value.date.mon)
3385 return -1;
3386 else if (x->value.date.mon > y->value.date.mon)
3387 return 1;
3388 }
3389
3390 /* day */
3391 if (xor_mask & 4)
3392 return 2; /* indeterminate */
3393 else if (and_mask & 4) {
3394 if (x->value.date.day < y->value.date.day)
3395 return -1;
3396 else if (x->value.date.day > y->value.date.day)
3397 return 1;
3398 }
3399
3400 /* time */
3401 if (xor_mask & 8)
3402 return 2; /* indeterminate */
3403 else if (and_mask & 8) {
3404 if (x->value.date.hour < y->value.date.hour)
3405 return -1;
3406 else if (x->value.date.hour > y->value.date.hour)
3407 return 1;
3408 else if (x->value.date.min < y->value.date.min)
3409 return -1;
3410 else if (x->value.date.min > y->value.date.min)
3411 return 1;
3412 else if (x->value.date.sec < y->value.date.sec)
3413 return -1;
3414 else if (x->value.date.sec > y->value.date.sec)
3415 return 1;
3416 }
3417
Daniel Veillard070803b2002-05-03 07:29:38 +00003418 return 0;
3419}
3420
3421/**
Daniel Veillardc4c21552003-03-29 10:53:38 +00003422 * xmlSchemaCompareNormStrings:
3423 * @x: a first string value
3424 * @y: a second string value
3425 *
3426 * Compare 2 string for their normalized values.
3427 *
3428 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
3429 * case of error
3430 */
3431static int
3432xmlSchemaCompareNormStrings(xmlSchemaValPtr x, xmlSchemaValPtr y) {
3433 const xmlChar *utf1;
3434 const xmlChar *utf2;
3435 int tmp;
3436
3437 if ((x == NULL) || (y == NULL))
3438 return(-2);
3439 utf1 = x->value.str;
3440 utf2 = y->value.str;
3441
William M. Brack76e95df2003-10-18 16:20:14 +00003442 while (IS_BLANK_CH(*utf1)) utf1++;
3443 while (IS_BLANK_CH(*utf2)) utf2++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003444 while ((*utf1 != 0) && (*utf2 != 0)) {
William M. Brack76e95df2003-10-18 16:20:14 +00003445 if (IS_BLANK_CH(*utf1)) {
3446 if (!IS_BLANK_CH(*utf2)) {
Daniel Veillardc4c21552003-03-29 10:53:38 +00003447 tmp = *utf1 - *utf2;
3448 return(tmp);
3449 }
William M. Brack76e95df2003-10-18 16:20:14 +00003450 while (IS_BLANK_CH(*utf1)) utf1++;
3451 while (IS_BLANK_CH(*utf2)) utf2++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003452 } else {
3453 tmp = *utf1++ - *utf2++;
3454 if (tmp < 0)
3455 return(-1);
3456 if (tmp > 0)
3457 return(1);
3458 }
3459 }
3460 if (*utf1 != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00003461 while (IS_BLANK_CH(*utf1)) utf1++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003462 if (*utf1 != 0)
3463 return(1);
3464 }
3465 if (*utf2 != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00003466 while (IS_BLANK_CH(*utf2)) utf2++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003467 if (*utf2 != 0)
3468 return(-1);
3469 }
3470 return(0);
3471}
3472
3473/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003474 * xmlSchemaCompareFloats:
3475 * @x: a first float or double value
3476 * @y: a second float or double value
3477 *
3478 * Compare 2 values
3479 *
3480 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3481 * case of error
3482 */
3483static int
3484xmlSchemaCompareFloats(xmlSchemaValPtr x, xmlSchemaValPtr y) {
3485 double d1, d2;
3486
3487 if ((x == NULL) || (y == NULL))
3488 return(-2);
3489
3490 /*
3491 * Cast everything to doubles.
3492 */
3493 if (x->type == XML_SCHEMAS_DOUBLE)
3494 d1 = x->value.d;
3495 else if (x->type == XML_SCHEMAS_FLOAT)
3496 d1 = x->value.f;
3497 else
3498 return(-2);
3499
3500 if (y->type == XML_SCHEMAS_DOUBLE)
3501 d2 = y->value.d;
3502 else if (y->type == XML_SCHEMAS_FLOAT)
3503 d2 = y->value.f;
3504 else
3505 return(-2);
3506
3507 /*
3508 * Check for special cases.
3509 */
3510 if (xmlXPathIsNaN(d1)) {
3511 if (xmlXPathIsNaN(d2))
3512 return(0);
3513 return(1);
3514 }
3515 if (xmlXPathIsNaN(d2))
3516 return(-1);
3517 if (d1 == xmlXPathPINF) {
3518 if (d2 == xmlXPathPINF)
3519 return(0);
3520 return(1);
3521 }
3522 if (d2 == xmlXPathPINF)
3523 return(-1);
3524 if (d1 == xmlXPathNINF) {
3525 if (d2 == xmlXPathNINF)
3526 return(0);
3527 return(-1);
3528 }
3529 if (d2 == xmlXPathNINF)
3530 return(1);
3531
3532 /*
3533 * basic tests, the last one we should have equality, but
3534 * portability is more important than speed and handling
3535 * NaN or Inf in a portable way is always a challenge, so ...
3536 */
3537 if (d1 < d2)
3538 return(-1);
3539 if (d1 > d2)
3540 return(1);
3541 if (d1 == d2)
3542 return(0);
3543 return(2);
3544}
3545
3546/**
Daniel Veillard4255d502002-04-16 15:50:10 +00003547 * xmlSchemaCompareValues:
3548 * @x: a first value
3549 * @y: a second value
3550 *
3551 * Compare 2 values
3552 *
Daniel Veillard5a872412002-05-22 06:40:27 +00003553 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3554 * case of error
Daniel Veillard4255d502002-04-16 15:50:10 +00003555 */
Daniel Veillard80b19092003-03-28 13:29:53 +00003556int
Daniel Veillard4255d502002-04-16 15:50:10 +00003557xmlSchemaCompareValues(xmlSchemaValPtr x, xmlSchemaValPtr y) {
3558 if ((x == NULL) || (y == NULL))
3559 return(-2);
3560
3561 switch (x->type) {
Daniel Veillard80b19092003-03-28 13:29:53 +00003562 case XML_SCHEMAS_UNKNOWN:
William M. Brack2f2a6632004-08-20 23:09:47 +00003563 case XML_SCHEMAS_ANYTYPE:
3564 case XML_SCHEMAS_ANYSIMPLETYPE:
Daniel Veillard80b19092003-03-28 13:29:53 +00003565 return(-2);
3566 case XML_SCHEMAS_INTEGER:
3567 case XML_SCHEMAS_NPINTEGER:
3568 case XML_SCHEMAS_NINTEGER:
3569 case XML_SCHEMAS_NNINTEGER:
3570 case XML_SCHEMAS_PINTEGER:
3571 case XML_SCHEMAS_INT:
3572 case XML_SCHEMAS_UINT:
3573 case XML_SCHEMAS_LONG:
3574 case XML_SCHEMAS_ULONG:
3575 case XML_SCHEMAS_SHORT:
3576 case XML_SCHEMAS_USHORT:
3577 case XML_SCHEMAS_BYTE:
3578 case XML_SCHEMAS_UBYTE:
Daniel Veillard4255d502002-04-16 15:50:10 +00003579 case XML_SCHEMAS_DECIMAL:
Daniel Veillard80b19092003-03-28 13:29:53 +00003580 if (y->type == x->type)
3581 return(xmlSchemaCompareDecimals(x, y));
3582 if ((y->type == XML_SCHEMAS_DECIMAL) ||
3583 (y->type == XML_SCHEMAS_INTEGER) ||
3584 (y->type == XML_SCHEMAS_NPINTEGER) ||
3585 (y->type == XML_SCHEMAS_NINTEGER) ||
3586 (y->type == XML_SCHEMAS_NNINTEGER) ||
3587 (y->type == XML_SCHEMAS_PINTEGER) ||
3588 (y->type == XML_SCHEMAS_INT) ||
3589 (y->type == XML_SCHEMAS_UINT) ||
3590 (y->type == XML_SCHEMAS_LONG) ||
3591 (y->type == XML_SCHEMAS_ULONG) ||
3592 (y->type == XML_SCHEMAS_SHORT) ||
3593 (y->type == XML_SCHEMAS_USHORT) ||
3594 (y->type == XML_SCHEMAS_BYTE) ||
3595 (y->type == XML_SCHEMAS_UBYTE))
Daniel Veillard4255d502002-04-16 15:50:10 +00003596 return(xmlSchemaCompareDecimals(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00003597 return(-2);
Daniel Veillard070803b2002-05-03 07:29:38 +00003598 case XML_SCHEMAS_DURATION:
3599 if (y->type == XML_SCHEMAS_DURATION)
3600 return(xmlSchemaCompareDurations(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00003601 return(-2);
3602 case XML_SCHEMAS_TIME:
3603 case XML_SCHEMAS_GDAY:
3604 case XML_SCHEMAS_GMONTH:
3605 case XML_SCHEMAS_GMONTHDAY:
3606 case XML_SCHEMAS_GYEAR:
3607 case XML_SCHEMAS_GYEARMONTH:
3608 case XML_SCHEMAS_DATE:
3609 case XML_SCHEMAS_DATETIME:
3610 if ((y->type == XML_SCHEMAS_DATETIME) ||
3611 (y->type == XML_SCHEMAS_TIME) ||
3612 (y->type == XML_SCHEMAS_GDAY) ||
3613 (y->type == XML_SCHEMAS_GMONTH) ||
3614 (y->type == XML_SCHEMAS_GMONTHDAY) ||
3615 (y->type == XML_SCHEMAS_GYEAR) ||
3616 (y->type == XML_SCHEMAS_DATE) ||
3617 (y->type == XML_SCHEMAS_GYEARMONTH))
3618 return (xmlSchemaCompareDates(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00003619 return (-2);
Daniel Veillard80b19092003-03-28 13:29:53 +00003620 case XML_SCHEMAS_NORMSTRING:
Daniel Veillard80b19092003-03-28 13:29:53 +00003621 case XML_SCHEMAS_TOKEN:
3622 case XML_SCHEMAS_LANGUAGE:
3623 case XML_SCHEMAS_NMTOKEN:
Daniel Veillard80b19092003-03-28 13:29:53 +00003624 case XML_SCHEMAS_NAME:
Daniel Veillard80b19092003-03-28 13:29:53 +00003625 case XML_SCHEMAS_NCNAME:
3626 case XML_SCHEMAS_ID:
3627 case XML_SCHEMAS_IDREF:
Daniel Veillard80b19092003-03-28 13:29:53 +00003628 case XML_SCHEMAS_ENTITY:
Daniel Veillard80b19092003-03-28 13:29:53 +00003629 case XML_SCHEMAS_NOTATION:
3630 case XML_SCHEMAS_ANYURI:
Daniel Veillardc4c21552003-03-29 10:53:38 +00003631 if ((y->type == XML_SCHEMAS_NORMSTRING) ||
3632 (y->type == XML_SCHEMAS_TOKEN) ||
3633 (y->type == XML_SCHEMAS_LANGUAGE) ||
3634 (y->type == XML_SCHEMAS_NMTOKEN) ||
3635 (y->type == XML_SCHEMAS_NAME) ||
3636 (y->type == XML_SCHEMAS_QNAME) ||
3637 (y->type == XML_SCHEMAS_NCNAME) ||
3638 (y->type == XML_SCHEMAS_ID) ||
3639 (y->type == XML_SCHEMAS_IDREF) ||
3640 (y->type == XML_SCHEMAS_ENTITY) ||
3641 (y->type == XML_SCHEMAS_NOTATION) ||
3642 (y->type == XML_SCHEMAS_ANYURI))
3643 return (xmlSchemaCompareNormStrings(x, y));
3644 return (-2);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003645 case XML_SCHEMAS_QNAME:
3646 if (y->type == XML_SCHEMAS_QNAME) {
3647 if ((xmlStrEqual(x->value.qname.name, y->value.qname.name)) &&
3648 (xmlStrEqual(x->value.qname.uri, y->value.qname.uri)))
3649 return(0);
3650 return(2);
3651 }
3652 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00003653 case XML_SCHEMAS_FLOAT:
3654 case XML_SCHEMAS_DOUBLE:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003655 if ((y->type == XML_SCHEMAS_FLOAT) ||
3656 (y->type == XML_SCHEMAS_DOUBLE))
3657 return (xmlSchemaCompareFloats(x, y));
3658 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00003659 case XML_SCHEMAS_BOOLEAN:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003660 if (y->type == XML_SCHEMAS_BOOLEAN) {
3661 if (x->value.b == y->value.b)
3662 return(0);
3663 if (x->value.b == 0)
3664 return(-1);
3665 return(1);
3666 }
3667 return (-2);
Daniel Veillard560c2a42003-07-06 21:13:49 +00003668 case XML_SCHEMAS_HEXBINARY:
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00003669 if (y->type == XML_SCHEMAS_HEXBINARY) {
3670 if (x->value.hex.total == y->value.hex.total) {
3671 int ret = xmlStrcmp(x->value.hex.str, y->value.hex.str);
3672 if (ret > 0)
3673 return(1);
3674 else if (ret == 0)
3675 return(0);
3676 }
3677 else if (x->value.hex.total > y->value.hex.total)
3678 return(1);
3679
3680 return(-1);
3681 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00003682 return (-2);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003683 case XML_SCHEMAS_BASE64BINARY:
3684 if (y->type == XML_SCHEMAS_BASE64BINARY) {
3685 if (x->value.base64.total == y->value.base64.total) {
3686 int ret = xmlStrcmp(x->value.base64.str,
3687 y->value.base64.str);
3688 if (ret > 0)
3689 return(1);
3690 else if (ret == 0)
3691 return(0);
3692 }
3693 else if (x->value.base64.total > y->value.base64.total)
3694 return(1);
3695 else
3696 return(-1);
3697 }
3698 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00003699 case XML_SCHEMAS_STRING:
3700 case XML_SCHEMAS_IDREFS:
3701 case XML_SCHEMAS_ENTITIES:
3702 case XML_SCHEMAS_NMTOKENS:
3703 TODO
3704 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00003705 }
Daniel Veillard5a872412002-05-22 06:40:27 +00003706 return -2;
Daniel Veillard4255d502002-04-16 15:50:10 +00003707}
3708
3709/**
Daniel Veillardc4c21552003-03-29 10:53:38 +00003710 * xmlSchemaNormLen:
3711 * @value: a string
3712 *
3713 * Computes the UTF8 length of the normalized value of the string
3714 *
3715 * Returns the length or -1 in case of error.
3716 */
3717static int
3718xmlSchemaNormLen(const xmlChar *value) {
3719 const xmlChar *utf;
3720 int ret = 0;
3721
3722 if (value == NULL)
3723 return(-1);
3724 utf = value;
William M. Brack76e95df2003-10-18 16:20:14 +00003725 while (IS_BLANK_CH(*utf)) utf++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003726 while (*utf != 0) {
3727 if (utf[0] & 0x80) {
3728 if ((utf[1] & 0xc0) != 0x80)
3729 return(-1);
3730 if ((utf[0] & 0xe0) == 0xe0) {
3731 if ((utf[2] & 0xc0) != 0x80)
3732 return(-1);
3733 if ((utf[0] & 0xf0) == 0xf0) {
3734 if ((utf[0] & 0xf8) != 0xf0 || (utf[3] & 0xc0) != 0x80)
3735 return(-1);
3736 utf += 4;
3737 } else {
3738 utf += 3;
3739 }
3740 } else {
3741 utf += 2;
3742 }
William M. Brack76e95df2003-10-18 16:20:14 +00003743 } else if (IS_BLANK_CH(*utf)) {
3744 while (IS_BLANK_CH(*utf)) utf++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003745 if (*utf == 0)
3746 break;
3747 } else {
3748 utf++;
3749 }
3750 ret++;
3751 }
3752 return(ret);
3753}
3754
Daniel Veillardc0826a72004-08-10 14:17:33 +00003755unsigned long
3756xmlSchemaGetFacetValueAsULong(xmlSchemaFacetPtr facet)
3757{
3758 /*
3759 * TODO: Check if this is a decimal.
3760 */
3761 return ((unsigned long) facet->val->value.decimal.lo);
3762}
3763
Daniel Veillardc4c21552003-03-29 10:53:38 +00003764/**
Daniel Veillard01fa6152004-06-29 17:04:39 +00003765 * xmlSchemaValidateListSimpleTypeFacet:
3766 * @facet: the facet to check
3767 * @value: the lexical repr of the value to validate
3768 * @actualLen: the number of list items
3769 * @expectedLen: the resulting expected number of list items
3770 *
3771 * Checks the value of a list simple type against a facet.
3772 *
3773 * Returns 0 if the value is valid, a positive error code
3774 * number otherwise and -1 in case of an internal error.
3775 */
3776int
3777xmlSchemaValidateListSimpleTypeFacet(xmlSchemaFacetPtr facet,
3778 const xmlChar *value,
3779 unsigned long actualLen,
3780 unsigned long *expectedLen)
3781{
3782 /*
3783 * TODO: Check if this will work with large numbers.
3784 * (compare value.decimal.mi and value.decimal.hi as well?).
3785 */
3786 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
3787 if (actualLen != facet->val->value.decimal.lo) {
Daniel Veillardc0826a72004-08-10 14:17:33 +00003788 if (expectedLen != 0)
3789 *expectedLen = facet->val->value.decimal.lo;
Daniel Veillard01fa6152004-06-29 17:04:39 +00003790 return (XML_SCHEMAV_CVC_LENGTH_VALID);
3791 }
3792 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
3793 if (actualLen < facet->val->value.decimal.lo) {
Daniel Veillardc0826a72004-08-10 14:17:33 +00003794 if (expectedLen != 0)
3795 *expectedLen = facet->val->value.decimal.lo;
Daniel Veillard01fa6152004-06-29 17:04:39 +00003796 return (XML_SCHEMAV_CVC_MINLENGTH_VALID);
3797 }
3798 } else if (facet->type == XML_SCHEMA_FACET_MAXLENGTH) {
3799 if (actualLen > facet->val->value.decimal.lo) {
Daniel Veillardc0826a72004-08-10 14:17:33 +00003800 if (expectedLen != 0)
3801 *expectedLen = facet->val->value.decimal.lo;
Daniel Veillard01fa6152004-06-29 17:04:39 +00003802 return (XML_SCHEMAV_CVC_MAXLENGTH_VALID);
3803 }
3804 } else
3805 /*
3806 * NOTE: That we can pass NULL as xmlSchemaValPtr to
3807 * xmlSchemaValidateFacet, since the remaining facet types
3808 * are: XML_SCHEMA_FACET_PATTERN, XML_SCHEMA_FACET_ENUMERATION.
3809 */
3810 return(xmlSchemaValidateFacet(NULL, facet, value, NULL));
3811 return (0);
3812}
3813
3814/**
Daniel Veillard4255d502002-04-16 15:50:10 +00003815 * xmlSchemaValidateFacet:
Daniel Veillardc0826a72004-08-10 14:17:33 +00003816 * @type: the built-in type
3817 * @facet: the facet to check
3818 * @value: the lexical repr. of the value to be validated
3819 * @val: the precomputed value
3820 * @length: the actual length of the value
3821 *
3822 * Checka a value against a "length", "minLength" and "maxLength"
3823 * facet; sets @length to the computed length of @value.
3824 *
3825 * Returns 0 if the value is valid, a positive error code
3826 * otherwise and -1 in case of an internal or API error.
3827 */
3828int
3829xmlSchemaValidateLengthFacet(xmlSchemaTypePtr type,
3830 xmlSchemaFacetPtr facet,
3831 const xmlChar *value,
3832 xmlSchemaValPtr val,
3833 unsigned long *length)
3834{
3835 unsigned int len = 0;
3836
3837 *length = 0;
3838 if ((facet->type != XML_SCHEMA_FACET_LENGTH) &&
3839 (facet->type != XML_SCHEMA_FACET_MAXLENGTH) &&
3840 (facet->type != XML_SCHEMA_FACET_MINLENGTH))
3841 return (-1);
3842
3843 if ((facet->val == NULL) ||
3844 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
3845 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
3846 (facet->val->value.decimal.frac != 0)) {
3847 return(-1);
3848 }
3849 if ((val != NULL) && (val->type == XML_SCHEMAS_HEXBINARY))
3850 len = val->value.hex.total;
3851 else if ((val != NULL) && (val->type == XML_SCHEMAS_BASE64BINARY))
3852 len = val->value.base64.total;
3853 else {
3854 switch (type->builtInType) {
3855 case XML_SCHEMAS_IDREF:
3856 case XML_SCHEMAS_NORMSTRING:
3857 case XML_SCHEMAS_TOKEN:
3858 case XML_SCHEMAS_LANGUAGE:
3859 case XML_SCHEMAS_NMTOKEN:
3860 case XML_SCHEMAS_NAME:
3861 case XML_SCHEMAS_NCNAME:
3862 case XML_SCHEMAS_ID:
3863 len = xmlSchemaNormLen(value);
3864 break;
3865 case XML_SCHEMAS_STRING:
3866 /*
3867 * FIXME: What exactly to do with anyURI?
3868 */
3869 case XML_SCHEMAS_ANYURI:
3870 if (value != NULL)
3871 len = xmlUTF8Strlen(value);
3872 break;
3873 default:
3874 TODO
3875 }
3876 }
3877 *length = (unsigned long) len;
3878 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
3879 if (len != facet->val->value.decimal.lo)
3880 return(XML_SCHEMAV_CVC_LENGTH_VALID);
3881 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
3882 if (len < facet->val->value.decimal.lo)
3883 return(XML_SCHEMAV_CVC_MINLENGTH_VALID);
3884 } else {
3885 if (len > facet->val->value.decimal.lo)
3886 return(XML_SCHEMAV_CVC_MAXLENGTH_VALID);
3887 }
3888
3889 return (0);
3890}
3891
3892/**
3893 * xmlSchemaValidateFacet:
Daniel Veillard01c13b52002-12-10 15:19:08 +00003894 * @base: the base type
Daniel Veillard4255d502002-04-16 15:50:10 +00003895 * @facet: the facet to check
3896 * @value: the lexical repr of the value to validate
3897 * @val: the precomputed value
3898 *
3899 * Check a value against a facet condition
3900 *
3901 * Returns 0 if the element is schemas valid, a positive error code
3902 * number otherwise and -1 in case of internal or API error.
3903 */
3904int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00003905xmlSchemaValidateFacet(xmlSchemaTypePtr base ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +00003906 xmlSchemaFacetPtr facet,
Daniel Veillard4255d502002-04-16 15:50:10 +00003907 const xmlChar *value, xmlSchemaValPtr val)
3908{
3909 int ret;
3910
3911 switch (facet->type) {
3912 case XML_SCHEMA_FACET_PATTERN:
3913 ret = xmlRegexpExec(facet->regexp, value);
3914 if (ret == 1)
3915 return(0);
3916 if (ret == 0) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00003917 return(XML_SCHEMAV_CVC_PATTERN_VALID);
Daniel Veillard4255d502002-04-16 15:50:10 +00003918 }
3919 return(ret);
3920 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
3921 ret = xmlSchemaCompareValues(val, facet->val);
3922 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003923 /* TODO error code */
Daniel Veillard4255d502002-04-16 15:50:10 +00003924 return(-1);
3925 }
3926 if (ret == -1)
3927 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00003928 /* error code */
Daniel Veillard01fa6152004-06-29 17:04:39 +00003929 return(XML_SCHEMAV_CVC_MAXEXCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00003930 case XML_SCHEMA_FACET_MAXINCLUSIVE:
3931 ret = xmlSchemaCompareValues(val, facet->val);
3932 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003933 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00003934 return(-1);
3935 }
3936 if ((ret == -1) || (ret == 0))
3937 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00003938 /* error code */
Daniel Veillard01fa6152004-06-29 17:04:39 +00003939 return(XML_SCHEMAV_CVC_MAXINCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00003940 case XML_SCHEMA_FACET_MINEXCLUSIVE:
3941 ret = xmlSchemaCompareValues(val, facet->val);
3942 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003943 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00003944 return(-1);
3945 }
3946 if (ret == 1)
3947 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00003948 /* error code */
Daniel Veillard01fa6152004-06-29 17:04:39 +00003949 return(XML_SCHEMAV_CVC_MINEXCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00003950 case XML_SCHEMA_FACET_MININCLUSIVE:
3951 ret = xmlSchemaCompareValues(val, facet->val);
3952 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003953 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00003954 return(-1);
3955 }
3956 if ((ret == 1) || (ret == 0))
3957 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00003958 /* error code */
Daniel Veillard01fa6152004-06-29 17:04:39 +00003959 return(XML_SCHEMAV_CVC_MININCLUSIVE_VALID);
Daniel Veillard8651f532002-04-17 09:06:27 +00003960 case XML_SCHEMA_FACET_WHITESPACE:
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003961 /* TODO whitespaces */
Daniel Veillard01fa6152004-06-29 17:04:39 +00003962 /*
3963 * NOTE: Whitespace should be handled to normalize
3964 * the value to be validated against a the facets;
3965 * not to normalize the value in-between.
3966 */
Daniel Veillard8651f532002-04-17 09:06:27 +00003967 return(0);
Daniel Veillard88c58912002-04-23 07:12:20 +00003968 case XML_SCHEMA_FACET_ENUMERATION:
3969 if ((facet->value != NULL) &&
3970 (xmlStrEqual(facet->value, value)))
3971 return(0);
Daniel Veillard01fa6152004-06-29 17:04:39 +00003972 return(XML_SCHEMAV_CVC_ENUMERATION_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003973 case XML_SCHEMA_FACET_LENGTH:
3974 case XML_SCHEMA_FACET_MAXLENGTH:
3975 case XML_SCHEMA_FACET_MINLENGTH: {
3976 unsigned int len = 0;
3977
3978 if ((facet->val == NULL) ||
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003979 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
3980 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003981 (facet->val->value.decimal.frac != 0)) {
3982 return(-1);
3983 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00003984 if ((val != NULL) && (val->type == XML_SCHEMAS_HEXBINARY))
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00003985 len = val->value.hex.total;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003986 else if ((val != NULL) && (val->type == XML_SCHEMAS_BASE64BINARY))
3987 len = val->value.base64.total;
3988 else {
Daniel Veillard01fa6152004-06-29 17:04:39 +00003989 switch (base->builtInType) {
Daniel Veillard560c2a42003-07-06 21:13:49 +00003990 case XML_SCHEMAS_IDREF:
3991 case XML_SCHEMAS_NORMSTRING:
3992 case XML_SCHEMAS_TOKEN:
3993 case XML_SCHEMAS_LANGUAGE:
3994 case XML_SCHEMAS_NMTOKEN:
3995 case XML_SCHEMAS_NAME:
3996 case XML_SCHEMAS_NCNAME:
3997 case XML_SCHEMAS_ID:
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00003998 len = xmlSchemaNormLen(value);
3999 break;
Daniel Veillard560c2a42003-07-06 21:13:49 +00004000 case XML_SCHEMAS_STRING:
Daniel Veillard01fa6152004-06-29 17:04:39 +00004001 /*
4002 * FIXME: What exactly to do with anyURI?
4003 */
4004 case XML_SCHEMAS_ANYURI:
William M. Brackfbf2c5e2004-02-03 17:55:56 +00004005 if (value != NULL)
4006 len = xmlUTF8Strlen(value);
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004007 break;
Daniel Veillard560c2a42003-07-06 21:13:49 +00004008 default:
4009 TODO
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00004010 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004011 }
4012 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004013 if (len != facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004014 return(XML_SCHEMAV_CVC_LENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004015 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004016 if (len < facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004017 return(XML_SCHEMAV_CVC_MINLENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004018 } else {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00004019 if (len > facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004020 return(XML_SCHEMAV_CVC_MAXLENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004021 }
4022 break;
4023 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00004024 case XML_SCHEMA_FACET_TOTALDIGITS:
4025 case XML_SCHEMA_FACET_FRACTIONDIGITS:
4026
4027 if ((facet->val == NULL) ||
4028 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
4029 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
4030 (facet->val->value.decimal.frac != 0)) {
4031 return(-1);
4032 }
4033 if ((val == NULL) ||
4034 ((val->type != XML_SCHEMAS_DECIMAL) &&
4035 (val->type != XML_SCHEMAS_INTEGER) &&
4036 (val->type != XML_SCHEMAS_NPINTEGER) &&
4037 (val->type != XML_SCHEMAS_NINTEGER) &&
4038 (val->type != XML_SCHEMAS_NNINTEGER) &&
4039 (val->type != XML_SCHEMAS_PINTEGER) &&
4040 (val->type != XML_SCHEMAS_INT) &&
4041 (val->type != XML_SCHEMAS_UINT) &&
4042 (val->type != XML_SCHEMAS_LONG) &&
4043 (val->type != XML_SCHEMAS_ULONG) &&
4044 (val->type != XML_SCHEMAS_SHORT) &&
4045 (val->type != XML_SCHEMAS_USHORT) &&
4046 (val->type != XML_SCHEMAS_BYTE) &&
4047 (val->type != XML_SCHEMAS_UBYTE))) {
4048 return(-1);
4049 }
4050 if (facet->type == XML_SCHEMA_FACET_TOTALDIGITS) {
4051 if (val->value.decimal.total > facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004052 return(XML_SCHEMAV_CVC_TOTALDIGITS_VALID);
Daniel Veillard560c2a42003-07-06 21:13:49 +00004053
4054 } else if (facet->type == XML_SCHEMA_FACET_FRACTIONDIGITS) {
4055 if (val->value.decimal.frac > facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00004056 return(XML_SCHEMAV_CVC_FRACTIONDIGITS_VALID);
Daniel Veillard560c2a42003-07-06 21:13:49 +00004057 }
4058 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00004059 default:
4060 TODO
4061 }
4062 return(0);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00004063
Daniel Veillard4255d502002-04-16 15:50:10 +00004064}
4065
4066#endif /* LIBXML_SCHEMAS_ENABLED */