blob: d503c9a5a7f7a0cf4511d3fc7cf45b35dfc93c38 [file] [log] [blame]
Daniel Veillard4255d502002-04-16 15:50:10 +00001/*
2 * schemastypes.c : implementation of the XML Schema Datatypes
3 * definition and validity checking
4 *
5 * See Copyright for the status of this software.
6 *
7 * Daniel Veillard <veillard@redhat.com>
8 */
9
10#define IN_LIBXML
11#include "libxml.h"
12
13#ifdef LIBXML_SCHEMAS_ENABLED
14
15#include <string.h>
16#include <libxml/xmlmemory.h>
17#include <libxml/parser.h>
18#include <libxml/parserInternals.h>
19#include <libxml/hash.h>
20#include <libxml/valid.h>
Daniel Veillard96a4b252003-02-06 08:22:32 +000021#include <libxml/xpath.h>
22#include <libxml/uri.h>
Daniel Veillard4255d502002-04-16 15:50:10 +000023
24#include <libxml/xmlschemas.h>
25#include <libxml/schemasInternals.h>
26#include <libxml/xmlschemastypes.h>
27
Daniel Veillard070803b2002-05-03 07:29:38 +000028#ifdef HAVE_MATH_H
29#include <math.h>
30#endif
31
Daniel Veillard4255d502002-04-16 15:50:10 +000032#define DEBUG
33
34#define TODO \
35 xmlGenericError(xmlGenericErrorContext, \
36 "Unimplemented block at %s:%d\n", \
37 __FILE__, __LINE__);
38
39#define XML_SCHEMAS_NAMESPACE_NAME \
40 (const xmlChar *)"http://www.w3.org/2001/XMLSchema"
41
Daniel Veillard4255d502002-04-16 15:50:10 +000042
Daniel Veillard5f704af2003-03-05 10:01:43 +000043static unsigned long powten[10] = {
Daniel Veillard4255d502002-04-16 15:50:10 +000044 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000L,
45 100000000L, 1000000000L
46};
47
Daniel Veillard01fa6152004-06-29 17:04:39 +000048
Daniel Veillard070803b2002-05-03 07:29:38 +000049/* Date value */
50typedef struct _xmlSchemaValDate xmlSchemaValDate;
51typedef xmlSchemaValDate *xmlSchemaValDatePtr;
52struct _xmlSchemaValDate {
53 long year;
54 unsigned int mon :4; /* 1 <= mon <= 12 */
55 unsigned int day :5; /* 1 <= day <= 31 */
56 unsigned int hour :5; /* 0 <= hour <= 23 */
57 unsigned int min :6; /* 0 <= min <= 59 */
58 double sec;
Daniel Veillarda77cf712003-05-09 23:09:55 +000059 unsigned int tz_flag :1; /* is tzo explicitely set? */
Daniel Veillard070803b2002-05-03 07:29:38 +000060 int tzo :11; /* -1440 <= tzo <= 1440 */
61};
62
63/* Duration value */
64typedef struct _xmlSchemaValDuration xmlSchemaValDuration;
65typedef xmlSchemaValDuration *xmlSchemaValDurationPtr;
66struct _xmlSchemaValDuration {
67 long mon; /* mon stores years also */
68 long day;
69 double sec; /* sec stores min and hour also */
70};
71
Daniel Veillard4255d502002-04-16 15:50:10 +000072typedef struct _xmlSchemaValDecimal xmlSchemaValDecimal;
73typedef xmlSchemaValDecimal *xmlSchemaValDecimalPtr;
74struct _xmlSchemaValDecimal {
75 /* would use long long but not portable */
Daniel Veillarde637c4a2003-03-30 21:10:09 +000076 unsigned long lo;
77 unsigned long mi;
78 unsigned long hi;
Daniel Veillard4255d502002-04-16 15:50:10 +000079 unsigned int extra;
Daniel Veillard5a872412002-05-22 06:40:27 +000080 unsigned int sign:1;
William M. Brackc1939562003-08-05 15:52:22 +000081 unsigned int frac:7;
82 unsigned int total:8;
Daniel Veillard4255d502002-04-16 15:50:10 +000083};
84
Daniel Veillarde637c4a2003-03-30 21:10:09 +000085typedef struct _xmlSchemaValQName xmlSchemaValQName;
86typedef xmlSchemaValQName *xmlSchemaValQNamePtr;
87struct _xmlSchemaValQName {
88 xmlChar *name;
89 xmlChar *uri;
90};
91
Daniel Veillard70bcb0e2003-08-08 14:00:28 +000092typedef struct _xmlSchemaValHex xmlSchemaValHex;
93typedef xmlSchemaValHex *xmlSchemaValHexPtr;
94struct _xmlSchemaValHex {
95 xmlChar *str;
96 unsigned int total;
97};
98
Daniel Veillard1ac24d32003-08-27 14:15:15 +000099typedef struct _xmlSchemaValBase64 xmlSchemaValBase64;
100typedef xmlSchemaValBase64 *xmlSchemaValBase64Ptr;
101struct _xmlSchemaValBase64 {
102 xmlChar *str;
103 unsigned int total;
104};
105
Daniel Veillard4255d502002-04-16 15:50:10 +0000106struct _xmlSchemaVal {
107 xmlSchemaValType type;
108 union {
Daniel Veillard5a872412002-05-22 06:40:27 +0000109 xmlSchemaValDecimal decimal;
Daniel Veillard070803b2002-05-03 07:29:38 +0000110 xmlSchemaValDate date;
111 xmlSchemaValDuration dur;
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000112 xmlSchemaValQName qname;
Daniel Veillard70bcb0e2003-08-08 14:00:28 +0000113 xmlSchemaValHex hex;
Daniel Veillard1ac24d32003-08-27 14:15:15 +0000114 xmlSchemaValBase64 base64;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000115 float f;
116 double d;
Daniel Veillardc5a70f22003-02-06 23:41:59 +0000117 int b;
Daniel Veillardc4c21552003-03-29 10:53:38 +0000118 xmlChar *str;
Daniel Veillard4255d502002-04-16 15:50:10 +0000119 } value;
120};
121
122static int xmlSchemaTypesInitialized = 0;
123static xmlHashTablePtr xmlSchemaTypesBank = NULL;
124
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000125/*
126 * Basic types
127 */
Daniel Veillard4255d502002-04-16 15:50:10 +0000128static xmlSchemaTypePtr xmlSchemaTypeStringDef = NULL;
129static xmlSchemaTypePtr xmlSchemaTypeAnyTypeDef = NULL;
130static xmlSchemaTypePtr xmlSchemaTypeAnySimpleTypeDef = NULL;
131static xmlSchemaTypePtr xmlSchemaTypeDecimalDef = NULL;
Daniel Veillard070803b2002-05-03 07:29:38 +0000132static xmlSchemaTypePtr xmlSchemaTypeDatetimeDef = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +0000133static xmlSchemaTypePtr xmlSchemaTypeDateDef = NULL;
Daniel Veillard070803b2002-05-03 07:29:38 +0000134static xmlSchemaTypePtr xmlSchemaTypeTimeDef = NULL;
135static xmlSchemaTypePtr xmlSchemaTypeGYearDef = NULL;
136static xmlSchemaTypePtr xmlSchemaTypeGYearMonthDef = NULL;
137static xmlSchemaTypePtr xmlSchemaTypeGDayDef = NULL;
138static xmlSchemaTypePtr xmlSchemaTypeGMonthDayDef = NULL;
139static xmlSchemaTypePtr xmlSchemaTypeGMonthDef = NULL;
140static xmlSchemaTypePtr xmlSchemaTypeDurationDef = NULL;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000141static xmlSchemaTypePtr xmlSchemaTypeFloatDef = NULL;
Daniel Veillardc5a70f22003-02-06 23:41:59 +0000142static xmlSchemaTypePtr xmlSchemaTypeBooleanDef = NULL;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000143static xmlSchemaTypePtr xmlSchemaTypeDoubleDef = NULL;
Daniel Veillard560c2a42003-07-06 21:13:49 +0000144static xmlSchemaTypePtr xmlSchemaTypeHexBinaryDef = NULL;
Daniel Veillard1ac24d32003-08-27 14:15:15 +0000145static xmlSchemaTypePtr xmlSchemaTypeBase64BinaryDef = NULL;
Daniel Veillarde5b110b2003-02-04 14:43:39 +0000146static xmlSchemaTypePtr xmlSchemaTypeAnyURIDef = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +0000147
148/*
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000149 * Derived types
150 */
151static xmlSchemaTypePtr xmlSchemaTypePositiveIntegerDef = NULL;
152static xmlSchemaTypePtr xmlSchemaTypeNonPositiveIntegerDef = NULL;
153static xmlSchemaTypePtr xmlSchemaTypeNegativeIntegerDef = NULL;
154static xmlSchemaTypePtr xmlSchemaTypeNonNegativeIntegerDef = NULL;
155static xmlSchemaTypePtr xmlSchemaTypeIntegerDef = NULL;
156static xmlSchemaTypePtr xmlSchemaTypeLongDef = NULL;
157static xmlSchemaTypePtr xmlSchemaTypeIntDef = NULL;
158static xmlSchemaTypePtr xmlSchemaTypeShortDef = NULL;
159static xmlSchemaTypePtr xmlSchemaTypeByteDef = NULL;
160static xmlSchemaTypePtr xmlSchemaTypeUnsignedLongDef = NULL;
161static xmlSchemaTypePtr xmlSchemaTypeUnsignedIntDef = NULL;
162static xmlSchemaTypePtr xmlSchemaTypeUnsignedShortDef = NULL;
163static xmlSchemaTypePtr xmlSchemaTypeUnsignedByteDef = NULL;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000164static xmlSchemaTypePtr xmlSchemaTypeNormStringDef = NULL;
165static xmlSchemaTypePtr xmlSchemaTypeTokenDef = NULL;
166static xmlSchemaTypePtr xmlSchemaTypeLanguageDef = NULL;
167static xmlSchemaTypePtr xmlSchemaTypeNameDef = NULL;
168static xmlSchemaTypePtr xmlSchemaTypeQNameDef = NULL;
Daniel Veillarde5b110b2003-02-04 14:43:39 +0000169static xmlSchemaTypePtr xmlSchemaTypeNCNameDef = NULL;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000170static xmlSchemaTypePtr xmlSchemaTypeIdDef = NULL;
171static xmlSchemaTypePtr xmlSchemaTypeIdrefDef = NULL;
172static xmlSchemaTypePtr xmlSchemaTypeIdrefsDef = NULL;
Daniel Veillarda1a9d042003-03-18 16:53:17 +0000173static xmlSchemaTypePtr xmlSchemaTypeEntityDef = NULL;
174static xmlSchemaTypePtr xmlSchemaTypeEntitiesDef = NULL;
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000175static xmlSchemaTypePtr xmlSchemaTypeNotationDef = NULL;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000176static xmlSchemaTypePtr xmlSchemaTypeNmtokenDef = NULL;
177static xmlSchemaTypePtr xmlSchemaTypeNmtokensDef = NULL;
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000178
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000179/************************************************************************
180 * *
181 * Datatype error handlers *
182 * *
183 ************************************************************************/
184/**
185 * xmlSchemaTypeErrMemory:
186 * @extra: extra informations
187 *
188 * Handle an out of memory condition
189 */
190static void
191xmlSchemaTypeErrMemory(xmlNodePtr node, const char *extra)
192{
193 __xmlSimpleError(XML_FROM_DATATYPE, XML_ERR_NO_MEMORY, node, NULL, extra);
194}
195
196/************************************************************************
197 * *
198 * Base types support *
199 * *
200 ************************************************************************/
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000201/*
Daniel Veillard4255d502002-04-16 15:50:10 +0000202 * xmlSchemaInitBasicType:
203 * @name: the type name
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000204 * @type: the value type associated
Daniel Veillard4255d502002-04-16 15:50:10 +0000205 *
Daniel Veillard01fa6152004-06-29 17:04:39 +0000206 * Initialize one primitive built-in type
Daniel Veillard4255d502002-04-16 15:50:10 +0000207 */
208static xmlSchemaTypePtr
Daniel Veillard01fa6152004-06-29 17:04:39 +0000209xmlSchemaInitBasicType(const char *name, xmlSchemaValType type,
210 xmlSchemaTypePtr baseType) {
Daniel Veillard4255d502002-04-16 15:50:10 +0000211 xmlSchemaTypePtr ret;
212
213 ret = (xmlSchemaTypePtr) xmlMalloc(sizeof(xmlSchemaType));
214 if (ret == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000215 xmlSchemaTypeErrMemory(NULL, "could not initialize basic types");
Daniel Veillard4255d502002-04-16 15:50:10 +0000216 return(NULL);
217 }
218 memset(ret, 0, sizeof(xmlSchemaType));
Daniel Veillardbe9c6322003-11-22 20:37:51 +0000219 ret->name = (const xmlChar *)name;
Daniel Veillard4255d502002-04-16 15:50:10 +0000220 ret->type = XML_SCHEMA_TYPE_BASIC;
Daniel Veillard01fa6152004-06-29 17:04:39 +0000221 ret->baseType = baseType;
222 /*
223 * Hack to reflect the variety.
224 */
225 if ((type == XML_SCHEMAS_IDREFS) ||
226 (type == XML_SCHEMAS_NMTOKENS) ||
227 (type == XML_SCHEMAS_ENTITIES))
228 ret->flags |= XML_SCHEMAS_TYPE_VARIETY_LIST;
229 else if (type != XML_SCHEMAS_UNKNOWN)
230 ret->flags |= XML_SCHEMAS_TYPE_VARIETY_ATOMIC;
Daniel Veillard4255d502002-04-16 15:50:10 +0000231 ret->contentType = XML_SCHEMA_CONTENT_BASIC;
Daniel Veillard01fa6152004-06-29 17:04:39 +0000232 switch (type) {
233 case XML_SCHEMAS_STRING:
234 case XML_SCHEMAS_DECIMAL:
235 case XML_SCHEMAS_DATE:
236 case XML_SCHEMAS_DATETIME:
237 case XML_SCHEMAS_TIME:
238 case XML_SCHEMAS_GYEAR:
239 case XML_SCHEMAS_GYEARMONTH:
240 case XML_SCHEMAS_GMONTH:
241 case XML_SCHEMAS_GMONTHDAY:
242 case XML_SCHEMAS_GDAY:
243 case XML_SCHEMAS_DURATION:
244 case XML_SCHEMAS_FLOAT:
245 case XML_SCHEMAS_DOUBLE:
246 case XML_SCHEMAS_BOOLEAN:
247 case XML_SCHEMAS_ANYURI:
248 case XML_SCHEMAS_HEXBINARY:
249 case XML_SCHEMAS_BASE64BINARY:
250 case XML_SCHEMAS_QNAME:
251 case XML_SCHEMAS_NOTATION:
252 ret->flags |= XML_SCHEMAS_TYPE_BUILTIN_PRIMITIVE;
William M. Brack96d2eff2004-06-30 11:48:47 +0000253 default:
254 break;
Daniel Veillard01fa6152004-06-29 17:04:39 +0000255 }
256
Daniel Veillard4255d502002-04-16 15:50:10 +0000257 xmlHashAddEntry2(xmlSchemaTypesBank, ret->name,
258 XML_SCHEMAS_NAMESPACE_NAME, ret);
Daniel Veillard01fa6152004-06-29 17:04:39 +0000259 ret->builtInType = type;
Daniel Veillard4255d502002-04-16 15:50:10 +0000260 return(ret);
261}
262
263/*
264 * xmlSchemaInitTypes:
265 *
266 * Initialize the default XML Schemas type library
267 */
268void
Daniel Veillard6560a422003-03-27 21:25:38 +0000269xmlSchemaInitTypes(void)
270{
Daniel Veillard4255d502002-04-16 15:50:10 +0000271 if (xmlSchemaTypesInitialized != 0)
Daniel Veillard6560a422003-03-27 21:25:38 +0000272 return;
Daniel Veillard4255d502002-04-16 15:50:10 +0000273 xmlSchemaTypesBank = xmlHashCreate(40);
Daniel Veillard6560a422003-03-27 21:25:38 +0000274
Daniel Veillard01fa6152004-06-29 17:04:39 +0000275
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000276 /*
Daniel Veillard01fa6152004-06-29 17:04:39 +0000277 * 3.4.7 Built-in Complex Type Definition
278 */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000279 xmlSchemaTypeAnyTypeDef = xmlSchemaInitBasicType("anyType",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000280 XML_SCHEMAS_UNKNOWN,
281 NULL);
282 xmlSchemaTypeAnyTypeDef->baseType = xmlSchemaTypeAnyTypeDef;
283 xmlSchemaTypeAnyTypeDef->contentType = XML_SCHEMA_CONTENT_MIXED;
284 {
285 xmlSchemaWildcardPtr wild;
286
287 wild = (xmlSchemaWildcardPtr) xmlMalloc(sizeof(xmlSchemaWildcard));
288 if (wild == NULL) {
289 xmlSchemaTypeErrMemory(NULL, "could not create a wildcard on anyType");
290 return;
291 }
292 memset(wild, 0, sizeof(xmlSchemaWildcard));
293 wild->any = 1;
294 wild->processContents = XML_SCHEMAS_ANY_LAX;
295 wild->minOccurs = 1;
296 wild->maxOccurs = 1;
297 xmlSchemaTypeAnyTypeDef->attributeWildcard = wild;
298 }
299 xmlSchemaTypeAnySimpleTypeDef = xmlSchemaInitBasicType("anySimpleType",
300 XML_SCHEMAS_UNKNOWN,
301 xmlSchemaTypeAnyTypeDef);
302 /*
303 * primitive datatypes
304 */
305 xmlSchemaTypeStringDef = xmlSchemaInitBasicType("string",
306 XML_SCHEMAS_STRING,
307 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000308 xmlSchemaTypeDecimalDef = xmlSchemaInitBasicType("decimal",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000309 XML_SCHEMAS_DECIMAL,
310 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000311 xmlSchemaTypeDateDef = xmlSchemaInitBasicType("date",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000312 XML_SCHEMAS_DATE,
313 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000314 xmlSchemaTypeDatetimeDef = xmlSchemaInitBasicType("dateTime",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000315 XML_SCHEMAS_DATETIME,
316 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000317 xmlSchemaTypeTimeDef = xmlSchemaInitBasicType("time",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000318 XML_SCHEMAS_TIME,
319 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000320 xmlSchemaTypeGYearDef = xmlSchemaInitBasicType("gYear",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000321 XML_SCHEMAS_GYEAR,
322 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000323 xmlSchemaTypeGYearMonthDef = xmlSchemaInitBasicType("gYearMonth",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000324 XML_SCHEMAS_GYEARMONTH,
325 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000326 xmlSchemaTypeGMonthDef = xmlSchemaInitBasicType("gMonth",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000327 XML_SCHEMAS_GMONTH,
328 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000329 xmlSchemaTypeGMonthDayDef = xmlSchemaInitBasicType("gMonthDay",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000330 XML_SCHEMAS_GMONTHDAY,
331 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000332 xmlSchemaTypeGDayDef = xmlSchemaInitBasicType("gDay",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000333 XML_SCHEMAS_GDAY,
334 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000335 xmlSchemaTypeDurationDef = xmlSchemaInitBasicType("duration",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000336 XML_SCHEMAS_DURATION,
337 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000338 xmlSchemaTypeFloatDef = xmlSchemaInitBasicType("float",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000339 XML_SCHEMAS_FLOAT,
340 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000341 xmlSchemaTypeDoubleDef = xmlSchemaInitBasicType("double",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000342 XML_SCHEMAS_DOUBLE,
343 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000344 xmlSchemaTypeBooleanDef = xmlSchemaInitBasicType("boolean",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000345 XML_SCHEMAS_BOOLEAN,
346 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000347 xmlSchemaTypeAnyURIDef = xmlSchemaInitBasicType("anyURI",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000348 XML_SCHEMAS_ANYURI,
349 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard560c2a42003-07-06 21:13:49 +0000350 xmlSchemaTypeHexBinaryDef = xmlSchemaInitBasicType("hexBinary",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000351 XML_SCHEMAS_HEXBINARY,
352 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard1ac24d32003-08-27 14:15:15 +0000353 xmlSchemaTypeBase64BinaryDef
Daniel Veillard01fa6152004-06-29 17:04:39 +0000354 = xmlSchemaInitBasicType("base64Binary", XML_SCHEMAS_BASE64BINARY,
355 xmlSchemaTypeAnySimpleTypeDef);
356 xmlSchemaTypeNotationDef = xmlSchemaInitBasicType("NOTATION",
357 XML_SCHEMAS_NOTATION,
358 xmlSchemaTypeAnySimpleTypeDef);
359 xmlSchemaTypeQNameDef = xmlSchemaInitBasicType("QName",
360 XML_SCHEMAS_QNAME,
361 xmlSchemaTypeAnySimpleTypeDef);
Daniel Veillard4255d502002-04-16 15:50:10 +0000362
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000363 /*
364 * derived datatypes
365 */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000366 xmlSchemaTypeIntegerDef = xmlSchemaInitBasicType("integer",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000367 XML_SCHEMAS_INTEGER,
368 xmlSchemaTypeDecimalDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000369 xmlSchemaTypeNonPositiveIntegerDef =
370 xmlSchemaInitBasicType("nonPositiveInteger",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000371 XML_SCHEMAS_NPINTEGER,
372 xmlSchemaTypeIntegerDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000373 xmlSchemaTypeNegativeIntegerDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000374 xmlSchemaInitBasicType("negativeInteger", XML_SCHEMAS_NINTEGER,
375 xmlSchemaTypeNonPositiveIntegerDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000376 xmlSchemaTypeLongDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000377 xmlSchemaInitBasicType("long", XML_SCHEMAS_LONG,
378 xmlSchemaTypeIntegerDef);
379 xmlSchemaTypeIntDef = xmlSchemaInitBasicType("int", XML_SCHEMAS_INT,
380 xmlSchemaTypeLongDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000381 xmlSchemaTypeShortDef = xmlSchemaInitBasicType("short",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000382 XML_SCHEMAS_SHORT,
383 xmlSchemaTypeIntDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000384 xmlSchemaTypeByteDef = xmlSchemaInitBasicType("byte",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000385 XML_SCHEMAS_BYTE,
386 xmlSchemaTypeShortDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000387 xmlSchemaTypeNonNegativeIntegerDef =
388 xmlSchemaInitBasicType("nonNegativeInteger",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000389 XML_SCHEMAS_NNINTEGER,
390 xmlSchemaTypeIntegerDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000391 xmlSchemaTypeUnsignedLongDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000392 xmlSchemaInitBasicType("unsignedLong", XML_SCHEMAS_ULONG,
393 xmlSchemaTypeNonNegativeIntegerDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000394 xmlSchemaTypeUnsignedIntDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000395 xmlSchemaInitBasicType("unsignedInt", XML_SCHEMAS_UINT,
396 xmlSchemaTypeUnsignedLongDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000397 xmlSchemaTypeUnsignedShortDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000398 xmlSchemaInitBasicType("unsignedShort", XML_SCHEMAS_USHORT,
399 xmlSchemaTypeUnsignedIntDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000400 xmlSchemaTypeUnsignedByteDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000401 xmlSchemaInitBasicType("unsignedByte", XML_SCHEMAS_UBYTE,
402 xmlSchemaTypeUnsignedShortDef);
Daniel Veillard6560a422003-03-27 21:25:38 +0000403 xmlSchemaTypePositiveIntegerDef =
Daniel Veillard01fa6152004-06-29 17:04:39 +0000404 xmlSchemaInitBasicType("positiveInteger", XML_SCHEMAS_PINTEGER,
405 xmlSchemaTypeNonNegativeIntegerDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000406 xmlSchemaTypeNormStringDef = xmlSchemaInitBasicType("normalizedString",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000407 XML_SCHEMAS_NORMSTRING,
408 xmlSchemaTypeStringDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000409 xmlSchemaTypeTokenDef = xmlSchemaInitBasicType("token",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000410 XML_SCHEMAS_TOKEN,
411 xmlSchemaTypeNormStringDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000412 xmlSchemaTypeLanguageDef = xmlSchemaInitBasicType("language",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000413 XML_SCHEMAS_LANGUAGE,
414 xmlSchemaTypeTokenDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000415 xmlSchemaTypeNameDef = xmlSchemaInitBasicType("Name",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000416 XML_SCHEMAS_NAME,
417 xmlSchemaTypeTokenDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000418 xmlSchemaTypeNmtokenDef = xmlSchemaInitBasicType("NMTOKEN",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000419 XML_SCHEMAS_NMTOKEN,
420 xmlSchemaTypeTokenDef);
421 xmlSchemaTypeNCNameDef = xmlSchemaInitBasicType("NCName",
422 XML_SCHEMAS_NCNAME,
423 xmlSchemaTypeNameDef);
424 xmlSchemaTypeIdDef = xmlSchemaInitBasicType("ID", XML_SCHEMAS_ID,
425 xmlSchemaTypeNCNameDef);
426 xmlSchemaTypeIdrefDef = xmlSchemaInitBasicType("IDREF",
427 XML_SCHEMAS_IDREF,
428 xmlSchemaTypeNCNameDef);
429 xmlSchemaTypeIdrefsDef = xmlSchemaInitBasicType("IDREFS",
430 XML_SCHEMAS_IDREFS,
431 xmlSchemaTypeIdrefDef);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000432 xmlSchemaTypeNmtokensDef = xmlSchemaInitBasicType("NMTOKENS",
Daniel Veillard01fa6152004-06-29 17:04:39 +0000433 XML_SCHEMAS_NMTOKENS,
434 xmlSchemaTypeNmtokenDef);
435 xmlSchemaTypeEntityDef = xmlSchemaInitBasicType("ENTITY",
436 XML_SCHEMAS_ENTITY,
437 xmlSchemaTypeNCNameDef);
438 xmlSchemaTypeEntitiesDef = xmlSchemaInitBasicType("ENTITIES",
439 XML_SCHEMAS_ENTITIES,
440 xmlSchemaTypeNCNameDef);
Daniel Veillard4255d502002-04-16 15:50:10 +0000441 xmlSchemaTypesInitialized = 1;
442}
443
444/**
445 * xmlSchemaCleanupTypes:
446 *
447 * Cleanup the default XML Schemas type library
448 */
449void
450xmlSchemaCleanupTypes(void) {
451 if (xmlSchemaTypesInitialized == 0)
452 return;
Daniel Veillard01fa6152004-06-29 17:04:39 +0000453 xmlSchemaFreeWildcard(xmlSchemaTypeAnyTypeDef->attributeWildcard);
Daniel Veillard4255d502002-04-16 15:50:10 +0000454 xmlHashFree(xmlSchemaTypesBank, (xmlHashDeallocator) xmlSchemaFreeType);
455 xmlSchemaTypesInitialized = 0;
456}
457
458/**
William M. Brack4e3a9fa2004-08-03 22:41:11 +0000459 * xmlSchemaIsBuiltInTypeFacet:
Daniel Veillard01fa6152004-06-29 17:04:39 +0000460 * @type: the built-in type
461 * @facetType: the facet type
462 *
463 * Evaluates if a specific facet can be
464 * used in conjunction with a type.
465 *
466 * Returns 1 if the facet can be used with the given built-in type,
467 * 0 otherwise and -1 in case the type is not a built-in type.
468 */
469int
470xmlSchemaIsBuiltInTypeFacet(xmlSchemaTypePtr type, int facetType)
471{
472 if (type->type != XML_SCHEMA_TYPE_BASIC)
473 return (-1);
474 switch (type->builtInType) {
475 case XML_SCHEMAS_BOOLEAN:
476 if ((facetType == XML_SCHEMA_FACET_PATTERN) ||
477 (facetType == XML_SCHEMA_FACET_WHITESPACE))
478 return (1);
479 else
480 return (0);
481 case XML_SCHEMAS_STRING:
482 case XML_SCHEMAS_NOTATION:
483 case XML_SCHEMAS_QNAME:
484 case XML_SCHEMAS_ANYURI:
485 case XML_SCHEMAS_BASE64BINARY:
486 case XML_SCHEMAS_HEXBINARY:
487 if ((facetType == XML_SCHEMA_FACET_LENGTH) ||
488 (facetType == XML_SCHEMA_FACET_MINLENGTH) ||
489 (facetType == XML_SCHEMA_FACET_MAXLENGTH) ||
490 (facetType == XML_SCHEMA_FACET_PATTERN) ||
491 (facetType == XML_SCHEMA_FACET_ENUMERATION) ||
492 (facetType == XML_SCHEMA_FACET_WHITESPACE))
493 return (1);
494 else
495 return (0);
496 case XML_SCHEMAS_DECIMAL:
497 if ((facetType == XML_SCHEMA_FACET_TOTALDIGITS) ||
498 (facetType == XML_SCHEMA_FACET_FRACTIONDIGITS) ||
499 (facetType == XML_SCHEMA_FACET_PATTERN) ||
500 (facetType == XML_SCHEMA_FACET_WHITESPACE) ||
501 (facetType == XML_SCHEMA_FACET_ENUMERATION) ||
502 (facetType == XML_SCHEMA_FACET_MAXINCLUSIVE) ||
503 (facetType == XML_SCHEMA_FACET_MAXEXCLUSIVE) ||
504 (facetType == XML_SCHEMA_FACET_MININCLUSIVE) ||
505 (facetType == XML_SCHEMA_FACET_MINEXCLUSIVE))
506 return (1);
507 else
508 return (0);
509 case XML_SCHEMAS_TIME:
510 case XML_SCHEMAS_GDAY:
511 case XML_SCHEMAS_GMONTH:
512 case XML_SCHEMAS_GMONTHDAY:
513 case XML_SCHEMAS_GYEAR:
514 case XML_SCHEMAS_GYEARMONTH:
515 case XML_SCHEMAS_DATE:
516 case XML_SCHEMAS_DATETIME:
517 case XML_SCHEMAS_DURATION:
518 case XML_SCHEMAS_FLOAT:
519 case XML_SCHEMAS_DOUBLE:
520 if ((facetType == XML_SCHEMA_FACET_PATTERN) ||
521 (facetType == XML_SCHEMA_FACET_ENUMERATION) ||
522 (facetType == XML_SCHEMA_FACET_WHITESPACE) ||
523 (facetType == XML_SCHEMA_FACET_MAXINCLUSIVE) ||
524 (facetType == XML_SCHEMA_FACET_MAXEXCLUSIVE) ||
525 (facetType == XML_SCHEMA_FACET_MININCLUSIVE) ||
526 (facetType == XML_SCHEMA_FACET_MINEXCLUSIVE))
527 return (1);
528 else
529 return (0);
530 default:
531 return (0);
532 }
533 return (0);
534}
535
536/**
537 * xmlSchemaGetBuiltInType:
538 * @type: the type of the built in type
539 *
540 * Gives you the type struct for a built-in
541 * type by its type id.
542 *
543 * Returns the type if found, NULL otherwise.
544 */
545xmlSchemaTypePtr
546xmlSchemaGetBuiltInType(xmlSchemaValType type)
547{
548 if (xmlSchemaTypesInitialized == 0)
549 xmlSchemaInitTypes();
550 switch (type) {
551
552 case XML_SCHEMAS_ANYSIMPLETYPE:
553 return (xmlSchemaTypeAnySimpleTypeDef);
554 case XML_SCHEMAS_STRING:
555 return (xmlSchemaTypeStringDef);
556 case XML_SCHEMAS_NORMSTRING:
557 return (xmlSchemaTypeNormStringDef);
558 case XML_SCHEMAS_DECIMAL:
559 return (xmlSchemaTypeDecimalDef);
560 case XML_SCHEMAS_TIME:
561 return (xmlSchemaTypeTimeDef);
562 case XML_SCHEMAS_GDAY:
563 return (xmlSchemaTypeGDayDef);
564 case XML_SCHEMAS_GMONTH:
565 return (xmlSchemaTypeGMonthDef);
566 case XML_SCHEMAS_GMONTHDAY:
567 return (xmlSchemaTypeGMonthDayDef);
568 case XML_SCHEMAS_GYEAR:
569 return (xmlSchemaTypeGYearDef);
570 case XML_SCHEMAS_GYEARMONTH:
571 return (xmlSchemaTypeGYearMonthDef);
572 case XML_SCHEMAS_DATE:
573 return (xmlSchemaTypeDateDef);
574 case XML_SCHEMAS_DATETIME:
575 return (xmlSchemaTypeDatetimeDef);
576 case XML_SCHEMAS_DURATION:
577 return (xmlSchemaTypeDurationDef);
578 case XML_SCHEMAS_FLOAT:
579 return (xmlSchemaTypeFloatDef);
580 case XML_SCHEMAS_DOUBLE:
581 return (xmlSchemaTypeDoubleDef);
582 case XML_SCHEMAS_BOOLEAN:
583 return (xmlSchemaTypeBooleanDef);
584 case XML_SCHEMAS_TOKEN:
585 return (xmlSchemaTypeTokenDef);
586 case XML_SCHEMAS_LANGUAGE:
587 return (xmlSchemaTypeLanguageDef);
588 case XML_SCHEMAS_NMTOKEN:
589 return (xmlSchemaTypeNmtokenDef);
590 case XML_SCHEMAS_NMTOKENS:
591 return (xmlSchemaTypeNmtokensDef);
592 case XML_SCHEMAS_NAME:
593 return (xmlSchemaTypeNameDef);
594 case XML_SCHEMAS_QNAME:
595 return (xmlSchemaTypeQNameDef);
596 case XML_SCHEMAS_NCNAME:
597 return (xmlSchemaTypeNCNameDef);
598 case XML_SCHEMAS_ID:
599 return (xmlSchemaTypeIdDef);
600 case XML_SCHEMAS_IDREF:
601 return (xmlSchemaTypeIdrefDef);
602 case XML_SCHEMAS_IDREFS:
603 return (xmlSchemaTypeIdrefsDef);
604 case XML_SCHEMAS_ENTITY:
605 return (xmlSchemaTypeEntityDef);
606 case XML_SCHEMAS_ENTITIES:
607 return (xmlSchemaTypeEntitiesDef);
608 case XML_SCHEMAS_NOTATION:
609 return (xmlSchemaTypeNotationDef);
610 case XML_SCHEMAS_ANYURI:
611 return (xmlSchemaTypeAnyURIDef);
612 case XML_SCHEMAS_INTEGER:
613 return (xmlSchemaTypeIntegerDef);
614 case XML_SCHEMAS_NPINTEGER:
615 return (xmlSchemaTypeNonPositiveIntegerDef);
616 case XML_SCHEMAS_NINTEGER:
617 return (xmlSchemaTypeNegativeIntegerDef);
618 case XML_SCHEMAS_NNINTEGER:
619 return (xmlSchemaTypeNonNegativeIntegerDef);
620 case XML_SCHEMAS_PINTEGER:
621 return (xmlSchemaTypePositiveIntegerDef);
622 case XML_SCHEMAS_INT:
623 return (xmlSchemaTypeIntDef);
624 case XML_SCHEMAS_UINT:
625 return (xmlSchemaTypeUnsignedIntDef);
626 case XML_SCHEMAS_LONG:
627 return (xmlSchemaTypeLongDef);
628 case XML_SCHEMAS_ULONG:
629 return (xmlSchemaTypeUnsignedLongDef);
630 case XML_SCHEMAS_SHORT:
631 return (xmlSchemaTypeShortDef);
632 case XML_SCHEMAS_USHORT:
633 return (xmlSchemaTypeUnsignedShortDef);
634 case XML_SCHEMAS_BYTE:
635 return (xmlSchemaTypeByteDef);
636 case XML_SCHEMAS_UBYTE:
637 return (xmlSchemaTypeUnsignedByteDef);
638 case XML_SCHEMAS_HEXBINARY:
639 return (xmlSchemaTypeHexBinaryDef);
640 case XML_SCHEMAS_BASE64BINARY:
641 return (xmlSchemaTypeBase64BinaryDef);
642 case XML_SCHEMAS_ANYTYPE:
643 return (xmlSchemaTypeAnyTypeDef);
644 default:
645 return (NULL);
646 }
647}
648
649/**
Daniel Veillard4255d502002-04-16 15:50:10 +0000650 * xmlSchemaNewValue:
651 * @type: the value type
652 *
653 * Allocate a new simple type value
654 *
655 * Returns a pointer to the new value or NULL in case of error
656 */
657static xmlSchemaValPtr
658xmlSchemaNewValue(xmlSchemaValType type) {
659 xmlSchemaValPtr value;
660
661 value = (xmlSchemaValPtr) xmlMalloc(sizeof(xmlSchemaVal));
662 if (value == NULL) {
663 return(NULL);
664 }
665 memset(value, 0, sizeof(xmlSchemaVal));
666 value->type = type;
667 return(value);
668}
669
670/**
671 * xmlSchemaFreeValue:
672 * @value: the value to free
673 *
674 * Cleanup the default XML Schemas type library
675 */
676void
677xmlSchemaFreeValue(xmlSchemaValPtr value) {
678 if (value == NULL)
679 return;
Daniel Veillardc4c21552003-03-29 10:53:38 +0000680 switch (value->type) {
681 case XML_SCHEMAS_STRING:
682 case XML_SCHEMAS_NORMSTRING:
683 case XML_SCHEMAS_TOKEN:
684 case XML_SCHEMAS_LANGUAGE:
685 case XML_SCHEMAS_NMTOKEN:
686 case XML_SCHEMAS_NMTOKENS:
687 case XML_SCHEMAS_NAME:
Daniel Veillardc4c21552003-03-29 10:53:38 +0000688 case XML_SCHEMAS_NCNAME:
689 case XML_SCHEMAS_ID:
690 case XML_SCHEMAS_IDREF:
691 case XML_SCHEMAS_IDREFS:
692 case XML_SCHEMAS_ENTITY:
693 case XML_SCHEMAS_ENTITIES:
694 case XML_SCHEMAS_NOTATION:
695 case XML_SCHEMAS_ANYURI:
696 if (value->value.str != NULL)
697 xmlFree(value->value.str);
698 break;
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000699 case XML_SCHEMAS_QNAME:
700 if (value->value.qname.uri != NULL)
701 xmlFree(value->value.qname.uri);
702 if (value->value.qname.name != NULL)
703 xmlFree(value->value.qname.name);
704 break;
Daniel Veillard70bcb0e2003-08-08 14:00:28 +0000705 case XML_SCHEMAS_HEXBINARY:
706 if (value->value.hex.str != NULL)
707 xmlFree(value->value.hex.str);
708 break;
Daniel Veillard1ac24d32003-08-27 14:15:15 +0000709 case XML_SCHEMAS_BASE64BINARY:
710 if (value->value.base64.str != NULL)
711 xmlFree(value->value.base64.str);
712 break;
Daniel Veillardc4c21552003-03-29 10:53:38 +0000713 default:
714 break;
715 }
Daniel Veillard4255d502002-04-16 15:50:10 +0000716 xmlFree(value);
717}
718
719/**
720 * xmlSchemaGetPredefinedType:
721 * @name: the type name
722 * @ns: the URI of the namespace usually "http://www.w3.org/2001/XMLSchema"
723 *
724 * Lookup a type in the default XML Schemas type library
725 *
726 * Returns the type if found, NULL otherwise
727 */
728xmlSchemaTypePtr
729xmlSchemaGetPredefinedType(const xmlChar *name, const xmlChar *ns) {
730 if (xmlSchemaTypesInitialized == 0)
731 xmlSchemaInitTypes();
732 if (name == NULL)
733 return(NULL);
734 return((xmlSchemaTypePtr) xmlHashLookup2(xmlSchemaTypesBank, name, ns));
735}
Daniel Veillard070803b2002-05-03 07:29:38 +0000736
Daniel Veillard01fa6152004-06-29 17:04:39 +0000737/**
738 * xmlSchemaGetBuiltInListSimpleTypeItemType:
739 * @type: the built-in simple type.
740 *
William M. Brack4e3a9fa2004-08-03 22:41:11 +0000741 * Lookup a type in the built-in type database hierarchy of XML Schema
742 * Part 2:Datatypes.
743 *
744 * Returns the type if found, NULL otherwise.
Daniel Veillard01fa6152004-06-29 17:04:39 +0000745 */
746xmlSchemaTypePtr
747xmlSchemaGetBuiltInListSimpleTypeItemType(xmlSchemaTypePtr type)
748{
749 if (type->type != XML_SCHEMA_TYPE_BASIC)
750 return (NULL);
751 switch (type->builtInType) {
752 case XML_SCHEMAS_NMTOKENS:
753 return (xmlSchemaTypeNmtokenDef );
754 case XML_SCHEMAS_IDREFS:
755 return (xmlSchemaTypeIdrefDef);
756 case XML_SCHEMAS_ENTITIES:
757 return (xmlSchemaTypeEntityDef);
758 default:
759 return (NULL);
760 }
761}
762
Daniel Veillard070803b2002-05-03 07:29:38 +0000763/****************************************************************
764 * *
765 * Convenience macros and functions *
766 * *
767 ****************************************************************/
768
769#define IS_TZO_CHAR(c) \
770 ((c == 0) || (c == 'Z') || (c == '+') || (c == '-'))
771
772#define VALID_YEAR(yr) (yr != 0)
773#define VALID_MONTH(mon) ((mon >= 1) && (mon <= 12))
774/* VALID_DAY should only be used when month is unknown */
775#define VALID_DAY(day) ((day >= 1) && (day <= 31))
776#define VALID_HOUR(hr) ((hr >= 0) && (hr <= 23))
777#define VALID_MIN(min) ((min >= 0) && (min <= 59))
778#define VALID_SEC(sec) ((sec >= 0) && (sec < 60))
779#define VALID_TZO(tzo) ((tzo > -1440) && (tzo < 1440))
780#define IS_LEAP(y) \
781 (((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0))
782
Daniel Veillardebe25d42004-03-25 09:35:49 +0000783static const unsigned int daysInMonth[12] =
Daniel Veillard070803b2002-05-03 07:29:38 +0000784 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
Daniel Veillardebe25d42004-03-25 09:35:49 +0000785static const unsigned int daysInMonthLeap[12] =
Daniel Veillard070803b2002-05-03 07:29:38 +0000786 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
787
Daniel Veillard5a872412002-05-22 06:40:27 +0000788#define MAX_DAYINMONTH(yr,mon) \
789 (IS_LEAP(yr) ? daysInMonthLeap[mon - 1] : daysInMonth[mon - 1])
790
Daniel Veillard070803b2002-05-03 07:29:38 +0000791#define VALID_MDAY(dt) \
792 (IS_LEAP(dt->year) ? \
793 (dt->day <= daysInMonthLeap[dt->mon - 1]) : \
794 (dt->day <= daysInMonth[dt->mon - 1]))
795
796#define VALID_DATE(dt) \
797 (VALID_YEAR(dt->year) && VALID_MONTH(dt->mon) && VALID_MDAY(dt))
798
799#define VALID_TIME(dt) \
800 (VALID_HOUR(dt->hour) && VALID_MIN(dt->min) && \
801 VALID_SEC(dt->sec) && VALID_TZO(dt->tzo))
802
803#define VALID_DATETIME(dt) \
804 (VALID_DATE(dt) && VALID_TIME(dt))
805
806#define SECS_PER_MIN (60)
807#define SECS_PER_HOUR (60 * SECS_PER_MIN)
808#define SECS_PER_DAY (24 * SECS_PER_HOUR)
809
Daniel Veillard5a872412002-05-22 06:40:27 +0000810static const long dayInYearByMonth[12] =
811 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
812static const long dayInLeapYearByMonth[12] =
813 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 };
814
815#define DAY_IN_YEAR(day, month, year) \
816 ((IS_LEAP(year) ? \
817 dayInLeapYearByMonth[month - 1] : \
818 dayInYearByMonth[month - 1]) + day)
819
820#ifdef DEBUG
821#define DEBUG_DATE(dt) \
822 xmlGenericError(xmlGenericErrorContext, \
823 "type=%o %04ld-%02u-%02uT%02u:%02u:%03f", \
824 dt->type,dt->value.date.year,dt->value.date.mon, \
825 dt->value.date.day,dt->value.date.hour,dt->value.date.min, \
826 dt->value.date.sec); \
827 if (dt->value.date.tz_flag) \
828 if (dt->value.date.tzo != 0) \
829 xmlGenericError(xmlGenericErrorContext, \
830 "%+05d\n",dt->value.date.tzo); \
831 else \
832 xmlGenericError(xmlGenericErrorContext, "Z\n"); \
833 else \
834 xmlGenericError(xmlGenericErrorContext,"\n")
835#else
836#define DEBUG_DATE(dt)
837#endif
838
Daniel Veillard070803b2002-05-03 07:29:38 +0000839/**
840 * _xmlSchemaParseGYear:
841 * @dt: pointer to a date structure
842 * @str: pointer to the string to analyze
843 *
844 * Parses a xs:gYear without time zone and fills in the appropriate
845 * field of the @dt structure. @str is updated to point just after the
846 * xs:gYear. It is supposed that @dt->year is big enough to contain
847 * the year.
848 *
849 * Returns 0 or the error code
850 */
851static int
852_xmlSchemaParseGYear (xmlSchemaValDatePtr dt, const xmlChar **str) {
853 const xmlChar *cur = *str, *firstChar;
854 int isneg = 0, digcnt = 0;
855
856 if (((*cur < '0') || (*cur > '9')) &&
857 (*cur != '-') && (*cur != '+'))
858 return -1;
859
860 if (*cur == '-') {
861 isneg = 1;
862 cur++;
863 }
864
865 firstChar = cur;
866
867 while ((*cur >= '0') && (*cur <= '9')) {
868 dt->year = dt->year * 10 + (*cur - '0');
869 cur++;
870 digcnt++;
871 }
872
873 /* year must be at least 4 digits (CCYY); over 4
874 * digits cannot have a leading zero. */
875 if ((digcnt < 4) || ((digcnt > 4) && (*firstChar == '0')))
876 return 1;
877
878 if (isneg)
879 dt->year = - dt->year;
880
881 if (!VALID_YEAR(dt->year))
882 return 2;
883
884 *str = cur;
885 return 0;
886}
887
888/**
889 * PARSE_2_DIGITS:
890 * @num: the integer to fill in
891 * @cur: an #xmlChar *
892 * @invalid: an integer
893 *
894 * Parses a 2-digits integer and updates @num with the value. @cur is
895 * updated to point just after the integer.
896 * In case of error, @invalid is set to %TRUE, values of @num and
897 * @cur are undefined.
898 */
899#define PARSE_2_DIGITS(num, cur, invalid) \
900 if ((cur[0] < '0') || (cur[0] > '9') || \
901 (cur[1] < '0') || (cur[1] > '9')) \
902 invalid = 1; \
903 else \
904 num = (cur[0] - '0') * 10 + (cur[1] - '0'); \
905 cur += 2;
906
907/**
908 * PARSE_FLOAT:
909 * @num: the double to fill in
910 * @cur: an #xmlChar *
911 * @invalid: an integer
912 *
913 * Parses a float and updates @num with the value. @cur is
914 * updated to point just after the float. The float must have a
915 * 2-digits integer part and may or may not have a decimal part.
916 * In case of error, @invalid is set to %TRUE, values of @num and
917 * @cur are undefined.
918 */
919#define PARSE_FLOAT(num, cur, invalid) \
920 PARSE_2_DIGITS(num, cur, invalid); \
921 if (!invalid && (*cur == '.')) { \
922 double mult = 1; \
923 cur++; \
924 if ((*cur < '0') || (*cur > '9')) \
925 invalid = 1; \
926 while ((*cur >= '0') && (*cur <= '9')) { \
927 mult /= 10; \
928 num += (*cur - '0') * mult; \
929 cur++; \
930 } \
931 }
932
933/**
934 * _xmlSchemaParseGMonth:
935 * @dt: pointer to a date structure
936 * @str: pointer to the string to analyze
937 *
938 * Parses a xs:gMonth without time zone and fills in the appropriate
939 * field of the @dt structure. @str is updated to point just after the
940 * xs:gMonth.
941 *
942 * Returns 0 or the error code
943 */
944static int
945_xmlSchemaParseGMonth (xmlSchemaValDatePtr dt, const xmlChar **str) {
946 const xmlChar *cur = *str;
947 int ret = 0;
948
949 PARSE_2_DIGITS(dt->mon, cur, ret);
950 if (ret != 0)
951 return ret;
952
953 if (!VALID_MONTH(dt->mon))
954 return 2;
955
956 *str = cur;
957 return 0;
958}
959
960/**
961 * _xmlSchemaParseGDay:
962 * @dt: pointer to a date structure
963 * @str: pointer to the string to analyze
964 *
965 * Parses a xs:gDay without time zone and fills in the appropriate
966 * field of the @dt structure. @str is updated to point just after the
967 * xs:gDay.
968 *
969 * Returns 0 or the error code
970 */
971static int
972_xmlSchemaParseGDay (xmlSchemaValDatePtr dt, const xmlChar **str) {
973 const xmlChar *cur = *str;
974 int ret = 0;
975
976 PARSE_2_DIGITS(dt->day, cur, ret);
977 if (ret != 0)
978 return ret;
979
980 if (!VALID_DAY(dt->day))
981 return 2;
982
983 *str = cur;
984 return 0;
985}
986
987/**
988 * _xmlSchemaParseTime:
989 * @dt: pointer to a date structure
990 * @str: pointer to the string to analyze
991 *
992 * Parses a xs:time without time zone and fills in the appropriate
993 * fields of the @dt structure. @str is updated to point just after the
994 * xs:time.
995 * In case of error, values of @dt fields are undefined.
996 *
997 * Returns 0 or the error code
998 */
999static int
1000_xmlSchemaParseTime (xmlSchemaValDatePtr dt, const xmlChar **str) {
1001 const xmlChar *cur = *str;
1002 unsigned int hour = 0; /* use temp var in case str is not xs:time */
1003 int ret = 0;
1004
1005 PARSE_2_DIGITS(hour, cur, ret);
1006 if (ret != 0)
1007 return ret;
1008
1009 if (*cur != ':')
1010 return 1;
1011 cur++;
1012
1013 /* the ':' insures this string is xs:time */
1014 dt->hour = hour;
1015
1016 PARSE_2_DIGITS(dt->min, cur, ret);
1017 if (ret != 0)
1018 return ret;
1019
1020 if (*cur != ':')
1021 return 1;
1022 cur++;
1023
1024 PARSE_FLOAT(dt->sec, cur, ret);
1025 if (ret != 0)
1026 return ret;
1027
1028 if (!VALID_TIME(dt))
1029 return 2;
1030
1031 *str = cur;
1032 return 0;
1033}
1034
1035/**
1036 * _xmlSchemaParseTimeZone:
1037 * @dt: pointer to a date structure
1038 * @str: pointer to the string to analyze
1039 *
1040 * Parses a time zone without time zone and fills in the appropriate
1041 * field of the @dt structure. @str is updated to point just after the
1042 * time zone.
1043 *
1044 * Returns 0 or the error code
1045 */
1046static int
1047_xmlSchemaParseTimeZone (xmlSchemaValDatePtr dt, const xmlChar **str) {
1048 const xmlChar *cur = *str;
1049 int ret = 0;
1050
1051 if (str == NULL)
1052 return -1;
1053
1054 switch (*cur) {
1055 case 0:
1056 dt->tz_flag = 0;
1057 dt->tzo = 0;
1058 break;
1059
1060 case 'Z':
1061 dt->tz_flag = 1;
1062 dt->tzo = 0;
1063 cur++;
1064 break;
1065
1066 case '+':
1067 case '-': {
1068 int isneg = 0, tmp = 0;
1069 isneg = (*cur == '-');
1070
1071 cur++;
1072
1073 PARSE_2_DIGITS(tmp, cur, ret);
1074 if (ret != 0)
1075 return ret;
1076 if (!VALID_HOUR(tmp))
1077 return 2;
1078
1079 if (*cur != ':')
1080 return 1;
1081 cur++;
1082
1083 dt->tzo = tmp * 60;
1084
1085 PARSE_2_DIGITS(tmp, cur, ret);
1086 if (ret != 0)
1087 return ret;
1088 if (!VALID_MIN(tmp))
1089 return 2;
1090
1091 dt->tzo += tmp;
1092 if (isneg)
1093 dt->tzo = - dt->tzo;
1094
1095 if (!VALID_TZO(dt->tzo))
1096 return 2;
1097
Daniel Veillard5a872412002-05-22 06:40:27 +00001098 dt->tz_flag = 1;
Daniel Veillard070803b2002-05-03 07:29:38 +00001099 break;
1100 }
1101 default:
1102 return 1;
1103 }
1104
1105 *str = cur;
1106 return 0;
1107}
1108
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001109/**
1110 * _xmlSchemaBase64Decode:
1111 * @ch: a character
1112 *
1113 * Converts a base64 encoded character to its base 64 value.
1114 *
1115 * Returns 0-63 (value), 64 (pad), or -1 (not recognized)
1116 */
1117static int
1118_xmlSchemaBase64Decode (const xmlChar ch) {
1119 if (('A' <= ch) && (ch <= 'Z')) return ch - 'A';
1120 if (('a' <= ch) && (ch <= 'z')) return ch - 'a' + 26;
1121 if (('0' <= ch) && (ch <= '9')) return ch - '0' + 52;
1122 if ('+' == ch) return 62;
1123 if ('/' == ch) return 63;
1124 if ('=' == ch) return 64;
1125 return -1;
1126}
1127
Daniel Veillard070803b2002-05-03 07:29:38 +00001128/****************************************************************
1129 * *
1130 * XML Schema Dates/Times Datatypes Handling *
1131 * *
1132 ****************************************************************/
1133
1134/**
1135 * PARSE_DIGITS:
1136 * @num: the integer to fill in
1137 * @cur: an #xmlChar *
1138 * @num_type: an integer flag
1139 *
1140 * Parses a digits integer and updates @num with the value. @cur is
1141 * updated to point just after the integer.
1142 * In case of error, @num_type is set to -1, values of @num and
1143 * @cur are undefined.
1144 */
1145#define PARSE_DIGITS(num, cur, num_type) \
1146 if ((*cur < '0') || (*cur > '9')) \
1147 num_type = -1; \
1148 else \
1149 while ((*cur >= '0') && (*cur <= '9')) { \
1150 num = num * 10 + (*cur - '0'); \
1151 cur++; \
1152 }
1153
1154/**
1155 * PARSE_NUM:
1156 * @num: the double to fill in
1157 * @cur: an #xmlChar *
1158 * @num_type: an integer flag
1159 *
1160 * Parses a float or integer and updates @num with the value. @cur is
1161 * updated to point just after the number. If the number is a float,
1162 * then it must have an integer part and a decimal part; @num_type will
1163 * be set to 1. If there is no decimal part, @num_type is set to zero.
1164 * In case of error, @num_type is set to -1, values of @num and
1165 * @cur are undefined.
1166 */
1167#define PARSE_NUM(num, cur, num_type) \
1168 num = 0; \
1169 PARSE_DIGITS(num, cur, num_type); \
1170 if (!num_type && (*cur == '.')) { \
1171 double mult = 1; \
1172 cur++; \
1173 if ((*cur < '0') || (*cur > '9')) \
1174 num_type = -1; \
1175 else \
1176 num_type = 1; \
1177 while ((*cur >= '0') && (*cur <= '9')) { \
1178 mult /= 10; \
1179 num += (*cur - '0') * mult; \
1180 cur++; \
1181 } \
1182 }
1183
1184/**
Daniel Veillard5a872412002-05-22 06:40:27 +00001185 * xmlSchemaValidateDates:
Daniel Veillard455cc072003-03-31 10:13:23 +00001186 * @type: the expected type or XML_SCHEMAS_UNKNOWN
Daniel Veillard070803b2002-05-03 07:29:38 +00001187 * @dateTime: string to analyze
1188 * @val: the return computed value
1189 *
1190 * Check that @dateTime conforms to the lexical space of one of the date types.
1191 * if true a value is computed and returned in @val.
1192 *
1193 * Returns 0 if this validates, a positive error code number otherwise
1194 * and -1 in case of internal or API error.
1195 */
1196static int
Daniel Veillard455cc072003-03-31 10:13:23 +00001197xmlSchemaValidateDates (xmlSchemaValType type,
Daniel Veillard118aed72002-09-24 14:13:13 +00001198 const xmlChar *dateTime, xmlSchemaValPtr *val) {
Daniel Veillard070803b2002-05-03 07:29:38 +00001199 xmlSchemaValPtr dt;
1200 int ret;
1201 const xmlChar *cur = dateTime;
1202
1203#define RETURN_TYPE_IF_VALID(t) \
1204 if (IS_TZO_CHAR(*cur)) { \
1205 ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur); \
1206 if (ret == 0) { \
1207 if (*cur != 0) \
1208 goto error; \
1209 dt->type = t; \
Daniel Veillard455cc072003-03-31 10:13:23 +00001210 goto done; \
Daniel Veillard070803b2002-05-03 07:29:38 +00001211 } \
1212 }
1213
1214 if (dateTime == NULL)
1215 return -1;
1216
1217 if ((*cur != '-') && (*cur < '0') && (*cur > '9'))
1218 return 1;
1219
1220 dt = xmlSchemaNewValue(XML_SCHEMAS_UNKNOWN);
1221 if (dt == NULL)
1222 return -1;
1223
1224 if ((cur[0] == '-') && (cur[1] == '-')) {
1225 /*
1226 * It's an incomplete date (xs:gMonthDay, xs:gMonth or
1227 * xs:gDay)
1228 */
1229 cur += 2;
1230
1231 /* is it an xs:gDay? */
1232 if (*cur == '-') {
Daniel Veillard455cc072003-03-31 10:13:23 +00001233 if (type == XML_SCHEMAS_GMONTH)
1234 goto error;
Daniel Veillard070803b2002-05-03 07:29:38 +00001235 ++cur;
1236 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
1237 if (ret != 0)
1238 goto error;
1239
1240 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GDAY);
1241
1242 goto error;
1243 }
1244
1245 /*
1246 * it should be an xs:gMonthDay or xs:gMonth
1247 */
1248 ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
1249 if (ret != 0)
1250 goto error;
1251
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001252 /*
1253 * a '-' char could indicate this type is xs:gMonthDay or
1254 * a negative time zone offset. Check for xs:gMonthDay first.
1255 * Also the first three char's of a negative tzo (-MM:SS) can
1256 * appear to be a valid day; so even if the day portion
1257 * of the xs:gMonthDay verifies, we must insure it was not
1258 * a tzo.
1259 */
1260 if (*cur == '-') {
1261 const xmlChar *rewnd = cur;
1262 cur++;
Daniel Veillard070803b2002-05-03 07:29:38 +00001263
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001264 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
1265 if ((ret == 0) && ((*cur == 0) || (*cur != ':'))) {
1266
1267 /*
1268 * we can use the VALID_MDAY macro to validate the month
1269 * and day because the leap year test will flag year zero
1270 * as a leap year (even though zero is an invalid year).
1271 */
1272 if (VALID_MDAY((&(dt->value.date)))) {
1273
1274 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTHDAY);
1275
1276 goto error;
1277 }
1278 }
1279
1280 /*
1281 * not xs:gMonthDay so rewind and check if just xs:gMonth
1282 * with an optional time zone.
1283 */
1284 cur = rewnd;
1285 }
1286
1287 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTH);
Daniel Veillard070803b2002-05-03 07:29:38 +00001288
1289 goto error;
1290 }
1291
1292 /*
1293 * It's a right-truncated date or an xs:time.
1294 * Try to parse an xs:time then fallback on right-truncated dates.
1295 */
1296 if ((*cur >= '0') && (*cur <= '9')) {
1297 ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
1298 if (ret == 0) {
1299 /* it's an xs:time */
1300 RETURN_TYPE_IF_VALID(XML_SCHEMAS_TIME);
1301 }
1302 }
1303
1304 /* fallback on date parsing */
1305 cur = dateTime;
1306
1307 ret = _xmlSchemaParseGYear(&(dt->value.date), &cur);
1308 if (ret != 0)
1309 goto error;
1310
1311 /* is it an xs:gYear? */
1312 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEAR);
1313
1314 if (*cur != '-')
1315 goto error;
1316 cur++;
1317
1318 ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
1319 if (ret != 0)
1320 goto error;
1321
1322 /* is it an xs:gYearMonth? */
1323 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEARMONTH);
1324
1325 if (*cur != '-')
1326 goto error;
1327 cur++;
1328
1329 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
1330 if ((ret != 0) || !VALID_DATE((&(dt->value.date))))
1331 goto error;
1332
1333 /* is it an xs:date? */
1334 RETURN_TYPE_IF_VALID(XML_SCHEMAS_DATE);
1335
1336 if (*cur != 'T')
1337 goto error;
1338 cur++;
1339
1340 /* it should be an xs:dateTime */
1341 ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
1342 if (ret != 0)
1343 goto error;
1344
1345 ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur);
1346 if ((ret != 0) || (*cur != 0) || !VALID_DATETIME((&(dt->value.date))))
1347 goto error;
1348
Daniel Veillard455cc072003-03-31 10:13:23 +00001349
Daniel Veillard070803b2002-05-03 07:29:38 +00001350 dt->type = XML_SCHEMAS_DATETIME;
1351
Daniel Veillard455cc072003-03-31 10:13:23 +00001352done:
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001353#if 1
1354 if ((type != XML_SCHEMAS_UNKNOWN) && (type != dt->type))
1355 goto error;
1356#else
1357 /*
1358 * insure the parsed type is equal to or less significant (right
1359 * truncated) than the desired type.
1360 */
1361 if ((type != XML_SCHEMAS_UNKNOWN) && (type != dt->type)) {
1362
1363 /* time only matches time */
1364 if ((type == XML_SCHEMAS_TIME) && (dt->type == XML_SCHEMAS_TIME))
1365 goto error;
1366
1367 if ((type == XML_SCHEMAS_DATETIME) &&
1368 ((dt->type != XML_SCHEMAS_DATE) ||
1369 (dt->type != XML_SCHEMAS_GYEARMONTH) ||
1370 (dt->type != XML_SCHEMAS_GYEAR)))
1371 goto error;
1372
1373 if ((type == XML_SCHEMAS_DATE) &&
1374 ((dt->type != XML_SCHEMAS_GYEAR) ||
1375 (dt->type != XML_SCHEMAS_GYEARMONTH)))
1376 goto error;
1377
1378 if ((type == XML_SCHEMAS_GYEARMONTH) && (dt->type != XML_SCHEMAS_GYEAR))
1379 goto error;
1380
1381 if ((type == XML_SCHEMAS_GMONTHDAY) && (dt->type != XML_SCHEMAS_GMONTH))
1382 goto error;
1383 }
Daniel Veillard455cc072003-03-31 10:13:23 +00001384#endif
1385
Daniel Veillard070803b2002-05-03 07:29:38 +00001386 if (val != NULL)
1387 *val = dt;
Daniel Veillard80b19092003-03-28 13:29:53 +00001388 else
1389 xmlSchemaFreeValue(dt);
Daniel Veillard070803b2002-05-03 07:29:38 +00001390
1391 return 0;
1392
1393error:
1394 if (dt != NULL)
1395 xmlSchemaFreeValue(dt);
1396 return 1;
1397}
1398
1399/**
Daniel Veillard5a872412002-05-22 06:40:27 +00001400 * xmlSchemaValidateDuration:
Daniel Veillard070803b2002-05-03 07:29:38 +00001401 * @type: the predefined type
1402 * @duration: string to analyze
1403 * @val: the return computed value
1404 *
1405 * Check that @duration conforms to the lexical space of the duration type.
1406 * if true a value is computed and returned in @val.
1407 *
1408 * Returns 0 if this validates, a positive error code number otherwise
1409 * and -1 in case of internal or API error.
1410 */
1411static int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00001412xmlSchemaValidateDuration (xmlSchemaTypePtr type ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +00001413 const xmlChar *duration, xmlSchemaValPtr *val) {
Daniel Veillard070803b2002-05-03 07:29:38 +00001414 const xmlChar *cur = duration;
1415 xmlSchemaValPtr dur;
1416 int isneg = 0;
1417 unsigned int seq = 0;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001418 double num;
1419 int num_type = 0; /* -1 = invalid, 0 = int, 1 = floating */
1420 const xmlChar desig[] = {'Y', 'M', 'D', 'H', 'M', 'S'};
1421 const double multi[] = { 0.0, 0.0, 86400.0, 3600.0, 60.0, 1.0, 0.0};
Daniel Veillard070803b2002-05-03 07:29:38 +00001422
1423 if (duration == NULL)
1424 return -1;
1425
1426 if (*cur == '-') {
1427 isneg = 1;
1428 cur++;
1429 }
1430
1431 /* duration must start with 'P' (after sign) */
1432 if (*cur++ != 'P')
1433 return 1;
1434
Daniel Veillard80b19092003-03-28 13:29:53 +00001435 if (*cur == 0)
1436 return 1;
1437
Daniel Veillard070803b2002-05-03 07:29:38 +00001438 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
1439 if (dur == NULL)
1440 return -1;
1441
1442 while (*cur != 0) {
Daniel Veillard070803b2002-05-03 07:29:38 +00001443
1444 /* input string should be empty or invalid date/time item */
1445 if (seq >= sizeof(desig))
1446 goto error;
1447
1448 /* T designator must be present for time items */
1449 if (*cur == 'T') {
1450 if (seq <= 3) {
1451 seq = 3;
1452 cur++;
1453 } else
1454 return 1;
1455 } else if (seq == 3)
1456 goto error;
1457
1458 /* parse the number portion of the item */
1459 PARSE_NUM(num, cur, num_type);
1460
1461 if ((num_type == -1) || (*cur == 0))
1462 goto error;
1463
1464 /* update duration based on item type */
1465 while (seq < sizeof(desig)) {
1466 if (*cur == desig[seq]) {
1467
1468 /* verify numeric type; only seconds can be float */
1469 if ((num_type != 0) && (seq < (sizeof(desig)-1)))
1470 goto error;
1471
1472 switch (seq) {
1473 case 0:
1474 dur->value.dur.mon = (long)num * 12;
1475 break;
1476 case 1:
1477 dur->value.dur.mon += (long)num;
1478 break;
1479 default:
1480 /* convert to seconds using multiplier */
1481 dur->value.dur.sec += num * multi[seq];
1482 seq++;
1483 break;
1484 }
1485
1486 break; /* exit loop */
1487 }
1488 /* no date designators found? */
1489 if (++seq == 3)
1490 goto error;
1491 }
1492 cur++;
1493 }
1494
1495 if (isneg) {
1496 dur->value.dur.mon = -dur->value.dur.mon;
1497 dur->value.dur.day = -dur->value.dur.day;
1498 dur->value.dur.sec = -dur->value.dur.sec;
1499 }
1500
1501 if (val != NULL)
1502 *val = dur;
Daniel Veillard80b19092003-03-28 13:29:53 +00001503 else
1504 xmlSchemaFreeValue(dur);
Daniel Veillard070803b2002-05-03 07:29:38 +00001505
1506 return 0;
1507
1508error:
1509 if (dur != NULL)
1510 xmlSchemaFreeValue(dur);
1511 return 1;
1512}
1513
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001514/**
1515 * xmlSchemaStrip:
1516 * @value: a value
1517 *
1518 * Removes the leading and ending spaces of a string
1519 *
1520 * Returns the new string or NULL if no change was required.
1521 */
1522static xmlChar *
1523xmlSchemaStrip(const xmlChar *value) {
1524 const xmlChar *start = value, *end, *f;
1525
1526 if (value == NULL) return(NULL);
William M. Brack76e95df2003-10-18 16:20:14 +00001527 while ((*start != 0) && (IS_BLANK_CH(*start))) start++;
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001528 end = start;
1529 while (*end != 0) end++;
1530 f = end;
1531 end--;
William M. Brack76e95df2003-10-18 16:20:14 +00001532 while ((end > start) && (IS_BLANK_CH(*end))) end--;
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001533 end++;
1534 if ((start == value) && (f == end)) return(NULL);
1535 return(xmlStrndup(start, end - start));
1536}
Daniel Veillard96a4b252003-02-06 08:22:32 +00001537
1538/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001539 * xmlSchemaCollapseString:
1540 * @value: a value
1541 *
1542 * Removes and normalize white spaces in the string
1543 *
1544 * Returns the new string or NULL if no change was required.
1545 */
Daniel Veillard01fa6152004-06-29 17:04:39 +00001546xmlChar *
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001547xmlSchemaCollapseString(const xmlChar *value) {
1548 const xmlChar *start = value, *end, *f;
1549 xmlChar *g;
1550 int col = 0;
1551
1552 if (value == NULL) return(NULL);
William M. Brack76e95df2003-10-18 16:20:14 +00001553 while ((*start != 0) && (IS_BLANK_CH(*start))) start++;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001554 end = start;
1555 while (*end != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00001556 if ((*end == ' ') && (IS_BLANK_CH(end[1]))) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001557 col = end - start;
1558 break;
1559 } else if ((*end == 0xa) || (*end == 0x9) || (*end == 0xd)) {
1560 col = end - start;
1561 break;
1562 }
1563 end++;
1564 }
1565 if (col == 0) {
1566 f = end;
1567 end--;
William M. Brack76e95df2003-10-18 16:20:14 +00001568 while ((end > start) && (IS_BLANK_CH(*end))) end--;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001569 end++;
1570 if ((start == value) && (f == end)) return(NULL);
1571 return(xmlStrndup(start, end - start));
1572 }
1573 start = xmlStrdup(start);
1574 if (start == NULL) return(NULL);
1575 g = (xmlChar *) (start + col);
1576 end = g;
1577 while (*end != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00001578 if (IS_BLANK_CH(*end)) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001579 end++;
William M. Brack76e95df2003-10-18 16:20:14 +00001580 while (IS_BLANK_CH(*end)) end++;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001581 if (*end != 0)
1582 *g++ = ' ';
1583 } else
1584 *g++ = *end++;
1585 }
1586 *g = 0;
1587 return((xmlChar *) start);
1588}
1589
1590/**
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001591 * xmlSchemaValAtomicListNode:
1592 * @type: the predefined atomic type for a token in the list
1593 * @value: the list value to check
1594 * @ret: the return computed value
1595 * @node: the node containing the value
1596 *
1597 * Check that a value conforms to the lexical space of the predefined
1598 * list type. if true a value is computed and returned in @ret.
1599 *
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001600 * Returns the number of items if this validates, a negative error code
1601 * number otherwise
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001602 */
1603static int
1604xmlSchemaValAtomicListNode(xmlSchemaTypePtr type, const xmlChar *value,
1605 xmlSchemaValPtr *ret, xmlNodePtr node) {
1606 xmlChar *val, *cur, *endval;
1607 int nb_values = 0;
Daniel Veillard580ced82003-03-21 21:22:48 +00001608 int tmp = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001609
1610 if (value == NULL) {
1611 return(-1);
1612 }
1613 val = xmlStrdup(value);
1614 if (val == NULL) {
1615 return(-1);
1616 }
1617 cur = val;
1618 /*
1619 * Split the list
1620 */
William M. Brack76e95df2003-10-18 16:20:14 +00001621 while (IS_BLANK_CH(*cur)) *cur++ = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001622 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00001623 if (IS_BLANK_CH(*cur)) {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001624 *cur = 0;
1625 cur++;
William M. Brack76e95df2003-10-18 16:20:14 +00001626 while (IS_BLANK_CH(*cur)) *cur++ = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001627 } else {
1628 nb_values++;
1629 cur++;
William M. Brack76e95df2003-10-18 16:20:14 +00001630 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001631 }
1632 }
1633 if (nb_values == 0) {
1634 if (ret != NULL) {
1635 TODO
1636 }
1637 xmlFree(val);
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001638 return(nb_values);
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001639 }
1640 endval = cur;
1641 cur = val;
1642 while ((*cur == 0) && (cur != endval)) cur++;
1643 while (cur != endval) {
1644 tmp = xmlSchemaValPredefTypeNode(type, cur, NULL, node);
1645 if (tmp != 0)
1646 break;
1647 while (*cur != 0) cur++;
1648 while ((*cur == 0) && (cur != endval)) cur++;
1649 }
1650 xmlFree(val);
1651 if (ret != NULL) {
1652 TODO
1653 }
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001654 if (tmp == 0)
1655 return(nb_values);
1656 return(-1);
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001657}
1658
1659/**
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001660 * xmlSchemaParseUInt:
1661 * @str: pointer to the string R/W
1662 * @llo: pointer to the low result
1663 * @lmi: pointer to the mid result
1664 * @lhi: pointer to the high result
1665 *
1666 * Parse an unsigned long into 3 fields.
1667 *
1668 * Returns the number of chars parsed or -1 if overflow of the capacity
1669 */
1670static int
1671xmlSchemaParseUInt(const xmlChar **str, unsigned long *llo,
1672 unsigned long *lmi, unsigned long *lhi) {
1673 unsigned long lo = 0, mi = 0, hi = 0;
1674 const xmlChar *tmp, *cur = *str;
1675 int ret = 0, i = 0;
1676
1677 while (*cur == '0') {
1678 ret++;
1679 cur++;
1680 }
1681 tmp = cur;
1682 while ((*tmp != 0) && (*tmp >= '0') && (*tmp <= '9')) {
1683 i++;tmp++;ret++;
1684 }
1685 if (i > 24) {
1686 *str = tmp;
1687 return(-1);
1688 }
1689 while (i > 16) {
1690 hi = hi * 10 + (*cur++ - '0');
1691 i--;
1692 }
1693 while (i > 8) {
1694 mi = mi * 10 + (*cur++ - '0');
1695 i--;
1696 }
1697 while (i > 0) {
1698 lo = lo * 10 + (*cur++ - '0');
1699 i--;
1700 }
1701
1702 *str = cur;
1703 *llo = lo;
1704 *lmi = mi;
1705 *lhi = hi;
1706 return(ret);
1707}
1708
1709/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001710 * xmlSchemaValAtomicType:
1711 * @type: the predefined type
1712 * @value: the value to check
1713 * @val: the return computed value
1714 * @node: the node containing the value
1715 * flags: flags to control the vlidation
1716 *
1717 * Check that a value conforms to the lexical space of the atomic type.
1718 * if true a value is computed and returned in @val.
Daniel Veillard01fa6152004-06-29 17:04:39 +00001719 * This checks the value space for list types as well (IDREFS, NMTOKENS).
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001720 *
1721 * Returns 0 if this validates, a positive error code number otherwise
1722 * and -1 in case of internal or API error.
1723 */
1724static int
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001725xmlSchemaValAtomicType(xmlSchemaTypePtr type, const xmlChar * value,
1726 xmlSchemaValPtr * val, xmlNodePtr node, int flags)
1727{
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001728 xmlSchemaValPtr v;
1729 xmlChar *norm = NULL;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001730 int ret = 0;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001731
1732 if (xmlSchemaTypesInitialized == 0)
Daniel Veillard01fa6152004-06-29 17:04:39 +00001733 xmlSchemaInitTypes();
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001734 if (type == NULL)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001735 return (-1);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001736
1737 if (val != NULL)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001738 *val = NULL;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001739 if ((flags == 0) && (value != NULL)) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00001740 if ((type->builtInType != XML_SCHEMAS_STRING) &&
1741 (type->builtInType != XML_SCHEMAS_NORMSTRING)) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001742 norm = xmlSchemaCollapseString(value);
1743 if (norm != NULL)
1744 value = norm;
1745 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001746 }
1747
Daniel Veillard01fa6152004-06-29 17:04:39 +00001748 switch (type->builtInType) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001749 case XML_SCHEMAS_UNKNOWN:
Daniel Veillard01fa6152004-06-29 17:04:39 +00001750 if (type == xmlSchemaTypeAnySimpleTypeDef)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001751 goto return0;
1752 goto error;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001753 case XML_SCHEMAS_STRING:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001754 goto return0;
Daniel Veillard1516d5b2004-01-22 07:27:45 +00001755 case XML_SCHEMAS_NORMSTRING:{
1756 const xmlChar *cur = value;
1757
1758 while (*cur != 0) {
1759 if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) {
1760 goto return1;
1761 } else {
1762 cur++;
1763 }
1764 }
1765 if (val != NULL) {
1766 v = xmlSchemaNewValue(XML_SCHEMAS_NORMSTRING);
1767 if (v != NULL) {
1768 v->value.str = xmlStrdup(value);
1769 *val = v;
1770 } else {
1771 goto error;
1772 }
1773 }
1774 goto return0;
1775 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001776 case XML_SCHEMAS_DECIMAL:{
1777 const xmlChar *cur = value, *tmp;
1778 unsigned int frac = 0, len, neg = 0;
1779 unsigned long base = 0;
1780
1781 if (cur == NULL)
1782 goto return1;
1783 if (*cur == '+')
1784 cur++;
1785 else if (*cur == '-') {
1786 neg = 1;
1787 cur++;
1788 }
1789 tmp = cur;
1790 while ((*cur >= '0') && (*cur <= '9')) {
1791 base = base * 10 + (*cur - '0');
1792 cur++;
1793 }
1794 len = cur - tmp;
1795 if (*cur == '.') {
1796 cur++;
1797 tmp = cur;
1798 while ((*cur >= '0') && (*cur <= '9')) {
1799 base = base * 10 + (*cur - '0');
1800 cur++;
1801 }
1802 frac = cur - tmp;
1803 }
1804 if (*cur != 0)
1805 goto return1;
1806 if (val != NULL) {
1807 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
1808 if (v != NULL) {
1809 v->value.decimal.lo = base;
1810 v->value.decimal.sign = neg;
1811 v->value.decimal.frac = frac;
1812 v->value.decimal.total = frac + len;
1813 *val = v;
1814 }
1815 }
1816 goto return0;
1817 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001818 case XML_SCHEMAS_TIME:
1819 case XML_SCHEMAS_GDAY:
1820 case XML_SCHEMAS_GMONTH:
1821 case XML_SCHEMAS_GMONTHDAY:
1822 case XML_SCHEMAS_GYEAR:
1823 case XML_SCHEMAS_GYEARMONTH:
1824 case XML_SCHEMAS_DATE:
1825 case XML_SCHEMAS_DATETIME:
Daniel Veillard01fa6152004-06-29 17:04:39 +00001826 ret = xmlSchemaValidateDates(type->builtInType, value, val);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001827 break;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001828 case XML_SCHEMAS_DURATION:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001829 ret = xmlSchemaValidateDuration(type, value, val);
1830 break;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001831 case XML_SCHEMAS_FLOAT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001832 case XML_SCHEMAS_DOUBLE:{
1833 const xmlChar *cur = value;
1834 int neg = 0;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001835
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001836 if (cur == NULL)
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00001837 goto return1;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001838 if ((cur[0] == 'N') && (cur[1] == 'a') && (cur[2] == 'N')) {
1839 cur += 3;
1840 if (*cur != 0)
1841 goto return1;
1842 if (val != NULL) {
1843 if (type == xmlSchemaTypeFloatDef) {
1844 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1845 if (v != NULL) {
1846 v->value.f = (float) xmlXPathNAN;
1847 } else {
1848 xmlSchemaFreeValue(v);
1849 goto error;
1850 }
1851 } else {
1852 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1853 if (v != NULL) {
1854 v->value.d = xmlXPathNAN;
1855 } else {
1856 xmlSchemaFreeValue(v);
1857 goto error;
1858 }
1859 }
1860 *val = v;
1861 }
1862 goto return0;
1863 }
1864 if (*cur == '-') {
1865 neg = 1;
1866 cur++;
1867 }
1868 if ((cur[0] == 'I') && (cur[1] == 'N') && (cur[2] == 'F')) {
1869 cur += 3;
1870 if (*cur != 0)
1871 goto return1;
1872 if (val != NULL) {
1873 if (type == xmlSchemaTypeFloatDef) {
1874 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1875 if (v != NULL) {
1876 if (neg)
1877 v->value.f = (float) xmlXPathNINF;
1878 else
1879 v->value.f = (float) xmlXPathPINF;
1880 } else {
1881 xmlSchemaFreeValue(v);
1882 goto error;
1883 }
1884 } else {
1885 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1886 if (v != NULL) {
1887 if (neg)
1888 v->value.d = xmlXPathNINF;
1889 else
1890 v->value.d = xmlXPathPINF;
1891 } else {
1892 xmlSchemaFreeValue(v);
1893 goto error;
1894 }
1895 }
1896 *val = v;
1897 }
1898 goto return0;
1899 }
1900 if ((neg == 0) && (*cur == '+'))
1901 cur++;
1902 if ((cur[0] == 0) || (cur[0] == '+') || (cur[0] == '-'))
1903 goto return1;
1904 while ((*cur >= '0') && (*cur <= '9')) {
1905 cur++;
1906 }
1907 if (*cur == '.') {
1908 cur++;
1909 while ((*cur >= '0') && (*cur <= '9'))
1910 cur++;
1911 }
1912 if ((*cur == 'e') || (*cur == 'E')) {
1913 cur++;
1914 if ((*cur == '-') || (*cur == '+'))
1915 cur++;
1916 while ((*cur >= '0') && (*cur <= '9'))
1917 cur++;
1918 }
1919 if (*cur != 0)
1920 goto return1;
1921 if (val != NULL) {
1922 if (type == xmlSchemaTypeFloatDef) {
1923 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1924 if (v != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001925 if (sscanf((const char *) value, "%f",
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001926 &(v->value.f)) == 1) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00001927 *val = v;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001928 } else {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001929 xmlSchemaFreeValue(v);
1930 goto return1;
1931 }
1932 } else {
1933 goto error;
1934 }
1935 } else {
1936 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1937 if (v != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001938 if (sscanf((const char *) value, "%lf",
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001939 &(v->value.d)) == 1) {
1940 *val = v;
1941 } else {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001942 xmlSchemaFreeValue(v);
1943 goto return1;
1944 }
1945 } else {
1946 goto error;
1947 }
1948 }
1949 }
1950 goto return0;
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00001951 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001952 case XML_SCHEMAS_BOOLEAN:{
1953 const xmlChar *cur = value;
1954
1955 if ((cur[0] == '0') && (cur[1] == 0))
1956 ret = 0;
1957 else if ((cur[0] == '1') && (cur[1] == 0))
1958 ret = 1;
1959 else if ((cur[0] == 't') && (cur[1] == 'r')
1960 && (cur[2] == 'u') && (cur[3] == 'e')
1961 && (cur[4] == 0))
1962 ret = 1;
1963 else if ((cur[0] == 'f') && (cur[1] == 'a')
1964 && (cur[2] == 'l') && (cur[3] == 's')
1965 && (cur[4] == 'e') && (cur[5] == 0))
1966 ret = 0;
1967 else
1968 goto return1;
1969 if (val != NULL) {
1970 v = xmlSchemaNewValue(XML_SCHEMAS_BOOLEAN);
1971 if (v != NULL) {
1972 v->value.b = ret;
1973 *val = v;
1974 } else {
1975 goto error;
1976 }
1977 }
1978 goto return0;
1979 }
1980 case XML_SCHEMAS_TOKEN:{
1981 const xmlChar *cur = value;
1982
William M. Brack76e95df2003-10-18 16:20:14 +00001983 if (IS_BLANK_CH(*cur))
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001984 goto return1;
1985
1986 while (*cur != 0) {
1987 if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) {
1988 goto return1;
1989 } else if (*cur == ' ') {
1990 cur++;
1991 if (*cur == 0)
1992 goto return1;
1993 if (*cur == ' ')
1994 goto return1;
1995 } else {
1996 cur++;
1997 }
1998 }
1999 if (val != NULL) {
2000 v = xmlSchemaNewValue(XML_SCHEMAS_TOKEN);
2001 if (v != NULL) {
2002 v->value.str = xmlStrdup(value);
2003 *val = v;
2004 } else {
2005 goto error;
2006 }
2007 }
2008 goto return0;
2009 }
2010 case XML_SCHEMAS_LANGUAGE:
2011 if (xmlCheckLanguageID(value) == 1) {
2012 if (val != NULL) {
2013 v = xmlSchemaNewValue(XML_SCHEMAS_LANGUAGE);
2014 if (v != NULL) {
2015 v->value.str = xmlStrdup(value);
2016 *val = v;
2017 } else {
2018 goto error;
2019 }
2020 }
2021 goto return0;
2022 }
2023 goto return1;
2024 case XML_SCHEMAS_NMTOKEN:
2025 if (xmlValidateNMToken(value, 1) == 0) {
2026 if (val != NULL) {
2027 v = xmlSchemaNewValue(XML_SCHEMAS_NMTOKEN);
2028 if (v != NULL) {
2029 v->value.str = xmlStrdup(value);
2030 *val = v;
2031 } else {
2032 goto error;
2033 }
2034 }
2035 goto return0;
2036 }
2037 goto return1;
2038 case XML_SCHEMAS_NMTOKENS:
2039 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeNmtokenDef,
2040 value, val, node);
2041 if (ret > 0)
2042 ret = 0;
2043 else
2044 ret = 1;
2045 goto done;
2046 case XML_SCHEMAS_NAME:
2047 ret = xmlValidateName(value, 1);
2048 if ((ret == 0) && (val != NULL)) {
2049 TODO;
2050 }
2051 goto done;
2052 case XML_SCHEMAS_QNAME:{
2053 xmlChar *uri = NULL;
2054 xmlChar *local = NULL;
2055
2056 ret = xmlValidateQName(value, 1);
2057 if ((ret == 0) && (node != NULL)) {
2058 xmlChar *prefix;
2059
2060 local = xmlSplitQName2(value, &prefix);
2061 if (prefix != NULL) {
2062 xmlNsPtr ns;
2063
2064 ns = xmlSearchNs(node->doc, node, prefix);
2065 if (ns == NULL)
2066 ret = 1;
2067 else if (val != NULL)
2068 uri = xmlStrdup(ns->href);
2069 }
2070 if ((local != NULL) && ((val == NULL) || (ret != 0)))
2071 xmlFree(local);
2072 if (prefix != NULL)
2073 xmlFree(prefix);
2074 }
2075 if ((ret == 0) && (val != NULL)) {
2076 v = xmlSchemaNewValue(XML_SCHEMAS_QNAME);
2077 if (v != NULL) {
2078 if (local != NULL)
2079 v->value.qname.name = local;
2080 else
2081 v->value.qname.name = xmlStrdup(value);
2082 if (uri != NULL)
2083 v->value.qname.uri = uri;
2084
2085 *val = v;
2086 } else {
2087 if (local != NULL)
2088 xmlFree(local);
2089 if (uri != NULL)
2090 xmlFree(uri);
2091 goto error;
2092 }
2093 }
2094 goto done;
2095 }
2096 case XML_SCHEMAS_NCNAME:
2097 ret = xmlValidateNCName(value, 1);
2098 if ((ret == 0) && (val != NULL)) {
2099 v = xmlSchemaNewValue(XML_SCHEMAS_NCNAME);
2100 if (v != NULL) {
2101 v->value.str = xmlStrdup(value);
2102 *val = v;
2103 } else {
2104 goto error;
2105 }
2106 }
2107 goto done;
2108 case XML_SCHEMAS_ID:
2109 ret = xmlValidateNCName(value, 1);
2110 if ((ret == 0) && (val != NULL)) {
2111 v = xmlSchemaNewValue(XML_SCHEMAS_ID);
2112 if (v != NULL) {
2113 v->value.str = xmlStrdup(value);
2114 *val = v;
2115 } else {
2116 goto error;
2117 }
2118 }
2119 if ((ret == 0) && (node != NULL) &&
2120 (node->type == XML_ATTRIBUTE_NODE)) {
2121 xmlAttrPtr attr = (xmlAttrPtr) node;
2122
2123 /*
2124 * NOTE: the IDness might have already be declared in the DTD
2125 */
2126 if (attr->atype != XML_ATTRIBUTE_ID) {
2127 xmlIDPtr res;
2128 xmlChar *strip;
2129
2130 strip = xmlSchemaStrip(value);
2131 if (strip != NULL) {
2132 res = xmlAddID(NULL, node->doc, strip, attr);
2133 xmlFree(strip);
2134 } else
2135 res = xmlAddID(NULL, node->doc, value, attr);
2136 if (res == NULL) {
2137 ret = 2;
2138 } else {
2139 attr->atype = XML_ATTRIBUTE_ID;
2140 }
2141 }
2142 }
2143 goto done;
2144 case XML_SCHEMAS_IDREF:
2145 ret = xmlValidateNCName(value, 1);
2146 if ((ret == 0) && (val != NULL)) {
2147 TODO;
2148 }
2149 if ((ret == 0) && (node != NULL) &&
2150 (node->type == XML_ATTRIBUTE_NODE)) {
2151 xmlAttrPtr attr = (xmlAttrPtr) node;
2152 xmlChar *strip;
2153
2154 strip = xmlSchemaStrip(value);
2155 if (strip != NULL) {
2156 xmlAddRef(NULL, node->doc, strip, attr);
2157 xmlFree(strip);
2158 } else
2159 xmlAddRef(NULL, node->doc, value, attr);
2160 attr->atype = XML_ATTRIBUTE_IDREF;
2161 }
2162 goto done;
2163 case XML_SCHEMAS_IDREFS:
2164 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeIdrefDef,
2165 value, val, node);
2166 if (ret < 0)
2167 ret = 2;
2168 else
2169 ret = 0;
2170 if ((ret == 0) && (node != NULL) &&
2171 (node->type == XML_ATTRIBUTE_NODE)) {
2172 xmlAttrPtr attr = (xmlAttrPtr) node;
2173
2174 attr->atype = XML_ATTRIBUTE_IDREFS;
2175 }
2176 goto done;
2177 case XML_SCHEMAS_ENTITY:{
2178 xmlChar *strip;
2179
2180 ret = xmlValidateNCName(value, 1);
2181 if ((node == NULL) || (node->doc == NULL))
2182 ret = 3;
2183 if (ret == 0) {
2184 xmlEntityPtr ent;
2185
2186 strip = xmlSchemaStrip(value);
2187 if (strip != NULL) {
2188 ent = xmlGetDocEntity(node->doc, strip);
2189 xmlFree(strip);
2190 } else {
2191 ent = xmlGetDocEntity(node->doc, value);
2192 }
2193 if ((ent == NULL) ||
2194 (ent->etype !=
2195 XML_EXTERNAL_GENERAL_UNPARSED_ENTITY))
2196 ret = 4;
2197 }
2198 if ((ret == 0) && (val != NULL)) {
2199 TODO;
2200 }
2201 if ((ret == 0) && (node != NULL) &&
2202 (node->type == XML_ATTRIBUTE_NODE)) {
2203 xmlAttrPtr attr = (xmlAttrPtr) node;
2204
2205 attr->atype = XML_ATTRIBUTE_ENTITY;
2206 }
2207 goto done;
2208 }
2209 case XML_SCHEMAS_ENTITIES:
2210 if ((node == NULL) || (node->doc == NULL))
2211 goto return3;
2212 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeEntityDef,
2213 value, val, node);
2214 if (ret <= 0)
2215 ret = 1;
2216 else
2217 ret = 0;
2218 if ((ret == 0) && (node != NULL) &&
2219 (node->type == XML_ATTRIBUTE_NODE)) {
2220 xmlAttrPtr attr = (xmlAttrPtr) node;
2221
2222 attr->atype = XML_ATTRIBUTE_ENTITIES;
2223 }
2224 goto done;
2225 case XML_SCHEMAS_NOTATION:{
2226 xmlChar *uri = NULL;
2227 xmlChar *local = NULL;
2228
2229 ret = xmlValidateQName(value, 1);
2230 if ((ret == 0) && (node != NULL)) {
2231 xmlChar *prefix;
2232
2233 local = xmlSplitQName2(value, &prefix);
2234 if (prefix != NULL) {
2235 xmlNsPtr ns;
2236
2237 ns = xmlSearchNs(node->doc, node, prefix);
2238 if (ns == NULL)
2239 ret = 1;
2240 else if (val != NULL)
2241 uri = xmlStrdup(ns->href);
2242 }
2243 if ((local != NULL) && ((val == NULL) || (ret != 0)))
2244 xmlFree(local);
2245 if (prefix != NULL)
2246 xmlFree(prefix);
2247 }
2248 if ((node == NULL) || (node->doc == NULL))
2249 ret = 3;
2250 if (ret == 0) {
2251 ret = xmlValidateNotationUse(NULL, node->doc, value);
2252 if (ret == 1)
2253 ret = 0;
2254 else
2255 ret = 1;
2256 }
2257 if ((ret == 0) && (val != NULL)) {
2258 v = xmlSchemaNewValue(XML_SCHEMAS_NOTATION);
2259 if (v != NULL) {
2260 if (local != NULL)
2261 v->value.qname.name = local;
2262 else
2263 v->value.qname.name = xmlStrdup(value);
2264 if (uri != NULL)
2265 v->value.qname.uri = uri;
2266
2267 *val = v;
2268 } else {
2269 if (local != NULL)
2270 xmlFree(local);
2271 if (uri != NULL)
2272 xmlFree(uri);
2273 goto error;
2274 }
2275 }
2276 goto done;
2277 }
2278 case XML_SCHEMAS_ANYURI:{
Daniel Veillard11c466a2004-03-14 12:20:15 +00002279 if (*value != 0) {
2280 xmlURIPtr uri = xmlParseURI((const char *) value);
2281 if (uri == NULL)
2282 goto return1;
2283 xmlFreeURI(uri);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002284 }
Daniel Veillard11c466a2004-03-14 12:20:15 +00002285
2286 if (val != NULL) {
2287 v = xmlSchemaNewValue(XML_SCHEMAS_ANYURI);
2288 if (v == NULL)
2289 goto error;
2290 v->value.str = xmlStrdup(value);
2291 *val = v;
2292 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002293 goto return0;
2294 }
2295 case XML_SCHEMAS_HEXBINARY:{
2296 const xmlChar *cur = value;
2297 xmlChar *base;
2298 int total, i = 0;
2299
2300 if (cur == NULL)
2301 goto return1;
2302
2303 while (((*cur >= '0') && (*cur <= '9')) ||
2304 ((*cur >= 'A') && (*cur <= 'F')) ||
2305 ((*cur >= 'a') && (*cur <= 'f'))) {
2306 i++;
2307 cur++;
2308 }
2309
2310 if (*cur != 0)
2311 goto return1;
2312 if ((i % 2) != 0)
2313 goto return1;
2314
2315 if (val != NULL) {
2316
2317 v = xmlSchemaNewValue(XML_SCHEMAS_HEXBINARY);
2318 if (v == NULL)
2319 goto error;
2320
2321 cur = xmlStrdup(value);
2322 if (cur == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002323 xmlSchemaTypeErrMemory(node, "allocating hexbin data");
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002324 xmlFree(v);
2325 goto return1;
2326 }
2327
2328 total = i / 2; /* number of octets */
2329
2330 base = (xmlChar *) cur;
2331 while (i-- > 0) {
2332 if (*base >= 'a')
2333 *base = *base - ('a' - 'A');
2334 base++;
2335 }
2336
2337 v->value.hex.str = (xmlChar *) cur;
2338 v->value.hex.total = total;
2339 *val = v;
2340 }
2341 goto return0;
2342 }
2343 case XML_SCHEMAS_BASE64BINARY:{
2344 /* ISSUE:
2345 *
2346 * Ignore all stray characters? (yes, currently)
2347 * Worry about long lines? (no, currently)
2348 *
2349 * rfc2045.txt:
2350 *
2351 * "The encoded output stream must be represented in lines of
2352 * no more than 76 characters each. All line breaks or other
2353 * characters not found in Table 1 must be ignored by decoding
2354 * software. In base64 data, characters other than those in
2355 * Table 1, line breaks, and other white space probably
2356 * indicate a transmission error, about which a warning
2357 * message or even a message rejection might be appropriate
2358 * under some circumstances." */
2359 const xmlChar *cur = value;
2360 xmlChar *base;
2361 int total, i = 0, pad = 0;
2362
2363 if (cur == NULL)
2364 goto return1;
2365
2366 for (; *cur; ++cur) {
2367 int decc;
2368
2369 decc = _xmlSchemaBase64Decode(*cur);
2370 if (decc < 0) ;
2371 else if (decc < 64)
2372 i++;
2373 else
2374 break;
2375 }
2376 for (; *cur; ++cur) {
2377 int decc;
2378
2379 decc = _xmlSchemaBase64Decode(*cur);
2380 if (decc < 0) ;
2381 else if (decc < 64)
2382 goto return1;
2383 if (decc == 64)
2384 pad++;
2385 }
2386
2387 /* rfc2045.txt: "Special processing is performed if fewer than
2388 * 24 bits are available at the end of the data being encoded.
2389 * A full encoding quantum is always completed at the end of a
2390 * body. When fewer than 24 input bits are available in an
2391 * input group, zero bits are added (on the right) to form an
2392 * integral number of 6-bit groups. Padding at the end of the
2393 * data is performed using the "=" character. Since all
2394 * base64 input is an integral number of octets, only the
2395 * following cases can arise: (1) the final quantum of
2396 * encoding input is an integral multiple of 24 bits; here,
2397 * the final unit of encoded output will be an integral
2398 * multiple ofindent: Standard input:701: Warning:old style
2399 * assignment ambiguity in "=*". Assuming "= *" 4 characters
2400 * with no "=" padding, (2) the final
2401 * quantum of encoding input is exactly 8 bits; here, the
2402 * final unit of encoded output will be two characters
2403 * followed by two "=" padding characters, or (3) the final
2404 * quantum of encoding input is exactly 16 bits; here, the
2405 * final unit of encoded output will be three characters
2406 * followed by one "=" padding character." */
2407
2408 total = 3 * (i / 4);
2409 if (pad == 0) {
2410 if (i % 4 != 0)
2411 goto return1;
2412 } else if (pad == 1) {
2413 int decc;
2414
2415 if (i % 4 != 3)
2416 goto return1;
2417 for (decc = _xmlSchemaBase64Decode(*cur);
2418 (decc < 0) || (decc > 63);
2419 decc = _xmlSchemaBase64Decode(*cur))
2420 --cur;
2421 /* 16bits in 24bits means 2 pad bits: nnnnnn nnmmmm mmmm00*/
2422 /* 00111100 -> 0x3c */
2423 if (decc & ~0x3c)
2424 goto return1;
2425 total += 2;
2426 } else if (pad == 2) {
2427 int decc;
2428
2429 if (i % 4 != 2)
2430 goto return1;
2431 for (decc = _xmlSchemaBase64Decode(*cur);
2432 (decc < 0) || (decc > 63);
2433 decc = _xmlSchemaBase64Decode(*cur))
2434 --cur;
2435 /* 8bits in 12bits means 4 pad bits: nnnnnn nn0000 */
2436 /* 00110000 -> 0x30 */
2437 if (decc & ~0x30)
2438 goto return1;
2439 total += 1;
2440 } else
2441 goto return1;
2442
2443 if (val != NULL) {
2444 v = xmlSchemaNewValue(XML_SCHEMAS_BASE64BINARY);
2445 if (v == NULL)
2446 goto error;
2447 base =
2448 (xmlChar *) xmlMallocAtomic((i + pad + 1) *
2449 sizeof(xmlChar));
2450 if (base == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002451 xmlSchemaTypeErrMemory(node, "allocating base64 data");
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002452 xmlFree(v);
2453 goto return1;
2454 }
2455 v->value.base64.str = base;
2456 for (cur = value; *cur; ++cur)
2457 if (_xmlSchemaBase64Decode(*cur) >= 0) {
2458 *base = *cur;
2459 ++base;
2460 }
2461 *base = 0;
2462 v->value.base64.total = total;
2463 *val = v;
2464 }
2465 goto return0;
2466 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002467 case XML_SCHEMAS_INTEGER:
2468 case XML_SCHEMAS_PINTEGER:
2469 case XML_SCHEMAS_NPINTEGER:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002470 case XML_SCHEMAS_NINTEGER:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002471 case XML_SCHEMAS_NNINTEGER:{
2472 const xmlChar *cur = value;
2473 unsigned long lo, mi, hi;
2474 int sign = 0;
2475
2476 if (cur == NULL)
2477 goto return1;
2478 if (*cur == '-') {
2479 sign = 1;
2480 cur++;
2481 } else if (*cur == '+')
2482 cur++;
2483 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2484 if (ret == 0)
2485 goto return1;
2486 if (*cur != 0)
2487 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002488 if (type->builtInType == XML_SCHEMAS_NPINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002489 if ((sign == 0) &&
2490 ((hi != 0) || (mi != 0) || (lo != 0)))
2491 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002492 } else if (type->builtInType == XML_SCHEMAS_PINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002493 if (sign == 1)
2494 goto return1;
2495 if ((hi == 0) && (mi == 0) && (lo == 0))
2496 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002497 } else if (type->builtInType == XML_SCHEMAS_NINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002498 if (sign == 0)
2499 goto return1;
2500 if ((hi == 0) && (mi == 0) && (lo == 0))
2501 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002502 } else if (type->builtInType == XML_SCHEMAS_NNINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002503 if ((sign == 1) &&
2504 ((hi != 0) || (mi != 0) || (lo != 0)))
2505 goto return1;
2506 }
2507 /*
2508 * We can store a value only if no overflow occured
2509 */
2510 if ((ret > 0) && (val != NULL)) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00002511 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002512 if (v != NULL) {
2513 v->value.decimal.lo = lo;
2514 v->value.decimal.mi = lo;
2515 v->value.decimal.hi = lo;
2516 v->value.decimal.sign = sign;
2517 v->value.decimal.frac = 0;
2518 v->value.decimal.total = cur - value;
2519 *val = v;
2520 }
2521 }
2522 goto return0;
2523 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002524 case XML_SCHEMAS_LONG:
2525 case XML_SCHEMAS_BYTE:
2526 case XML_SCHEMAS_SHORT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002527 case XML_SCHEMAS_INT:{
2528 const xmlChar *cur = value;
2529 unsigned long lo, mi, hi;
2530 int total = 0;
2531 int sign = 0;
2532
2533 if (cur == NULL)
2534 goto return1;
2535 if (*cur == '-') {
2536 sign = 1;
2537 cur++;
2538 } else if (*cur == '+')
2539 cur++;
2540 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2541 if (ret <= 0)
2542 goto return1;
2543 if (*cur != 0)
2544 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002545 if (type->builtInType == XML_SCHEMAS_LONG) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002546 if (hi >= 922) {
2547 if (hi > 922)
2548 goto return1;
2549 if (mi >= 33720368) {
2550 if (mi > 33720368)
2551 goto return1;
2552 if ((sign == 0) && (lo > 54775807))
2553 goto return1;
2554 if ((sign == 1) && (lo > 54775808))
2555 goto return1;
2556 }
2557 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002558 } else if (type->builtInType == XML_SCHEMAS_INT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002559 if (hi != 0)
2560 goto return1;
2561 if (mi >= 21) {
2562 if (mi > 21)
2563 goto return1;
2564 if ((sign == 0) && (lo > 47483647))
2565 goto return1;
2566 if ((sign == 1) && (lo > 47483648))
2567 goto return1;
2568 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002569 } else if (type->builtInType == XML_SCHEMAS_SHORT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002570 if ((mi != 0) || (hi != 0))
2571 goto return1;
2572 if ((sign == 1) && (lo > 32768))
2573 goto return1;
2574 if ((sign == 0) && (lo > 32767))
2575 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002576 } else if (type->builtInType == XML_SCHEMAS_BYTE) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002577 if ((mi != 0) || (hi != 0))
2578 goto return1;
2579 if ((sign == 1) && (lo > 128))
2580 goto return1;
2581 if ((sign == 0) && (lo > 127))
2582 goto return1;
2583 }
2584 if (val != NULL) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00002585 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002586 if (v != NULL) {
2587 v->value.decimal.lo = lo;
2588 v->value.decimal.mi = lo;
2589 v->value.decimal.hi = lo;
2590 v->value.decimal.sign = sign;
2591 v->value.decimal.frac = 0;
2592 v->value.decimal.total = total;
2593 *val = v;
2594 }
2595 }
2596 goto return0;
2597 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002598 case XML_SCHEMAS_UINT:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002599 case XML_SCHEMAS_ULONG:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002600 case XML_SCHEMAS_USHORT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002601 case XML_SCHEMAS_UBYTE:{
2602 const xmlChar *cur = value;
2603 unsigned long lo, mi, hi;
2604 int total = 0;
2605
2606 if (cur == NULL)
2607 goto return1;
2608 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2609 if (ret <= 0)
2610 goto return1;
2611 if (*cur != 0)
2612 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002613 if (type->builtInType == XML_SCHEMAS_ULONG) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002614 if (hi >= 1844) {
2615 if (hi > 1844)
2616 goto return1;
2617 if (mi >= 67440737) {
2618 if (mi > 67440737)
2619 goto return1;
2620 if (lo > 9551615)
2621 goto return1;
2622 }
2623 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002624 } else if (type->builtInType == XML_SCHEMAS_UINT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002625 if (hi != 0)
2626 goto return1;
2627 if (mi >= 42) {
2628 if (mi > 42)
2629 goto return1;
2630 if (lo > 94967295)
2631 goto return1;
2632 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002633 } else if (type->builtInType == XML_SCHEMAS_USHORT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002634 if ((mi != 0) || (hi != 0))
2635 goto return1;
2636 if (lo > 65535)
2637 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002638 } else if (type->builtInType == XML_SCHEMAS_UBYTE) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002639 if ((mi != 0) || (hi != 0))
2640 goto return1;
2641 if (lo > 255)
2642 goto return1;
2643 }
2644 if (val != NULL) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00002645 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002646 if (v != NULL) {
2647 v->value.decimal.lo = lo;
2648 v->value.decimal.mi = mi;
2649 v->value.decimal.hi = hi;
2650 v->value.decimal.sign = 0;
2651 v->value.decimal.frac = 0;
2652 v->value.decimal.total = total;
2653 *val = v;
2654 }
2655 }
2656 goto return0;
2657 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002658 }
2659
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002660 done:
2661 if (norm != NULL)
2662 xmlFree(norm);
2663 return (ret);
2664 return3:
2665 if (norm != NULL)
2666 xmlFree(norm);
2667 return (3);
2668 return1:
2669 if (norm != NULL)
2670 xmlFree(norm);
2671 return (1);
2672 return0:
2673 if (norm != NULL)
2674 xmlFree(norm);
2675 return (0);
2676 error:
2677 if (norm != NULL)
2678 xmlFree(norm);
2679 return (-1);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002680}
2681
2682/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002683 * xmlSchemaValPredefTypeNode:
Daniel Veillard4255d502002-04-16 15:50:10 +00002684 * @type: the predefined type
2685 * @value: the value to check
2686 * @val: the return computed value
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002687 * @node: the node containing the value
Daniel Veillard4255d502002-04-16 15:50:10 +00002688 *
2689 * Check that a value conforms to the lexical space of the predefined type.
2690 * if true a value is computed and returned in @val.
2691 *
2692 * Returns 0 if this validates, a positive error code number otherwise
2693 * and -1 in case of internal or API error.
2694 */
2695int
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002696xmlSchemaValPredefTypeNode(xmlSchemaTypePtr type, const xmlChar *value,
2697 xmlSchemaValPtr *val, xmlNodePtr node) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002698 return(xmlSchemaValAtomicType(type, value, val, node, 0));
Daniel Veillard4255d502002-04-16 15:50:10 +00002699}
2700
2701/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002702 * xmlSchemaValidatePredefinedType:
2703 * @type: the predefined type
2704 * @value: the value to check
2705 * @val: the return computed value
2706 *
2707 * Check that a value conforms to the lexical space of the predefined type.
2708 * if true a value is computed and returned in @val.
2709 *
2710 * Returns 0 if this validates, a positive error code number otherwise
2711 * and -1 in case of internal or API error.
2712 */
2713int
2714xmlSchemaValidatePredefinedType(xmlSchemaTypePtr type, const xmlChar *value,
2715 xmlSchemaValPtr *val) {
2716 return(xmlSchemaValPredefTypeNode(type, value, val, NULL));
2717}
2718
2719/**
Daniel Veillard4255d502002-04-16 15:50:10 +00002720 * xmlSchemaCompareDecimals:
2721 * @x: a first decimal value
2722 * @y: a second decimal value
2723 *
2724 * Compare 2 decimals
2725 *
2726 * Returns -1 if x < y, 0 if x == y, 1 if x > y and -2 in case of error
2727 */
2728static int
2729xmlSchemaCompareDecimals(xmlSchemaValPtr x, xmlSchemaValPtr y)
2730{
2731 xmlSchemaValPtr swp;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002732 int order = 1, p;
Daniel Veillard4255d502002-04-16 15:50:10 +00002733 unsigned long tmp;
2734
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002735 if ((x->value.decimal.sign) &&
2736 ((x->value.decimal.lo != 0) ||
2737 (x->value.decimal.mi != 0) ||
2738 (x->value.decimal.hi != 0))) {
2739 if ((y->value.decimal.sign) &&
2740 ((y->value.decimal.lo != 0) ||
2741 (y->value.decimal.mi != 0) ||
2742 (y->value.decimal.hi != 0)))
Daniel Veillard80b19092003-03-28 13:29:53 +00002743 order = -1;
2744 else
2745 return (-1);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002746 } else if ((y->value.decimal.sign) &&
2747 ((y->value.decimal.lo != 0) ||
2748 (y->value.decimal.mi != 0) ||
2749 (y->value.decimal.hi != 0))) {
Daniel Veillard4255d502002-04-16 15:50:10 +00002750 return (1);
Daniel Veillard80b19092003-03-28 13:29:53 +00002751 }
Daniel Veillard4255d502002-04-16 15:50:10 +00002752 if (x->value.decimal.frac == y->value.decimal.frac) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002753 if (x->value.decimal.hi < y->value.decimal.hi)
2754 return (-order);
Daniel Veillard01fa6152004-06-29 17:04:39 +00002755 if (x->value.decimal.hi > y->value.decimal.hi)
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002756 return (order);
2757 if (x->value.decimal.mi < y->value.decimal.mi)
2758 return (-order);
Daniel Veillard01fa6152004-06-29 17:04:39 +00002759 if (x->value.decimal.mi > y->value.decimal.mi)
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002760 return (order);
2761 if (x->value.decimal.lo < y->value.decimal.lo)
Daniel Veillard80b19092003-03-28 13:29:53 +00002762 return (-order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002763 if (x->value.decimal.lo > y->value.decimal.lo)
Daniel Veillard80b19092003-03-28 13:29:53 +00002764 return(order);
2765 return(0);
Daniel Veillard4255d502002-04-16 15:50:10 +00002766 }
2767 if (y->value.decimal.frac > x->value.decimal.frac) {
2768 swp = y;
2769 y = x;
2770 x = swp;
2771 order = -order;
2772 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002773 p = powten[x->value.decimal.frac - y->value.decimal.frac];
2774 tmp = x->value.decimal.lo / p;
2775 if (tmp > y->value.decimal.lo)
Daniel Veillard4255d502002-04-16 15:50:10 +00002776 return (order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002777 if (tmp < y->value.decimal.lo)
Daniel Veillard4255d502002-04-16 15:50:10 +00002778 return (-order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002779 tmp = y->value.decimal.lo * p;
2780 if (x->value.decimal.lo < tmp)
Daniel Veillard4255d502002-04-16 15:50:10 +00002781 return (-order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002782 if (x->value.decimal.lo == tmp)
Daniel Veillard4255d502002-04-16 15:50:10 +00002783 return (0);
2784 return (order);
2785}
2786
2787/**
Daniel Veillard070803b2002-05-03 07:29:38 +00002788 * xmlSchemaCompareDurations:
2789 * @x: a first duration value
2790 * @y: a second duration value
2791 *
2792 * Compare 2 durations
2793 *
2794 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
2795 * case of error
2796 */
2797static int
2798xmlSchemaCompareDurations(xmlSchemaValPtr x, xmlSchemaValPtr y)
2799{
2800 long carry, mon, day;
2801 double sec;
Daniel Veillard80b19092003-03-28 13:29:53 +00002802 int invert = 1;
2803 long xmon, xday, myear, minday, maxday;
Daniel Veillard070803b2002-05-03 07:29:38 +00002804 static const long dayRange [2][12] = {
2805 { 0, 28, 59, 89, 120, 150, 181, 212, 242, 273, 303, 334, },
2806 { 0, 31, 62, 92, 123, 153, 184, 215, 245, 276, 306, 337} };
2807
2808 if ((x == NULL) || (y == NULL))
Daniel Veillard5a872412002-05-22 06:40:27 +00002809 return -2;
Daniel Veillard070803b2002-05-03 07:29:38 +00002810
2811 /* months */
2812 mon = x->value.dur.mon - y->value.dur.mon;
2813
2814 /* seconds */
2815 sec = x->value.dur.sec - y->value.dur.sec;
2816 carry = (long)sec / SECS_PER_DAY;
2817 sec -= (double)(carry * SECS_PER_DAY);
2818
2819 /* days */
2820 day = x->value.dur.day - y->value.dur.day + carry;
2821
2822 /* easy test */
2823 if (mon == 0) {
2824 if (day == 0)
2825 if (sec == 0.0)
2826 return 0;
2827 else if (sec < 0.0)
2828 return -1;
2829 else
2830 return 1;
2831 else if (day < 0)
2832 return -1;
2833 else
2834 return 1;
2835 }
2836
2837 if (mon > 0) {
2838 if ((day >= 0) && (sec >= 0.0))
2839 return 1;
2840 else {
2841 xmon = mon;
2842 xday = -day;
2843 }
2844 } else if ((day <= 0) && (sec <= 0.0)) {
2845 return -1;
2846 } else {
Daniel Veillard80b19092003-03-28 13:29:53 +00002847 invert = -1;
Daniel Veillard070803b2002-05-03 07:29:38 +00002848 xmon = -mon;
2849 xday = day;
2850 }
2851
2852 myear = xmon / 12;
Daniel Veillard80b19092003-03-28 13:29:53 +00002853 if (myear == 0) {
2854 minday = 0;
2855 maxday = 0;
2856 } else {
2857 maxday = 366 * ((myear + 3) / 4) +
2858 365 * ((myear - 1) % 4);
2859 minday = maxday - 1;
2860 }
2861
Daniel Veillard070803b2002-05-03 07:29:38 +00002862 xmon = xmon % 12;
2863 minday += dayRange[0][xmon];
2864 maxday += dayRange[1][xmon];
2865
Daniel Veillard80b19092003-03-28 13:29:53 +00002866 if ((maxday == minday) && (maxday == xday))
2867 return(0); /* can this really happen ? */
Daniel Veillard070803b2002-05-03 07:29:38 +00002868 if (maxday < xday)
Daniel Veillard80b19092003-03-28 13:29:53 +00002869 return(-invert);
2870 if (minday > xday)
2871 return(invert);
Daniel Veillard070803b2002-05-03 07:29:38 +00002872
2873 /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00002874 return 2;
2875}
2876
2877/*
2878 * macros for adding date/times and durations
2879 */
2880#define FQUOTIENT(a,b) (floor(((double)a/(double)b)))
2881#define MODULO(a,b) (a - FQUOTIENT(a,b) * b)
2882#define FQUOTIENT_RANGE(a,low,high) (FQUOTIENT((a-low),(high-low)))
2883#define MODULO_RANGE(a,low,high) ((MODULO((a-low),(high-low)))+low)
2884
2885/**
Daniel Veillard669adfc2004-05-29 20:12:46 +00002886 * xmlSchemaDupVal:
2887 * @v: the #xmlSchemaValPtr value to duplicate
2888 *
2889 * Makes a copy of @v. The calling program is responsible for freeing
2890 * the returned value.
2891 *
2892 * returns a pointer to a duplicated #xmlSchemaValPtr or NULL if error.
2893 */
2894static xmlSchemaValPtr
2895xmlSchemaDupVal (xmlSchemaValPtr v)
2896{
2897 xmlSchemaValPtr ret = xmlSchemaNewValue(v->type);
2898 if (ret == NULL)
2899 return NULL;
2900
2901 memcpy(ret, v, sizeof(xmlSchemaVal));
2902 return ret;
2903}
2904
2905/**
Daniel Veillard5a872412002-05-22 06:40:27 +00002906 * _xmlSchemaDateAdd:
2907 * @dt: an #xmlSchemaValPtr
2908 * @dur: an #xmlSchemaValPtr of type #XS_DURATION
2909 *
2910 * Compute a new date/time from @dt and @dur. This function assumes @dt
2911 * is either #XML_SCHEMAS_DATETIME, #XML_SCHEMAS_DATE, #XML_SCHEMAS_GYEARMONTH,
Daniel Veillard669adfc2004-05-29 20:12:46 +00002912 * or #XML_SCHEMAS_GYEAR. The returned #xmlSchemaVal is the same type as
2913 * @dt. The calling program is responsible for freeing the returned value.
Daniel Veillard5a872412002-05-22 06:40:27 +00002914 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00002915 * Returns a pointer to a new #xmlSchemaVal or NULL if error.
Daniel Veillard5a872412002-05-22 06:40:27 +00002916 */
2917static xmlSchemaValPtr
2918_xmlSchemaDateAdd (xmlSchemaValPtr dt, xmlSchemaValPtr dur)
2919{
Daniel Veillard669adfc2004-05-29 20:12:46 +00002920 xmlSchemaValPtr ret, tmp;
Daniel Veillard5a872412002-05-22 06:40:27 +00002921 long carry, tempdays, temp;
2922 xmlSchemaValDatePtr r, d;
2923 xmlSchemaValDurationPtr u;
2924
2925 if ((dt == NULL) || (dur == NULL))
2926 return NULL;
2927
2928 ret = xmlSchemaNewValue(dt->type);
2929 if (ret == NULL)
2930 return NULL;
2931
Daniel Veillard669adfc2004-05-29 20:12:46 +00002932 /* make a copy so we don't alter the original value */
2933 tmp = xmlSchemaDupVal(dt);
2934 if (tmp == NULL) {
2935 xmlSchemaFreeValue(ret);
2936 return NULL;
2937 }
2938
Daniel Veillard5a872412002-05-22 06:40:27 +00002939 r = &(ret->value.date);
Daniel Veillard669adfc2004-05-29 20:12:46 +00002940 d = &(tmp->value.date);
Daniel Veillard5a872412002-05-22 06:40:27 +00002941 u = &(dur->value.dur);
2942
2943 /* normalization */
2944 if (d->mon == 0)
2945 d->mon = 1;
2946
2947 /* normalize for time zone offset */
2948 u->sec -= (d->tzo * 60);
2949 d->tzo = 0;
2950
2951 /* normalization */
2952 if (d->day == 0)
2953 d->day = 1;
2954
2955 /* month */
2956 carry = d->mon + u->mon;
Daniel Veillardebe25d42004-03-25 09:35:49 +00002957 r->mon = (unsigned int) MODULO_RANGE(carry, 1, 13);
2958 carry = (long) FQUOTIENT_RANGE(carry, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00002959
2960 /* year (may be modified later) */
2961 r->year = d->year + carry;
2962 if (r->year == 0) {
2963 if (d->year > 0)
2964 r->year--;
2965 else
2966 r->year++;
2967 }
2968
2969 /* time zone */
2970 r->tzo = d->tzo;
2971 r->tz_flag = d->tz_flag;
2972
2973 /* seconds */
2974 r->sec = d->sec + u->sec;
Daniel Veillardebe25d42004-03-25 09:35:49 +00002975 carry = (long) FQUOTIENT((long)r->sec, 60);
Daniel Veillard5a872412002-05-22 06:40:27 +00002976 if (r->sec != 0.0) {
2977 r->sec = MODULO(r->sec, 60.0);
2978 }
2979
2980 /* minute */
2981 carry += d->min;
Daniel Veillardebe25d42004-03-25 09:35:49 +00002982 r->min = (unsigned int) MODULO(carry, 60);
2983 carry = (long) FQUOTIENT(carry, 60);
Daniel Veillard5a872412002-05-22 06:40:27 +00002984
2985 /* hours */
2986 carry += d->hour;
Daniel Veillardebe25d42004-03-25 09:35:49 +00002987 r->hour = (unsigned int) MODULO(carry, 24);
2988 carry = (long)FQUOTIENT(carry, 24);
Daniel Veillard5a872412002-05-22 06:40:27 +00002989
2990 /*
2991 * days
2992 * Note we use tempdays because the temporary values may need more
2993 * than 5 bits
2994 */
2995 if ((VALID_YEAR(r->year)) && (VALID_MONTH(r->mon)) &&
2996 (d->day > MAX_DAYINMONTH(r->year, r->mon)))
2997 tempdays = MAX_DAYINMONTH(r->year, r->mon);
2998 else if (d->day < 1)
2999 tempdays = 1;
3000 else
3001 tempdays = d->day;
3002
3003 tempdays += u->day + carry;
3004
3005 while (1) {
3006 if (tempdays < 1) {
Daniel Veillardebe25d42004-03-25 09:35:49 +00003007 long tmon = (long) MODULO_RANGE(r->mon-1, 1, 13);
3008 long tyr = r->year + (long)FQUOTIENT_RANGE(r->mon-1, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00003009 if (tyr == 0)
3010 tyr--;
3011 tempdays += MAX_DAYINMONTH(tyr, tmon);
3012 carry = -1;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003013 } else if (tempdays > (long) MAX_DAYINMONTH(r->year, r->mon)) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003014 tempdays = tempdays - MAX_DAYINMONTH(r->year, r->mon);
3015 carry = 1;
3016 } else
3017 break;
3018
3019 temp = r->mon + carry;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003020 r->mon = (unsigned int) MODULO_RANGE(temp, 1, 13);
3021 r->year = r->year + (unsigned int) FQUOTIENT_RANGE(temp, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00003022 if (r->year == 0) {
3023 if (temp < 1)
3024 r->year--;
3025 else
3026 r->year++;
3027 }
3028 }
3029
3030 r->day = tempdays;
3031
3032 /*
3033 * adjust the date/time type to the date values
3034 */
3035 if (ret->type != XML_SCHEMAS_DATETIME) {
3036 if ((r->hour) || (r->min) || (r->sec))
3037 ret->type = XML_SCHEMAS_DATETIME;
3038 else if (ret->type != XML_SCHEMAS_DATE) {
3039 if ((r->mon != 1) && (r->day != 1))
3040 ret->type = XML_SCHEMAS_DATE;
3041 else if ((ret->type != XML_SCHEMAS_GYEARMONTH) && (r->mon != 1))
3042 ret->type = XML_SCHEMAS_GYEARMONTH;
3043 }
3044 }
3045
Daniel Veillard669adfc2004-05-29 20:12:46 +00003046 xmlSchemaFreeValue(tmp);
Daniel Veillard5a872412002-05-22 06:40:27 +00003047
Daniel Veillard5a872412002-05-22 06:40:27 +00003048 return ret;
3049}
3050
3051/**
3052 * xmlSchemaDateNormalize:
Daniel Veillard669adfc2004-05-29 20:12:46 +00003053 * @dt: an #xmlSchemaValPtr of a date/time type value.
3054 * @offset: number of seconds to adjust @dt by.
Daniel Veillard5a872412002-05-22 06:40:27 +00003055 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00003056 * Normalize @dt to GMT time. The @offset parameter is subtracted from
3057 * the return value is a time-zone offset is present on @dt.
Daniel Veillard5a872412002-05-22 06:40:27 +00003058 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00003059 * Returns a normalized copy of @dt or NULL if error.
Daniel Veillard5a872412002-05-22 06:40:27 +00003060 */
3061static xmlSchemaValPtr
3062xmlSchemaDateNormalize (xmlSchemaValPtr dt, double offset)
3063{
3064 xmlSchemaValPtr dur, ret;
3065
3066 if (dt == NULL)
3067 return NULL;
3068
3069 if (((dt->type != XML_SCHEMAS_TIME) &&
3070 (dt->type != XML_SCHEMAS_DATETIME)) || (dt->value.date.tzo == 0))
3071 return xmlSchemaDupVal(dt);
3072
3073 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
3074 if (dur == NULL)
3075 return NULL;
3076
3077 dur->value.date.sec -= offset;
3078
3079 ret = _xmlSchemaDateAdd(dt, dur);
3080 if (ret == NULL)
3081 return NULL;
3082
3083 xmlSchemaFreeValue(dur);
3084
3085 /* ret->value.date.tzo = 0; */
3086 return ret;
3087}
3088
3089/**
3090 * _xmlSchemaDateCastYMToDays:
3091 * @dt: an #xmlSchemaValPtr
3092 *
3093 * Convert mon and year of @dt to total number of days. Take the
3094 * number of years since (or before) 1 AD and add the number of leap
3095 * years. This is a function because negative
3096 * years must be handled a little differently and there is no zero year.
3097 *
3098 * Returns number of days.
3099 */
3100static long
3101_xmlSchemaDateCastYMToDays (const xmlSchemaValPtr dt)
3102{
3103 long ret;
3104
3105 if (dt->value.date.year < 0)
3106 ret = (dt->value.date.year * 365) +
3107 (((dt->value.date.year+1)/4)-((dt->value.date.year+1)/100)+
3108 ((dt->value.date.year+1)/400)) +
3109 DAY_IN_YEAR(0, dt->value.date.mon, dt->value.date.year);
3110 else
3111 ret = ((dt->value.date.year-1) * 365) +
3112 (((dt->value.date.year-1)/4)-((dt->value.date.year-1)/100)+
3113 ((dt->value.date.year-1)/400)) +
3114 DAY_IN_YEAR(0, dt->value.date.mon, dt->value.date.year);
3115
3116 return ret;
3117}
3118
3119/**
3120 * TIME_TO_NUMBER:
3121 * @dt: an #xmlSchemaValPtr
3122 *
3123 * Calculates the number of seconds in the time portion of @dt.
3124 *
3125 * Returns seconds.
3126 */
3127#define TIME_TO_NUMBER(dt) \
3128 ((double)((dt->value.date.hour * SECS_PER_HOUR) + \
Daniel Veillardb3721c22003-03-31 11:22:25 +00003129 (dt->value.date.min * SECS_PER_MIN) + \
3130 (dt->value.date.tzo * SECS_PER_MIN)) + \
3131 dt->value.date.sec)
Daniel Veillard5a872412002-05-22 06:40:27 +00003132
3133/**
3134 * xmlSchemaCompareDates:
3135 * @x: a first date/time value
3136 * @y: a second date/time value
3137 *
3138 * Compare 2 date/times
3139 *
3140 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3141 * case of error
3142 */
3143static int
3144xmlSchemaCompareDates (xmlSchemaValPtr x, xmlSchemaValPtr y)
3145{
3146 unsigned char xmask, ymask, xor_mask, and_mask;
3147 xmlSchemaValPtr p1, p2, q1, q2;
3148 long p1d, p2d, q1d, q2d;
3149
3150 if ((x == NULL) || (y == NULL))
3151 return -2;
3152
3153 if (x->value.date.tz_flag) {
3154
3155 if (!y->value.date.tz_flag) {
3156 p1 = xmlSchemaDateNormalize(x, 0);
3157 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3158 /* normalize y + 14:00 */
3159 q1 = xmlSchemaDateNormalize(y, (14 * SECS_PER_HOUR));
3160
3161 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003162 if (p1d < q1d) {
3163 xmlSchemaFreeValue(p1);
3164 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003165 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003166 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003167 double sec;
3168
3169 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00003170 if (sec < 0.0) {
3171 xmlSchemaFreeValue(p1);
3172 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003173 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003174 } else {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003175 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003176 /* normalize y - 14:00 */
3177 q2 = xmlSchemaDateNormalize(y, -(14 * SECS_PER_HOUR));
3178 q2d = _xmlSchemaDateCastYMToDays(q2) + q2->value.date.day;
3179 if (p1d > q2d)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003180 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003181 else if (p1d == q2d) {
3182 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q2);
3183 if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003184 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003185 else
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003186 ret = 2; /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00003187 }
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003188 xmlSchemaFreeValue(p1);
3189 xmlSchemaFreeValue(q1);
3190 xmlSchemaFreeValue(q2);
3191 if (ret != 0)
3192 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003193 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00003194 } else {
3195 xmlSchemaFreeValue(p1);
3196 xmlSchemaFreeValue(q1);
3197 }
Daniel Veillard5a872412002-05-22 06:40:27 +00003198 }
3199 } else if (y->value.date.tz_flag) {
3200 q1 = xmlSchemaDateNormalize(y, 0);
3201 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
3202
3203 /* normalize x - 14:00 */
3204 p1 = xmlSchemaDateNormalize(x, -(14 * SECS_PER_HOUR));
3205 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3206
Daniel Veillardfdc91562002-07-01 21:52:03 +00003207 if (p1d < q1d) {
3208 xmlSchemaFreeValue(p1);
3209 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003210 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003211 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003212 double sec;
3213
3214 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00003215 if (sec < 0.0) {
3216 xmlSchemaFreeValue(p1);
3217 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003218 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003219 } else {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003220 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003221 /* normalize x + 14:00 */
3222 p2 = xmlSchemaDateNormalize(x, (14 * SECS_PER_HOUR));
3223 p2d = _xmlSchemaDateCastYMToDays(p2) + p2->value.date.day;
3224
Daniel Veillard6560a422003-03-27 21:25:38 +00003225 if (p2d > q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003226 ret = 1;
Daniel Veillard6560a422003-03-27 21:25:38 +00003227 } else if (p2d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003228 sec = TIME_TO_NUMBER(p2) - TIME_TO_NUMBER(q1);
3229 if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003230 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003231 else
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003232 ret = 2; /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00003233 }
Daniel Veillard6560a422003-03-27 21:25:38 +00003234 xmlSchemaFreeValue(p1);
3235 xmlSchemaFreeValue(q1);
3236 xmlSchemaFreeValue(p2);
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003237 if (ret != 0)
3238 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003239 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00003240 } else {
3241 xmlSchemaFreeValue(p1);
3242 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003243 }
3244 }
3245
3246 /*
3247 * if the same type then calculate the difference
3248 */
3249 if (x->type == y->type) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003250 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003251 q1 = xmlSchemaDateNormalize(y, 0);
3252 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
3253
3254 p1 = xmlSchemaDateNormalize(x, 0);
3255 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3256
Daniel Veillardfdc91562002-07-01 21:52:03 +00003257 if (p1d < q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003258 ret = -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003259 } else if (p1d > q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003260 ret = 1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003261 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00003262 double sec;
3263
3264 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
3265 if (sec < 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003266 ret = -1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003267 else if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003268 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003269
3270 }
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003271 xmlSchemaFreeValue(p1);
3272 xmlSchemaFreeValue(q1);
3273 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003274 }
3275
3276 switch (x->type) {
3277 case XML_SCHEMAS_DATETIME:
3278 xmask = 0xf;
3279 break;
3280 case XML_SCHEMAS_DATE:
3281 xmask = 0x7;
3282 break;
3283 case XML_SCHEMAS_GYEAR:
3284 xmask = 0x1;
3285 break;
3286 case XML_SCHEMAS_GMONTH:
3287 xmask = 0x2;
3288 break;
3289 case XML_SCHEMAS_GDAY:
3290 xmask = 0x3;
3291 break;
3292 case XML_SCHEMAS_GYEARMONTH:
3293 xmask = 0x3;
3294 break;
3295 case XML_SCHEMAS_GMONTHDAY:
3296 xmask = 0x6;
3297 break;
3298 case XML_SCHEMAS_TIME:
3299 xmask = 0x8;
3300 break;
3301 default:
3302 xmask = 0;
3303 break;
3304 }
3305
3306 switch (y->type) {
3307 case XML_SCHEMAS_DATETIME:
3308 ymask = 0xf;
3309 break;
3310 case XML_SCHEMAS_DATE:
3311 ymask = 0x7;
3312 break;
3313 case XML_SCHEMAS_GYEAR:
3314 ymask = 0x1;
3315 break;
3316 case XML_SCHEMAS_GMONTH:
3317 ymask = 0x2;
3318 break;
3319 case XML_SCHEMAS_GDAY:
3320 ymask = 0x3;
3321 break;
3322 case XML_SCHEMAS_GYEARMONTH:
3323 ymask = 0x3;
3324 break;
3325 case XML_SCHEMAS_GMONTHDAY:
3326 ymask = 0x6;
3327 break;
3328 case XML_SCHEMAS_TIME:
3329 ymask = 0x8;
3330 break;
3331 default:
3332 ymask = 0;
3333 break;
3334 }
3335
3336 xor_mask = xmask ^ ymask; /* mark type differences */
3337 and_mask = xmask & ymask; /* mark field specification */
3338
3339 /* year */
3340 if (xor_mask & 1)
3341 return 2; /* indeterminate */
3342 else if (and_mask & 1) {
3343 if (x->value.date.year < y->value.date.year)
3344 return -1;
3345 else if (x->value.date.year > y->value.date.year)
3346 return 1;
3347 }
3348
3349 /* month */
3350 if (xor_mask & 2)
3351 return 2; /* indeterminate */
3352 else if (and_mask & 2) {
3353 if (x->value.date.mon < y->value.date.mon)
3354 return -1;
3355 else if (x->value.date.mon > y->value.date.mon)
3356 return 1;
3357 }
3358
3359 /* day */
3360 if (xor_mask & 4)
3361 return 2; /* indeterminate */
3362 else if (and_mask & 4) {
3363 if (x->value.date.day < y->value.date.day)
3364 return -1;
3365 else if (x->value.date.day > y->value.date.day)
3366 return 1;
3367 }
3368
3369 /* time */
3370 if (xor_mask & 8)
3371 return 2; /* indeterminate */
3372 else if (and_mask & 8) {
3373 if (x->value.date.hour < y->value.date.hour)
3374 return -1;
3375 else if (x->value.date.hour > y->value.date.hour)
3376 return 1;
3377 else if (x->value.date.min < y->value.date.min)
3378 return -1;
3379 else if (x->value.date.min > y->value.date.min)
3380 return 1;
3381 else if (x->value.date.sec < y->value.date.sec)
3382 return -1;
3383 else if (x->value.date.sec > y->value.date.sec)
3384 return 1;
3385 }
3386
Daniel Veillard070803b2002-05-03 07:29:38 +00003387 return 0;
3388}
3389
3390/**
Daniel Veillardc4c21552003-03-29 10:53:38 +00003391 * xmlSchemaCompareNormStrings:
3392 * @x: a first string value
3393 * @y: a second string value
3394 *
3395 * Compare 2 string for their normalized values.
3396 *
3397 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
3398 * case of error
3399 */
3400static int
3401xmlSchemaCompareNormStrings(xmlSchemaValPtr x, xmlSchemaValPtr y) {
3402 const xmlChar *utf1;
3403 const xmlChar *utf2;
3404 int tmp;
3405
3406 if ((x == NULL) || (y == NULL))
3407 return(-2);
3408 utf1 = x->value.str;
3409 utf2 = y->value.str;
3410
William M. Brack76e95df2003-10-18 16:20:14 +00003411 while (IS_BLANK_CH(*utf1)) utf1++;
3412 while (IS_BLANK_CH(*utf2)) utf2++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003413 while ((*utf1 != 0) && (*utf2 != 0)) {
William M. Brack76e95df2003-10-18 16:20:14 +00003414 if (IS_BLANK_CH(*utf1)) {
3415 if (!IS_BLANK_CH(*utf2)) {
Daniel Veillardc4c21552003-03-29 10:53:38 +00003416 tmp = *utf1 - *utf2;
3417 return(tmp);
3418 }
William M. Brack76e95df2003-10-18 16:20:14 +00003419 while (IS_BLANK_CH(*utf1)) utf1++;
3420 while (IS_BLANK_CH(*utf2)) utf2++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003421 } else {
3422 tmp = *utf1++ - *utf2++;
3423 if (tmp < 0)
3424 return(-1);
3425 if (tmp > 0)
3426 return(1);
3427 }
3428 }
3429 if (*utf1 != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00003430 while (IS_BLANK_CH(*utf1)) utf1++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003431 if (*utf1 != 0)
3432 return(1);
3433 }
3434 if (*utf2 != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00003435 while (IS_BLANK_CH(*utf2)) utf2++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003436 if (*utf2 != 0)
3437 return(-1);
3438 }
3439 return(0);
3440}
3441
3442/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003443 * xmlSchemaCompareFloats:
3444 * @x: a first float or double value
3445 * @y: a second float or double value
3446 *
3447 * Compare 2 values
3448 *
3449 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3450 * case of error
3451 */
3452static int
3453xmlSchemaCompareFloats(xmlSchemaValPtr x, xmlSchemaValPtr y) {
3454 double d1, d2;
3455
3456 if ((x == NULL) || (y == NULL))
3457 return(-2);
3458
3459 /*
3460 * Cast everything to doubles.
3461 */
3462 if (x->type == XML_SCHEMAS_DOUBLE)
3463 d1 = x->value.d;
3464 else if (x->type == XML_SCHEMAS_FLOAT)
3465 d1 = x->value.f;
3466 else
3467 return(-2);
3468
3469 if (y->type == XML_SCHEMAS_DOUBLE)
3470 d2 = y->value.d;
3471 else if (y->type == XML_SCHEMAS_FLOAT)
3472 d2 = y->value.f;
3473 else
3474 return(-2);
3475
3476 /*
3477 * Check for special cases.
3478 */
3479 if (xmlXPathIsNaN(d1)) {
3480 if (xmlXPathIsNaN(d2))
3481 return(0);
3482 return(1);
3483 }
3484 if (xmlXPathIsNaN(d2))
3485 return(-1);
3486 if (d1 == xmlXPathPINF) {
3487 if (d2 == xmlXPathPINF)
3488 return(0);
3489 return(1);
3490 }
3491 if (d2 == xmlXPathPINF)
3492 return(-1);
3493 if (d1 == xmlXPathNINF) {
3494 if (d2 == xmlXPathNINF)
3495 return(0);
3496 return(-1);
3497 }
3498 if (d2 == xmlXPathNINF)
3499 return(1);
3500
3501 /*
3502 * basic tests, the last one we should have equality, but
3503 * portability is more important than speed and handling
3504 * NaN or Inf in a portable way is always a challenge, so ...
3505 */
3506 if (d1 < d2)
3507 return(-1);
3508 if (d1 > d2)
3509 return(1);
3510 if (d1 == d2)
3511 return(0);
3512 return(2);
3513}
3514
3515/**
Daniel Veillard4255d502002-04-16 15:50:10 +00003516 * xmlSchemaCompareValues:
3517 * @x: a first value
3518 * @y: a second value
3519 *
3520 * Compare 2 values
3521 *
Daniel Veillard5a872412002-05-22 06:40:27 +00003522 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3523 * case of error
Daniel Veillard4255d502002-04-16 15:50:10 +00003524 */
Daniel Veillard80b19092003-03-28 13:29:53 +00003525int
Daniel Veillard4255d502002-04-16 15:50:10 +00003526xmlSchemaCompareValues(xmlSchemaValPtr x, xmlSchemaValPtr y) {
3527 if ((x == NULL) || (y == NULL))
3528 return(-2);
3529
3530 switch (x->type) {
Daniel Veillard80b19092003-03-28 13:29:53 +00003531 case XML_SCHEMAS_UNKNOWN:
3532 return(-2);
3533 case XML_SCHEMAS_INTEGER:
3534 case XML_SCHEMAS_NPINTEGER:
3535 case XML_SCHEMAS_NINTEGER:
3536 case XML_SCHEMAS_NNINTEGER:
3537 case XML_SCHEMAS_PINTEGER:
3538 case XML_SCHEMAS_INT:
3539 case XML_SCHEMAS_UINT:
3540 case XML_SCHEMAS_LONG:
3541 case XML_SCHEMAS_ULONG:
3542 case XML_SCHEMAS_SHORT:
3543 case XML_SCHEMAS_USHORT:
3544 case XML_SCHEMAS_BYTE:
3545 case XML_SCHEMAS_UBYTE:
Daniel Veillard4255d502002-04-16 15:50:10 +00003546 case XML_SCHEMAS_DECIMAL:
Daniel Veillard80b19092003-03-28 13:29:53 +00003547 if (y->type == x->type)
3548 return(xmlSchemaCompareDecimals(x, y));
3549 if ((y->type == XML_SCHEMAS_DECIMAL) ||
3550 (y->type == XML_SCHEMAS_INTEGER) ||
3551 (y->type == XML_SCHEMAS_NPINTEGER) ||
3552 (y->type == XML_SCHEMAS_NINTEGER) ||
3553 (y->type == XML_SCHEMAS_NNINTEGER) ||
3554 (y->type == XML_SCHEMAS_PINTEGER) ||
3555 (y->type == XML_SCHEMAS_INT) ||
3556 (y->type == XML_SCHEMAS_UINT) ||
3557 (y->type == XML_SCHEMAS_LONG) ||
3558 (y->type == XML_SCHEMAS_ULONG) ||
3559 (y->type == XML_SCHEMAS_SHORT) ||
3560 (y->type == XML_SCHEMAS_USHORT) ||
3561 (y->type == XML_SCHEMAS_BYTE) ||
3562 (y->type == XML_SCHEMAS_UBYTE))
Daniel Veillard4255d502002-04-16 15:50:10 +00003563 return(xmlSchemaCompareDecimals(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00003564 return(-2);
Daniel Veillard070803b2002-05-03 07:29:38 +00003565 case XML_SCHEMAS_DURATION:
3566 if (y->type == XML_SCHEMAS_DURATION)
3567 return(xmlSchemaCompareDurations(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00003568 return(-2);
3569 case XML_SCHEMAS_TIME:
3570 case XML_SCHEMAS_GDAY:
3571 case XML_SCHEMAS_GMONTH:
3572 case XML_SCHEMAS_GMONTHDAY:
3573 case XML_SCHEMAS_GYEAR:
3574 case XML_SCHEMAS_GYEARMONTH:
3575 case XML_SCHEMAS_DATE:
3576 case XML_SCHEMAS_DATETIME:
3577 if ((y->type == XML_SCHEMAS_DATETIME) ||
3578 (y->type == XML_SCHEMAS_TIME) ||
3579 (y->type == XML_SCHEMAS_GDAY) ||
3580 (y->type == XML_SCHEMAS_GMONTH) ||
3581 (y->type == XML_SCHEMAS_GMONTHDAY) ||
3582 (y->type == XML_SCHEMAS_GYEAR) ||
3583 (y->type == XML_SCHEMAS_DATE) ||
3584 (y->type == XML_SCHEMAS_GYEARMONTH))
3585 return (xmlSchemaCompareDates(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00003586 return (-2);
Daniel Veillard80b19092003-03-28 13:29:53 +00003587 case XML_SCHEMAS_NORMSTRING:
Daniel Veillard80b19092003-03-28 13:29:53 +00003588 case XML_SCHEMAS_TOKEN:
3589 case XML_SCHEMAS_LANGUAGE:
3590 case XML_SCHEMAS_NMTOKEN:
Daniel Veillard80b19092003-03-28 13:29:53 +00003591 case XML_SCHEMAS_NAME:
Daniel Veillard80b19092003-03-28 13:29:53 +00003592 case XML_SCHEMAS_NCNAME:
3593 case XML_SCHEMAS_ID:
3594 case XML_SCHEMAS_IDREF:
Daniel Veillard80b19092003-03-28 13:29:53 +00003595 case XML_SCHEMAS_ENTITY:
Daniel Veillard80b19092003-03-28 13:29:53 +00003596 case XML_SCHEMAS_NOTATION:
3597 case XML_SCHEMAS_ANYURI:
Daniel Veillardc4c21552003-03-29 10:53:38 +00003598 if ((y->type == XML_SCHEMAS_NORMSTRING) ||
3599 (y->type == XML_SCHEMAS_TOKEN) ||
3600 (y->type == XML_SCHEMAS_LANGUAGE) ||
3601 (y->type == XML_SCHEMAS_NMTOKEN) ||
3602 (y->type == XML_SCHEMAS_NAME) ||
3603 (y->type == XML_SCHEMAS_QNAME) ||
3604 (y->type == XML_SCHEMAS_NCNAME) ||
3605 (y->type == XML_SCHEMAS_ID) ||
3606 (y->type == XML_SCHEMAS_IDREF) ||
3607 (y->type == XML_SCHEMAS_ENTITY) ||
3608 (y->type == XML_SCHEMAS_NOTATION) ||
3609 (y->type == XML_SCHEMAS_ANYURI))
3610 return (xmlSchemaCompareNormStrings(x, y));
3611 return (-2);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003612 case XML_SCHEMAS_QNAME:
3613 if (y->type == XML_SCHEMAS_QNAME) {
3614 if ((xmlStrEqual(x->value.qname.name, y->value.qname.name)) &&
3615 (xmlStrEqual(x->value.qname.uri, y->value.qname.uri)))
3616 return(0);
3617 return(2);
3618 }
3619 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00003620 case XML_SCHEMAS_FLOAT:
3621 case XML_SCHEMAS_DOUBLE:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003622 if ((y->type == XML_SCHEMAS_FLOAT) ||
3623 (y->type == XML_SCHEMAS_DOUBLE))
3624 return (xmlSchemaCompareFloats(x, y));
3625 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00003626 case XML_SCHEMAS_BOOLEAN:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003627 if (y->type == XML_SCHEMAS_BOOLEAN) {
3628 if (x->value.b == y->value.b)
3629 return(0);
3630 if (x->value.b == 0)
3631 return(-1);
3632 return(1);
3633 }
3634 return (-2);
Daniel Veillard560c2a42003-07-06 21:13:49 +00003635 case XML_SCHEMAS_HEXBINARY:
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00003636 if (y->type == XML_SCHEMAS_HEXBINARY) {
3637 if (x->value.hex.total == y->value.hex.total) {
3638 int ret = xmlStrcmp(x->value.hex.str, y->value.hex.str);
3639 if (ret > 0)
3640 return(1);
3641 else if (ret == 0)
3642 return(0);
3643 }
3644 else if (x->value.hex.total > y->value.hex.total)
3645 return(1);
3646
3647 return(-1);
3648 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00003649 return (-2);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003650 case XML_SCHEMAS_BASE64BINARY:
3651 if (y->type == XML_SCHEMAS_BASE64BINARY) {
3652 if (x->value.base64.total == y->value.base64.total) {
3653 int ret = xmlStrcmp(x->value.base64.str,
3654 y->value.base64.str);
3655 if (ret > 0)
3656 return(1);
3657 else if (ret == 0)
3658 return(0);
3659 }
3660 else if (x->value.base64.total > y->value.base64.total)
3661 return(1);
3662 else
3663 return(-1);
3664 }
3665 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00003666 case XML_SCHEMAS_STRING:
3667 case XML_SCHEMAS_IDREFS:
3668 case XML_SCHEMAS_ENTITIES:
3669 case XML_SCHEMAS_NMTOKENS:
3670 TODO
3671 break;
William M. Brack96d2eff2004-06-30 11:48:47 +00003672 case XML_SCHEMAS_ANYTYPE:
3673 case XML_SCHEMAS_ANYSIMPLETYPE:
3674 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00003675 }
Daniel Veillard5a872412002-05-22 06:40:27 +00003676 return -2;
Daniel Veillard4255d502002-04-16 15:50:10 +00003677}
3678
3679/**
Daniel Veillardc4c21552003-03-29 10:53:38 +00003680 * xmlSchemaNormLen:
3681 * @value: a string
3682 *
3683 * Computes the UTF8 length of the normalized value of the string
3684 *
3685 * Returns the length or -1 in case of error.
3686 */
3687static int
3688xmlSchemaNormLen(const xmlChar *value) {
3689 const xmlChar *utf;
3690 int ret = 0;
3691
3692 if (value == NULL)
3693 return(-1);
3694 utf = value;
William M. Brack76e95df2003-10-18 16:20:14 +00003695 while (IS_BLANK_CH(*utf)) utf++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003696 while (*utf != 0) {
3697 if (utf[0] & 0x80) {
3698 if ((utf[1] & 0xc0) != 0x80)
3699 return(-1);
3700 if ((utf[0] & 0xe0) == 0xe0) {
3701 if ((utf[2] & 0xc0) != 0x80)
3702 return(-1);
3703 if ((utf[0] & 0xf0) == 0xf0) {
3704 if ((utf[0] & 0xf8) != 0xf0 || (utf[3] & 0xc0) != 0x80)
3705 return(-1);
3706 utf += 4;
3707 } else {
3708 utf += 3;
3709 }
3710 } else {
3711 utf += 2;
3712 }
William M. Brack76e95df2003-10-18 16:20:14 +00003713 } else if (IS_BLANK_CH(*utf)) {
3714 while (IS_BLANK_CH(*utf)) utf++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003715 if (*utf == 0)
3716 break;
3717 } else {
3718 utf++;
3719 }
3720 ret++;
3721 }
3722 return(ret);
3723}
3724
3725/**
Daniel Veillard01fa6152004-06-29 17:04:39 +00003726 * xmlSchemaValidateListSimpleTypeFacet:
3727 * @facet: the facet to check
3728 * @value: the lexical repr of the value to validate
3729 * @actualLen: the number of list items
3730 * @expectedLen: the resulting expected number of list items
3731 *
3732 * Checks the value of a list simple type against a facet.
3733 *
3734 * Returns 0 if the value is valid, a positive error code
3735 * number otherwise and -1 in case of an internal error.
3736 */
3737int
3738xmlSchemaValidateListSimpleTypeFacet(xmlSchemaFacetPtr facet,
3739 const xmlChar *value,
3740 unsigned long actualLen,
3741 unsigned long *expectedLen)
3742{
3743 /*
3744 * TODO: Check if this will work with large numbers.
3745 * (compare value.decimal.mi and value.decimal.hi as well?).
3746 */
3747 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
3748 if (actualLen != facet->val->value.decimal.lo) {
3749 *expectedLen = facet->val->value.decimal.lo;
3750 return (XML_SCHEMAV_CVC_LENGTH_VALID);
3751 }
3752 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
3753 if (actualLen < facet->val->value.decimal.lo) {
3754 *expectedLen = facet->val->value.decimal.lo;
3755 return (XML_SCHEMAV_CVC_MINLENGTH_VALID);
3756 }
3757 } else if (facet->type == XML_SCHEMA_FACET_MAXLENGTH) {
3758 if (actualLen > facet->val->value.decimal.lo) {
3759 *expectedLen = facet->val->value.decimal.lo;
3760 return (XML_SCHEMAV_CVC_MAXLENGTH_VALID);
3761 }
3762 } else
3763 /*
3764 * NOTE: That we can pass NULL as xmlSchemaValPtr to
3765 * xmlSchemaValidateFacet, since the remaining facet types
3766 * are: XML_SCHEMA_FACET_PATTERN, XML_SCHEMA_FACET_ENUMERATION.
3767 */
3768 return(xmlSchemaValidateFacet(NULL, facet, value, NULL));
3769 return (0);
3770}
3771
3772/**
Daniel Veillard4255d502002-04-16 15:50:10 +00003773 * xmlSchemaValidateFacet:
Daniel Veillard01c13b52002-12-10 15:19:08 +00003774 * @base: the base type
Daniel Veillard4255d502002-04-16 15:50:10 +00003775 * @facet: the facet to check
3776 * @value: the lexical repr of the value to validate
3777 * @val: the precomputed value
3778 *
3779 * Check a value against a facet condition
3780 *
3781 * Returns 0 if the element is schemas valid, a positive error code
3782 * number otherwise and -1 in case of internal or API error.
3783 */
3784int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00003785xmlSchemaValidateFacet(xmlSchemaTypePtr base ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +00003786 xmlSchemaFacetPtr facet,
Daniel Veillard4255d502002-04-16 15:50:10 +00003787 const xmlChar *value, xmlSchemaValPtr val)
3788{
3789 int ret;
3790
3791 switch (facet->type) {
3792 case XML_SCHEMA_FACET_PATTERN:
3793 ret = xmlRegexpExec(facet->regexp, value);
3794 if (ret == 1)
3795 return(0);
3796 if (ret == 0) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00003797 return(XML_SCHEMAV_CVC_PATTERN_VALID);
Daniel Veillard4255d502002-04-16 15:50:10 +00003798 }
3799 return(ret);
3800 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
3801 ret = xmlSchemaCompareValues(val, facet->val);
3802 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003803 /* TODO error code */
Daniel Veillard4255d502002-04-16 15:50:10 +00003804 return(-1);
3805 }
3806 if (ret == -1)
3807 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00003808 /* error code */
Daniel Veillard01fa6152004-06-29 17:04:39 +00003809 return(XML_SCHEMAV_CVC_MAXEXCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00003810 case XML_SCHEMA_FACET_MAXINCLUSIVE:
3811 ret = xmlSchemaCompareValues(val, facet->val);
3812 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003813 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00003814 return(-1);
3815 }
3816 if ((ret == -1) || (ret == 0))
3817 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00003818 /* error code */
Daniel Veillard01fa6152004-06-29 17:04:39 +00003819 return(XML_SCHEMAV_CVC_MAXINCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00003820 case XML_SCHEMA_FACET_MINEXCLUSIVE:
3821 ret = xmlSchemaCompareValues(val, facet->val);
3822 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003823 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00003824 return(-1);
3825 }
3826 if (ret == 1)
3827 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00003828 /* error code */
Daniel Veillard01fa6152004-06-29 17:04:39 +00003829 return(XML_SCHEMAV_CVC_MINEXCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00003830 case XML_SCHEMA_FACET_MININCLUSIVE:
3831 ret = xmlSchemaCompareValues(val, facet->val);
3832 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003833 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00003834 return(-1);
3835 }
3836 if ((ret == 1) || (ret == 0))
3837 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00003838 /* error code */
Daniel Veillard01fa6152004-06-29 17:04:39 +00003839 return(XML_SCHEMAV_CVC_MININCLUSIVE_VALID);
Daniel Veillard8651f532002-04-17 09:06:27 +00003840 case XML_SCHEMA_FACET_WHITESPACE:
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003841 /* TODO whitespaces */
Daniel Veillard01fa6152004-06-29 17:04:39 +00003842 /*
3843 * NOTE: Whitespace should be handled to normalize
3844 * the value to be validated against a the facets;
3845 * not to normalize the value in-between.
3846 */
Daniel Veillard8651f532002-04-17 09:06:27 +00003847 return(0);
Daniel Veillard88c58912002-04-23 07:12:20 +00003848 case XML_SCHEMA_FACET_ENUMERATION:
3849 if ((facet->value != NULL) &&
3850 (xmlStrEqual(facet->value, value)))
3851 return(0);
Daniel Veillard01fa6152004-06-29 17:04:39 +00003852 return(XML_SCHEMAV_CVC_ENUMERATION_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003853 case XML_SCHEMA_FACET_LENGTH:
3854 case XML_SCHEMA_FACET_MAXLENGTH:
3855 case XML_SCHEMA_FACET_MINLENGTH: {
3856 unsigned int len = 0;
3857
3858 if ((facet->val == NULL) ||
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003859 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
3860 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003861 (facet->val->value.decimal.frac != 0)) {
3862 return(-1);
3863 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00003864 if ((val != NULL) && (val->type == XML_SCHEMAS_HEXBINARY))
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00003865 len = val->value.hex.total;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003866 else if ((val != NULL) && (val->type == XML_SCHEMAS_BASE64BINARY))
3867 len = val->value.base64.total;
3868 else {
Daniel Veillard01fa6152004-06-29 17:04:39 +00003869 switch (base->builtInType) {
Daniel Veillard560c2a42003-07-06 21:13:49 +00003870 case XML_SCHEMAS_IDREF:
3871 case XML_SCHEMAS_NORMSTRING:
3872 case XML_SCHEMAS_TOKEN:
3873 case XML_SCHEMAS_LANGUAGE:
3874 case XML_SCHEMAS_NMTOKEN:
3875 case XML_SCHEMAS_NAME:
3876 case XML_SCHEMAS_NCNAME:
3877 case XML_SCHEMAS_ID:
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00003878 len = xmlSchemaNormLen(value);
3879 break;
Daniel Veillard560c2a42003-07-06 21:13:49 +00003880 case XML_SCHEMAS_STRING:
Daniel Veillard01fa6152004-06-29 17:04:39 +00003881 /*
3882 * FIXME: What exactly to do with anyURI?
3883 */
3884 case XML_SCHEMAS_ANYURI:
William M. Brackfbf2c5e2004-02-03 17:55:56 +00003885 if (value != NULL)
3886 len = xmlUTF8Strlen(value);
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00003887 break;
Daniel Veillard560c2a42003-07-06 21:13:49 +00003888 default:
3889 TODO
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00003890 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003891 }
3892 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003893 if (len != facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00003894 return(XML_SCHEMAV_CVC_LENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003895 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003896 if (len < facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00003897 return(XML_SCHEMAV_CVC_MINLENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003898 } else {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003899 if (len > facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00003900 return(XML_SCHEMAV_CVC_MAXLENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003901 }
3902 break;
3903 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00003904 case XML_SCHEMA_FACET_TOTALDIGITS:
3905 case XML_SCHEMA_FACET_FRACTIONDIGITS:
3906
3907 if ((facet->val == NULL) ||
3908 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
3909 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
3910 (facet->val->value.decimal.frac != 0)) {
3911 return(-1);
3912 }
3913 if ((val == NULL) ||
3914 ((val->type != XML_SCHEMAS_DECIMAL) &&
3915 (val->type != XML_SCHEMAS_INTEGER) &&
3916 (val->type != XML_SCHEMAS_NPINTEGER) &&
3917 (val->type != XML_SCHEMAS_NINTEGER) &&
3918 (val->type != XML_SCHEMAS_NNINTEGER) &&
3919 (val->type != XML_SCHEMAS_PINTEGER) &&
3920 (val->type != XML_SCHEMAS_INT) &&
3921 (val->type != XML_SCHEMAS_UINT) &&
3922 (val->type != XML_SCHEMAS_LONG) &&
3923 (val->type != XML_SCHEMAS_ULONG) &&
3924 (val->type != XML_SCHEMAS_SHORT) &&
3925 (val->type != XML_SCHEMAS_USHORT) &&
3926 (val->type != XML_SCHEMAS_BYTE) &&
3927 (val->type != XML_SCHEMAS_UBYTE))) {
3928 return(-1);
3929 }
3930 if (facet->type == XML_SCHEMA_FACET_TOTALDIGITS) {
3931 if (val->value.decimal.total > facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00003932 return(XML_SCHEMAV_CVC_TOTALDIGITS_VALID);
Daniel Veillard560c2a42003-07-06 21:13:49 +00003933
3934 } else if (facet->type == XML_SCHEMA_FACET_FRACTIONDIGITS) {
3935 if (val->value.decimal.frac > facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00003936 return(XML_SCHEMAV_CVC_FRACTIONDIGITS_VALID);
Daniel Veillard560c2a42003-07-06 21:13:49 +00003937 }
3938 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00003939 default:
3940 TODO
3941 }
3942 return(0);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003943
Daniel Veillard4255d502002-04-16 15:50:10 +00003944}
3945
3946#endif /* LIBXML_SCHEMAS_ENABLED */