blob: 78e10fc7aca411b4da14f9c09a1fc5f0b7838747 [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/**
Daniel Veillard01fa6152004-06-29 17:04:39 +0000459 * xmlSchemaGetBuiltInType:
460 * @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 *
741 * Returns the item type of @type as defined by the built-in datatype
742 * hierarchy of XML Schema Part 2: Datatypes, or NULL in case of an error.
743 */
744xmlSchemaTypePtr
745xmlSchemaGetBuiltInListSimpleTypeItemType(xmlSchemaTypePtr type)
746{
747 if (type->type != XML_SCHEMA_TYPE_BASIC)
748 return (NULL);
749 switch (type->builtInType) {
750 case XML_SCHEMAS_NMTOKENS:
751 return (xmlSchemaTypeNmtokenDef );
752 case XML_SCHEMAS_IDREFS:
753 return (xmlSchemaTypeIdrefDef);
754 case XML_SCHEMAS_ENTITIES:
755 return (xmlSchemaTypeEntityDef);
756 default:
757 return (NULL);
758 }
759}
760
Daniel Veillard070803b2002-05-03 07:29:38 +0000761/****************************************************************
762 * *
763 * Convenience macros and functions *
764 * *
765 ****************************************************************/
766
767#define IS_TZO_CHAR(c) \
768 ((c == 0) || (c == 'Z') || (c == '+') || (c == '-'))
769
770#define VALID_YEAR(yr) (yr != 0)
771#define VALID_MONTH(mon) ((mon >= 1) && (mon <= 12))
772/* VALID_DAY should only be used when month is unknown */
773#define VALID_DAY(day) ((day >= 1) && (day <= 31))
774#define VALID_HOUR(hr) ((hr >= 0) && (hr <= 23))
775#define VALID_MIN(min) ((min >= 0) && (min <= 59))
776#define VALID_SEC(sec) ((sec >= 0) && (sec < 60))
777#define VALID_TZO(tzo) ((tzo > -1440) && (tzo < 1440))
778#define IS_LEAP(y) \
779 (((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0))
780
Daniel Veillardebe25d42004-03-25 09:35:49 +0000781static const unsigned int daysInMonth[12] =
Daniel Veillard070803b2002-05-03 07:29:38 +0000782 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
Daniel Veillardebe25d42004-03-25 09:35:49 +0000783static const unsigned int daysInMonthLeap[12] =
Daniel Veillard070803b2002-05-03 07:29:38 +0000784 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
785
Daniel Veillard5a872412002-05-22 06:40:27 +0000786#define MAX_DAYINMONTH(yr,mon) \
787 (IS_LEAP(yr) ? daysInMonthLeap[mon - 1] : daysInMonth[mon - 1])
788
Daniel Veillard070803b2002-05-03 07:29:38 +0000789#define VALID_MDAY(dt) \
790 (IS_LEAP(dt->year) ? \
791 (dt->day <= daysInMonthLeap[dt->mon - 1]) : \
792 (dt->day <= daysInMonth[dt->mon - 1]))
793
794#define VALID_DATE(dt) \
795 (VALID_YEAR(dt->year) && VALID_MONTH(dt->mon) && VALID_MDAY(dt))
796
797#define VALID_TIME(dt) \
798 (VALID_HOUR(dt->hour) && VALID_MIN(dt->min) && \
799 VALID_SEC(dt->sec) && VALID_TZO(dt->tzo))
800
801#define VALID_DATETIME(dt) \
802 (VALID_DATE(dt) && VALID_TIME(dt))
803
804#define SECS_PER_MIN (60)
805#define SECS_PER_HOUR (60 * SECS_PER_MIN)
806#define SECS_PER_DAY (24 * SECS_PER_HOUR)
807
Daniel Veillard5a872412002-05-22 06:40:27 +0000808static const long dayInYearByMonth[12] =
809 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
810static const long dayInLeapYearByMonth[12] =
811 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 };
812
813#define DAY_IN_YEAR(day, month, year) \
814 ((IS_LEAP(year) ? \
815 dayInLeapYearByMonth[month - 1] : \
816 dayInYearByMonth[month - 1]) + day)
817
818#ifdef DEBUG
819#define DEBUG_DATE(dt) \
820 xmlGenericError(xmlGenericErrorContext, \
821 "type=%o %04ld-%02u-%02uT%02u:%02u:%03f", \
822 dt->type,dt->value.date.year,dt->value.date.mon, \
823 dt->value.date.day,dt->value.date.hour,dt->value.date.min, \
824 dt->value.date.sec); \
825 if (dt->value.date.tz_flag) \
826 if (dt->value.date.tzo != 0) \
827 xmlGenericError(xmlGenericErrorContext, \
828 "%+05d\n",dt->value.date.tzo); \
829 else \
830 xmlGenericError(xmlGenericErrorContext, "Z\n"); \
831 else \
832 xmlGenericError(xmlGenericErrorContext,"\n")
833#else
834#define DEBUG_DATE(dt)
835#endif
836
Daniel Veillard070803b2002-05-03 07:29:38 +0000837/**
838 * _xmlSchemaParseGYear:
839 * @dt: pointer to a date structure
840 * @str: pointer to the string to analyze
841 *
842 * Parses a xs:gYear without time zone and fills in the appropriate
843 * field of the @dt structure. @str is updated to point just after the
844 * xs:gYear. It is supposed that @dt->year is big enough to contain
845 * the year.
846 *
847 * Returns 0 or the error code
848 */
849static int
850_xmlSchemaParseGYear (xmlSchemaValDatePtr dt, const xmlChar **str) {
851 const xmlChar *cur = *str, *firstChar;
852 int isneg = 0, digcnt = 0;
853
854 if (((*cur < '0') || (*cur > '9')) &&
855 (*cur != '-') && (*cur != '+'))
856 return -1;
857
858 if (*cur == '-') {
859 isneg = 1;
860 cur++;
861 }
862
863 firstChar = cur;
864
865 while ((*cur >= '0') && (*cur <= '9')) {
866 dt->year = dt->year * 10 + (*cur - '0');
867 cur++;
868 digcnt++;
869 }
870
871 /* year must be at least 4 digits (CCYY); over 4
872 * digits cannot have a leading zero. */
873 if ((digcnt < 4) || ((digcnt > 4) && (*firstChar == '0')))
874 return 1;
875
876 if (isneg)
877 dt->year = - dt->year;
878
879 if (!VALID_YEAR(dt->year))
880 return 2;
881
882 *str = cur;
883 return 0;
884}
885
886/**
887 * PARSE_2_DIGITS:
888 * @num: the integer to fill in
889 * @cur: an #xmlChar *
890 * @invalid: an integer
891 *
892 * Parses a 2-digits integer and updates @num with the value. @cur is
893 * updated to point just after the integer.
894 * In case of error, @invalid is set to %TRUE, values of @num and
895 * @cur are undefined.
896 */
897#define PARSE_2_DIGITS(num, cur, invalid) \
898 if ((cur[0] < '0') || (cur[0] > '9') || \
899 (cur[1] < '0') || (cur[1] > '9')) \
900 invalid = 1; \
901 else \
902 num = (cur[0] - '0') * 10 + (cur[1] - '0'); \
903 cur += 2;
904
905/**
906 * PARSE_FLOAT:
907 * @num: the double to fill in
908 * @cur: an #xmlChar *
909 * @invalid: an integer
910 *
911 * Parses a float and updates @num with the value. @cur is
912 * updated to point just after the float. The float must have a
913 * 2-digits integer part and may or may not have a decimal part.
914 * In case of error, @invalid is set to %TRUE, values of @num and
915 * @cur are undefined.
916 */
917#define PARSE_FLOAT(num, cur, invalid) \
918 PARSE_2_DIGITS(num, cur, invalid); \
919 if (!invalid && (*cur == '.')) { \
920 double mult = 1; \
921 cur++; \
922 if ((*cur < '0') || (*cur > '9')) \
923 invalid = 1; \
924 while ((*cur >= '0') && (*cur <= '9')) { \
925 mult /= 10; \
926 num += (*cur - '0') * mult; \
927 cur++; \
928 } \
929 }
930
931/**
932 * _xmlSchemaParseGMonth:
933 * @dt: pointer to a date structure
934 * @str: pointer to the string to analyze
935 *
936 * Parses a xs:gMonth without time zone and fills in the appropriate
937 * field of the @dt structure. @str is updated to point just after the
938 * xs:gMonth.
939 *
940 * Returns 0 or the error code
941 */
942static int
943_xmlSchemaParseGMonth (xmlSchemaValDatePtr dt, const xmlChar **str) {
944 const xmlChar *cur = *str;
945 int ret = 0;
946
947 PARSE_2_DIGITS(dt->mon, cur, ret);
948 if (ret != 0)
949 return ret;
950
951 if (!VALID_MONTH(dt->mon))
952 return 2;
953
954 *str = cur;
955 return 0;
956}
957
958/**
959 * _xmlSchemaParseGDay:
960 * @dt: pointer to a date structure
961 * @str: pointer to the string to analyze
962 *
963 * Parses a xs:gDay without time zone and fills in the appropriate
964 * field of the @dt structure. @str is updated to point just after the
965 * xs:gDay.
966 *
967 * Returns 0 or the error code
968 */
969static int
970_xmlSchemaParseGDay (xmlSchemaValDatePtr dt, const xmlChar **str) {
971 const xmlChar *cur = *str;
972 int ret = 0;
973
974 PARSE_2_DIGITS(dt->day, cur, ret);
975 if (ret != 0)
976 return ret;
977
978 if (!VALID_DAY(dt->day))
979 return 2;
980
981 *str = cur;
982 return 0;
983}
984
985/**
986 * _xmlSchemaParseTime:
987 * @dt: pointer to a date structure
988 * @str: pointer to the string to analyze
989 *
990 * Parses a xs:time without time zone and fills in the appropriate
991 * fields of the @dt structure. @str is updated to point just after the
992 * xs:time.
993 * In case of error, values of @dt fields are undefined.
994 *
995 * Returns 0 or the error code
996 */
997static int
998_xmlSchemaParseTime (xmlSchemaValDatePtr dt, const xmlChar **str) {
999 const xmlChar *cur = *str;
1000 unsigned int hour = 0; /* use temp var in case str is not xs:time */
1001 int ret = 0;
1002
1003 PARSE_2_DIGITS(hour, cur, ret);
1004 if (ret != 0)
1005 return ret;
1006
1007 if (*cur != ':')
1008 return 1;
1009 cur++;
1010
1011 /* the ':' insures this string is xs:time */
1012 dt->hour = hour;
1013
1014 PARSE_2_DIGITS(dt->min, cur, ret);
1015 if (ret != 0)
1016 return ret;
1017
1018 if (*cur != ':')
1019 return 1;
1020 cur++;
1021
1022 PARSE_FLOAT(dt->sec, cur, ret);
1023 if (ret != 0)
1024 return ret;
1025
1026 if (!VALID_TIME(dt))
1027 return 2;
1028
1029 *str = cur;
1030 return 0;
1031}
1032
1033/**
1034 * _xmlSchemaParseTimeZone:
1035 * @dt: pointer to a date structure
1036 * @str: pointer to the string to analyze
1037 *
1038 * Parses a time zone without time zone and fills in the appropriate
1039 * field of the @dt structure. @str is updated to point just after the
1040 * time zone.
1041 *
1042 * Returns 0 or the error code
1043 */
1044static int
1045_xmlSchemaParseTimeZone (xmlSchemaValDatePtr dt, const xmlChar **str) {
1046 const xmlChar *cur = *str;
1047 int ret = 0;
1048
1049 if (str == NULL)
1050 return -1;
1051
1052 switch (*cur) {
1053 case 0:
1054 dt->tz_flag = 0;
1055 dt->tzo = 0;
1056 break;
1057
1058 case 'Z':
1059 dt->tz_flag = 1;
1060 dt->tzo = 0;
1061 cur++;
1062 break;
1063
1064 case '+':
1065 case '-': {
1066 int isneg = 0, tmp = 0;
1067 isneg = (*cur == '-');
1068
1069 cur++;
1070
1071 PARSE_2_DIGITS(tmp, cur, ret);
1072 if (ret != 0)
1073 return ret;
1074 if (!VALID_HOUR(tmp))
1075 return 2;
1076
1077 if (*cur != ':')
1078 return 1;
1079 cur++;
1080
1081 dt->tzo = tmp * 60;
1082
1083 PARSE_2_DIGITS(tmp, cur, ret);
1084 if (ret != 0)
1085 return ret;
1086 if (!VALID_MIN(tmp))
1087 return 2;
1088
1089 dt->tzo += tmp;
1090 if (isneg)
1091 dt->tzo = - dt->tzo;
1092
1093 if (!VALID_TZO(dt->tzo))
1094 return 2;
1095
Daniel Veillard5a872412002-05-22 06:40:27 +00001096 dt->tz_flag = 1;
Daniel Veillard070803b2002-05-03 07:29:38 +00001097 break;
1098 }
1099 default:
1100 return 1;
1101 }
1102
1103 *str = cur;
1104 return 0;
1105}
1106
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001107/**
1108 * _xmlSchemaBase64Decode:
1109 * @ch: a character
1110 *
1111 * Converts a base64 encoded character to its base 64 value.
1112 *
1113 * Returns 0-63 (value), 64 (pad), or -1 (not recognized)
1114 */
1115static int
1116_xmlSchemaBase64Decode (const xmlChar ch) {
1117 if (('A' <= ch) && (ch <= 'Z')) return ch - 'A';
1118 if (('a' <= ch) && (ch <= 'z')) return ch - 'a' + 26;
1119 if (('0' <= ch) && (ch <= '9')) return ch - '0' + 52;
1120 if ('+' == ch) return 62;
1121 if ('/' == ch) return 63;
1122 if ('=' == ch) return 64;
1123 return -1;
1124}
1125
Daniel Veillard070803b2002-05-03 07:29:38 +00001126/****************************************************************
1127 * *
1128 * XML Schema Dates/Times Datatypes Handling *
1129 * *
1130 ****************************************************************/
1131
1132/**
1133 * PARSE_DIGITS:
1134 * @num: the integer to fill in
1135 * @cur: an #xmlChar *
1136 * @num_type: an integer flag
1137 *
1138 * Parses a digits integer and updates @num with the value. @cur is
1139 * updated to point just after the integer.
1140 * In case of error, @num_type is set to -1, values of @num and
1141 * @cur are undefined.
1142 */
1143#define PARSE_DIGITS(num, cur, num_type) \
1144 if ((*cur < '0') || (*cur > '9')) \
1145 num_type = -1; \
1146 else \
1147 while ((*cur >= '0') && (*cur <= '9')) { \
1148 num = num * 10 + (*cur - '0'); \
1149 cur++; \
1150 }
1151
1152/**
1153 * PARSE_NUM:
1154 * @num: the double to fill in
1155 * @cur: an #xmlChar *
1156 * @num_type: an integer flag
1157 *
1158 * Parses a float or integer and updates @num with the value. @cur is
1159 * updated to point just after the number. If the number is a float,
1160 * then it must have an integer part and a decimal part; @num_type will
1161 * be set to 1. If there is no decimal part, @num_type is set to zero.
1162 * In case of error, @num_type is set to -1, values of @num and
1163 * @cur are undefined.
1164 */
1165#define PARSE_NUM(num, cur, num_type) \
1166 num = 0; \
1167 PARSE_DIGITS(num, cur, num_type); \
1168 if (!num_type && (*cur == '.')) { \
1169 double mult = 1; \
1170 cur++; \
1171 if ((*cur < '0') || (*cur > '9')) \
1172 num_type = -1; \
1173 else \
1174 num_type = 1; \
1175 while ((*cur >= '0') && (*cur <= '9')) { \
1176 mult /= 10; \
1177 num += (*cur - '0') * mult; \
1178 cur++; \
1179 } \
1180 }
1181
1182/**
Daniel Veillard5a872412002-05-22 06:40:27 +00001183 * xmlSchemaValidateDates:
Daniel Veillard455cc072003-03-31 10:13:23 +00001184 * @type: the expected type or XML_SCHEMAS_UNKNOWN
Daniel Veillard070803b2002-05-03 07:29:38 +00001185 * @dateTime: string to analyze
1186 * @val: the return computed value
1187 *
1188 * Check that @dateTime conforms to the lexical space of one of the date types.
1189 * if true a value is computed and returned in @val.
1190 *
1191 * Returns 0 if this validates, a positive error code number otherwise
1192 * and -1 in case of internal or API error.
1193 */
1194static int
Daniel Veillard455cc072003-03-31 10:13:23 +00001195xmlSchemaValidateDates (xmlSchemaValType type,
Daniel Veillard118aed72002-09-24 14:13:13 +00001196 const xmlChar *dateTime, xmlSchemaValPtr *val) {
Daniel Veillard070803b2002-05-03 07:29:38 +00001197 xmlSchemaValPtr dt;
1198 int ret;
1199 const xmlChar *cur = dateTime;
1200
1201#define RETURN_TYPE_IF_VALID(t) \
1202 if (IS_TZO_CHAR(*cur)) { \
1203 ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur); \
1204 if (ret == 0) { \
1205 if (*cur != 0) \
1206 goto error; \
1207 dt->type = t; \
Daniel Veillard455cc072003-03-31 10:13:23 +00001208 goto done; \
Daniel Veillard070803b2002-05-03 07:29:38 +00001209 } \
1210 }
1211
1212 if (dateTime == NULL)
1213 return -1;
1214
1215 if ((*cur != '-') && (*cur < '0') && (*cur > '9'))
1216 return 1;
1217
1218 dt = xmlSchemaNewValue(XML_SCHEMAS_UNKNOWN);
1219 if (dt == NULL)
1220 return -1;
1221
1222 if ((cur[0] == '-') && (cur[1] == '-')) {
1223 /*
1224 * It's an incomplete date (xs:gMonthDay, xs:gMonth or
1225 * xs:gDay)
1226 */
1227 cur += 2;
1228
1229 /* is it an xs:gDay? */
1230 if (*cur == '-') {
Daniel Veillard455cc072003-03-31 10:13:23 +00001231 if (type == XML_SCHEMAS_GMONTH)
1232 goto error;
Daniel Veillard070803b2002-05-03 07:29:38 +00001233 ++cur;
1234 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
1235 if (ret != 0)
1236 goto error;
1237
1238 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GDAY);
1239
1240 goto error;
1241 }
1242
1243 /*
1244 * it should be an xs:gMonthDay or xs:gMonth
1245 */
1246 ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
1247 if (ret != 0)
1248 goto error;
1249
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001250 /*
1251 * a '-' char could indicate this type is xs:gMonthDay or
1252 * a negative time zone offset. Check for xs:gMonthDay first.
1253 * Also the first three char's of a negative tzo (-MM:SS) can
1254 * appear to be a valid day; so even if the day portion
1255 * of the xs:gMonthDay verifies, we must insure it was not
1256 * a tzo.
1257 */
1258 if (*cur == '-') {
1259 const xmlChar *rewnd = cur;
1260 cur++;
Daniel Veillard070803b2002-05-03 07:29:38 +00001261
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001262 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
1263 if ((ret == 0) && ((*cur == 0) || (*cur != ':'))) {
1264
1265 /*
1266 * we can use the VALID_MDAY macro to validate the month
1267 * and day because the leap year test will flag year zero
1268 * as a leap year (even though zero is an invalid year).
1269 */
1270 if (VALID_MDAY((&(dt->value.date)))) {
1271
1272 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTHDAY);
1273
1274 goto error;
1275 }
1276 }
1277
1278 /*
1279 * not xs:gMonthDay so rewind and check if just xs:gMonth
1280 * with an optional time zone.
1281 */
1282 cur = rewnd;
1283 }
1284
1285 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTH);
Daniel Veillard070803b2002-05-03 07:29:38 +00001286
1287 goto error;
1288 }
1289
1290 /*
1291 * It's a right-truncated date or an xs:time.
1292 * Try to parse an xs:time then fallback on right-truncated dates.
1293 */
1294 if ((*cur >= '0') && (*cur <= '9')) {
1295 ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
1296 if (ret == 0) {
1297 /* it's an xs:time */
1298 RETURN_TYPE_IF_VALID(XML_SCHEMAS_TIME);
1299 }
1300 }
1301
1302 /* fallback on date parsing */
1303 cur = dateTime;
1304
1305 ret = _xmlSchemaParseGYear(&(dt->value.date), &cur);
1306 if (ret != 0)
1307 goto error;
1308
1309 /* is it an xs:gYear? */
1310 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEAR);
1311
1312 if (*cur != '-')
1313 goto error;
1314 cur++;
1315
1316 ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
1317 if (ret != 0)
1318 goto error;
1319
1320 /* is it an xs:gYearMonth? */
1321 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEARMONTH);
1322
1323 if (*cur != '-')
1324 goto error;
1325 cur++;
1326
1327 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
1328 if ((ret != 0) || !VALID_DATE((&(dt->value.date))))
1329 goto error;
1330
1331 /* is it an xs:date? */
1332 RETURN_TYPE_IF_VALID(XML_SCHEMAS_DATE);
1333
1334 if (*cur != 'T')
1335 goto error;
1336 cur++;
1337
1338 /* it should be an xs:dateTime */
1339 ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
1340 if (ret != 0)
1341 goto error;
1342
1343 ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur);
1344 if ((ret != 0) || (*cur != 0) || !VALID_DATETIME((&(dt->value.date))))
1345 goto error;
1346
Daniel Veillard455cc072003-03-31 10:13:23 +00001347
Daniel Veillard070803b2002-05-03 07:29:38 +00001348 dt->type = XML_SCHEMAS_DATETIME;
1349
Daniel Veillard455cc072003-03-31 10:13:23 +00001350done:
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001351#if 1
1352 if ((type != XML_SCHEMAS_UNKNOWN) && (type != dt->type))
1353 goto error;
1354#else
1355 /*
1356 * insure the parsed type is equal to or less significant (right
1357 * truncated) than the desired type.
1358 */
1359 if ((type != XML_SCHEMAS_UNKNOWN) && (type != dt->type)) {
1360
1361 /* time only matches time */
1362 if ((type == XML_SCHEMAS_TIME) && (dt->type == XML_SCHEMAS_TIME))
1363 goto error;
1364
1365 if ((type == XML_SCHEMAS_DATETIME) &&
1366 ((dt->type != XML_SCHEMAS_DATE) ||
1367 (dt->type != XML_SCHEMAS_GYEARMONTH) ||
1368 (dt->type != XML_SCHEMAS_GYEAR)))
1369 goto error;
1370
1371 if ((type == XML_SCHEMAS_DATE) &&
1372 ((dt->type != XML_SCHEMAS_GYEAR) ||
1373 (dt->type != XML_SCHEMAS_GYEARMONTH)))
1374 goto error;
1375
1376 if ((type == XML_SCHEMAS_GYEARMONTH) && (dt->type != XML_SCHEMAS_GYEAR))
1377 goto error;
1378
1379 if ((type == XML_SCHEMAS_GMONTHDAY) && (dt->type != XML_SCHEMAS_GMONTH))
1380 goto error;
1381 }
Daniel Veillard455cc072003-03-31 10:13:23 +00001382#endif
1383
Daniel Veillard070803b2002-05-03 07:29:38 +00001384 if (val != NULL)
1385 *val = dt;
Daniel Veillard80b19092003-03-28 13:29:53 +00001386 else
1387 xmlSchemaFreeValue(dt);
Daniel Veillard070803b2002-05-03 07:29:38 +00001388
1389 return 0;
1390
1391error:
1392 if (dt != NULL)
1393 xmlSchemaFreeValue(dt);
1394 return 1;
1395}
1396
1397/**
Daniel Veillard5a872412002-05-22 06:40:27 +00001398 * xmlSchemaValidateDuration:
Daniel Veillard070803b2002-05-03 07:29:38 +00001399 * @type: the predefined type
1400 * @duration: string to analyze
1401 * @val: the return computed value
1402 *
1403 * Check that @duration conforms to the lexical space of the duration type.
1404 * if true a value is computed and returned in @val.
1405 *
1406 * Returns 0 if this validates, a positive error code number otherwise
1407 * and -1 in case of internal or API error.
1408 */
1409static int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00001410xmlSchemaValidateDuration (xmlSchemaTypePtr type ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +00001411 const xmlChar *duration, xmlSchemaValPtr *val) {
Daniel Veillard070803b2002-05-03 07:29:38 +00001412 const xmlChar *cur = duration;
1413 xmlSchemaValPtr dur;
1414 int isneg = 0;
1415 unsigned int seq = 0;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001416 double num;
1417 int num_type = 0; /* -1 = invalid, 0 = int, 1 = floating */
1418 const xmlChar desig[] = {'Y', 'M', 'D', 'H', 'M', 'S'};
1419 const double multi[] = { 0.0, 0.0, 86400.0, 3600.0, 60.0, 1.0, 0.0};
Daniel Veillard070803b2002-05-03 07:29:38 +00001420
1421 if (duration == NULL)
1422 return -1;
1423
1424 if (*cur == '-') {
1425 isneg = 1;
1426 cur++;
1427 }
1428
1429 /* duration must start with 'P' (after sign) */
1430 if (*cur++ != 'P')
1431 return 1;
1432
Daniel Veillard80b19092003-03-28 13:29:53 +00001433 if (*cur == 0)
1434 return 1;
1435
Daniel Veillard070803b2002-05-03 07:29:38 +00001436 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
1437 if (dur == NULL)
1438 return -1;
1439
1440 while (*cur != 0) {
Daniel Veillard070803b2002-05-03 07:29:38 +00001441
1442 /* input string should be empty or invalid date/time item */
1443 if (seq >= sizeof(desig))
1444 goto error;
1445
1446 /* T designator must be present for time items */
1447 if (*cur == 'T') {
1448 if (seq <= 3) {
1449 seq = 3;
1450 cur++;
1451 } else
1452 return 1;
1453 } else if (seq == 3)
1454 goto error;
1455
1456 /* parse the number portion of the item */
1457 PARSE_NUM(num, cur, num_type);
1458
1459 if ((num_type == -1) || (*cur == 0))
1460 goto error;
1461
1462 /* update duration based on item type */
1463 while (seq < sizeof(desig)) {
1464 if (*cur == desig[seq]) {
1465
1466 /* verify numeric type; only seconds can be float */
1467 if ((num_type != 0) && (seq < (sizeof(desig)-1)))
1468 goto error;
1469
1470 switch (seq) {
1471 case 0:
1472 dur->value.dur.mon = (long)num * 12;
1473 break;
1474 case 1:
1475 dur->value.dur.mon += (long)num;
1476 break;
1477 default:
1478 /* convert to seconds using multiplier */
1479 dur->value.dur.sec += num * multi[seq];
1480 seq++;
1481 break;
1482 }
1483
1484 break; /* exit loop */
1485 }
1486 /* no date designators found? */
1487 if (++seq == 3)
1488 goto error;
1489 }
1490 cur++;
1491 }
1492
1493 if (isneg) {
1494 dur->value.dur.mon = -dur->value.dur.mon;
1495 dur->value.dur.day = -dur->value.dur.day;
1496 dur->value.dur.sec = -dur->value.dur.sec;
1497 }
1498
1499 if (val != NULL)
1500 *val = dur;
Daniel Veillard80b19092003-03-28 13:29:53 +00001501 else
1502 xmlSchemaFreeValue(dur);
Daniel Veillard070803b2002-05-03 07:29:38 +00001503
1504 return 0;
1505
1506error:
1507 if (dur != NULL)
1508 xmlSchemaFreeValue(dur);
1509 return 1;
1510}
1511
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001512/**
1513 * xmlSchemaStrip:
1514 * @value: a value
1515 *
1516 * Removes the leading and ending spaces of a string
1517 *
1518 * Returns the new string or NULL if no change was required.
1519 */
1520static xmlChar *
1521xmlSchemaStrip(const xmlChar *value) {
1522 const xmlChar *start = value, *end, *f;
1523
1524 if (value == NULL) return(NULL);
William M. Brack76e95df2003-10-18 16:20:14 +00001525 while ((*start != 0) && (IS_BLANK_CH(*start))) start++;
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001526 end = start;
1527 while (*end != 0) end++;
1528 f = end;
1529 end--;
William M. Brack76e95df2003-10-18 16:20:14 +00001530 while ((end > start) && (IS_BLANK_CH(*end))) end--;
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001531 end++;
1532 if ((start == value) && (f == end)) return(NULL);
1533 return(xmlStrndup(start, end - start));
1534}
Daniel Veillard96a4b252003-02-06 08:22:32 +00001535
1536/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001537 * xmlSchemaCollapseString:
1538 * @value: a value
1539 *
1540 * Removes and normalize white spaces in the string
1541 *
1542 * Returns the new string or NULL if no change was required.
1543 */
Daniel Veillard01fa6152004-06-29 17:04:39 +00001544xmlChar *
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001545xmlSchemaCollapseString(const xmlChar *value) {
1546 const xmlChar *start = value, *end, *f;
1547 xmlChar *g;
1548 int col = 0;
1549
1550 if (value == NULL) return(NULL);
William M. Brack76e95df2003-10-18 16:20:14 +00001551 while ((*start != 0) && (IS_BLANK_CH(*start))) start++;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001552 end = start;
1553 while (*end != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00001554 if ((*end == ' ') && (IS_BLANK_CH(end[1]))) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001555 col = end - start;
1556 break;
1557 } else if ((*end == 0xa) || (*end == 0x9) || (*end == 0xd)) {
1558 col = end - start;
1559 break;
1560 }
1561 end++;
1562 }
1563 if (col == 0) {
1564 f = end;
1565 end--;
William M. Brack76e95df2003-10-18 16:20:14 +00001566 while ((end > start) && (IS_BLANK_CH(*end))) end--;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001567 end++;
1568 if ((start == value) && (f == end)) return(NULL);
1569 return(xmlStrndup(start, end - start));
1570 }
1571 start = xmlStrdup(start);
1572 if (start == NULL) return(NULL);
1573 g = (xmlChar *) (start + col);
1574 end = g;
1575 while (*end != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00001576 if (IS_BLANK_CH(*end)) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001577 end++;
William M. Brack76e95df2003-10-18 16:20:14 +00001578 while (IS_BLANK_CH(*end)) end++;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001579 if (*end != 0)
1580 *g++ = ' ';
1581 } else
1582 *g++ = *end++;
1583 }
1584 *g = 0;
1585 return((xmlChar *) start);
1586}
1587
1588/**
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001589 * xmlSchemaValAtomicListNode:
1590 * @type: the predefined atomic type for a token in the list
1591 * @value: the list value to check
1592 * @ret: the return computed value
1593 * @node: the node containing the value
1594 *
1595 * Check that a value conforms to the lexical space of the predefined
1596 * list type. if true a value is computed and returned in @ret.
1597 *
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001598 * Returns the number of items if this validates, a negative error code
1599 * number otherwise
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001600 */
1601static int
1602xmlSchemaValAtomicListNode(xmlSchemaTypePtr type, const xmlChar *value,
1603 xmlSchemaValPtr *ret, xmlNodePtr node) {
1604 xmlChar *val, *cur, *endval;
1605 int nb_values = 0;
Daniel Veillard580ced82003-03-21 21:22:48 +00001606 int tmp = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001607
1608 if (value == NULL) {
1609 return(-1);
1610 }
1611 val = xmlStrdup(value);
1612 if (val == NULL) {
1613 return(-1);
1614 }
1615 cur = val;
1616 /*
1617 * Split the list
1618 */
William M. Brack76e95df2003-10-18 16:20:14 +00001619 while (IS_BLANK_CH(*cur)) *cur++ = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001620 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00001621 if (IS_BLANK_CH(*cur)) {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001622 *cur = 0;
1623 cur++;
William M. Brack76e95df2003-10-18 16:20:14 +00001624 while (IS_BLANK_CH(*cur)) *cur++ = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001625 } else {
1626 nb_values++;
1627 cur++;
William M. Brack76e95df2003-10-18 16:20:14 +00001628 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001629 }
1630 }
1631 if (nb_values == 0) {
1632 if (ret != NULL) {
1633 TODO
1634 }
1635 xmlFree(val);
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001636 return(nb_values);
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001637 }
1638 endval = cur;
1639 cur = val;
1640 while ((*cur == 0) && (cur != endval)) cur++;
1641 while (cur != endval) {
1642 tmp = xmlSchemaValPredefTypeNode(type, cur, NULL, node);
1643 if (tmp != 0)
1644 break;
1645 while (*cur != 0) cur++;
1646 while ((*cur == 0) && (cur != endval)) cur++;
1647 }
1648 xmlFree(val);
1649 if (ret != NULL) {
1650 TODO
1651 }
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001652 if (tmp == 0)
1653 return(nb_values);
1654 return(-1);
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001655}
1656
1657/**
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001658 * xmlSchemaParseUInt:
1659 * @str: pointer to the string R/W
1660 * @llo: pointer to the low result
1661 * @lmi: pointer to the mid result
1662 * @lhi: pointer to the high result
1663 *
1664 * Parse an unsigned long into 3 fields.
1665 *
1666 * Returns the number of chars parsed or -1 if overflow of the capacity
1667 */
1668static int
1669xmlSchemaParseUInt(const xmlChar **str, unsigned long *llo,
1670 unsigned long *lmi, unsigned long *lhi) {
1671 unsigned long lo = 0, mi = 0, hi = 0;
1672 const xmlChar *tmp, *cur = *str;
1673 int ret = 0, i = 0;
1674
1675 while (*cur == '0') {
1676 ret++;
1677 cur++;
1678 }
1679 tmp = cur;
1680 while ((*tmp != 0) && (*tmp >= '0') && (*tmp <= '9')) {
1681 i++;tmp++;ret++;
1682 }
1683 if (i > 24) {
1684 *str = tmp;
1685 return(-1);
1686 }
1687 while (i > 16) {
1688 hi = hi * 10 + (*cur++ - '0');
1689 i--;
1690 }
1691 while (i > 8) {
1692 mi = mi * 10 + (*cur++ - '0');
1693 i--;
1694 }
1695 while (i > 0) {
1696 lo = lo * 10 + (*cur++ - '0');
1697 i--;
1698 }
1699
1700 *str = cur;
1701 *llo = lo;
1702 *lmi = mi;
1703 *lhi = hi;
1704 return(ret);
1705}
1706
1707/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001708 * xmlSchemaValAtomicType:
1709 * @type: the predefined type
1710 * @value: the value to check
1711 * @val: the return computed value
1712 * @node: the node containing the value
1713 * flags: flags to control the vlidation
1714 *
1715 * Check that a value conforms to the lexical space of the atomic type.
1716 * if true a value is computed and returned in @val.
Daniel Veillard01fa6152004-06-29 17:04:39 +00001717 * This checks the value space for list types as well (IDREFS, NMTOKENS).
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001718 *
1719 * Returns 0 if this validates, a positive error code number otherwise
1720 * and -1 in case of internal or API error.
1721 */
1722static int
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001723xmlSchemaValAtomicType(xmlSchemaTypePtr type, const xmlChar * value,
1724 xmlSchemaValPtr * val, xmlNodePtr node, int flags)
1725{
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001726 xmlSchemaValPtr v;
1727 xmlChar *norm = NULL;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001728 int ret = 0;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001729
1730 if (xmlSchemaTypesInitialized == 0)
Daniel Veillard01fa6152004-06-29 17:04:39 +00001731 xmlSchemaInitTypes();
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001732 if (type == NULL)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001733 return (-1);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001734
1735 if (val != NULL)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001736 *val = NULL;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001737 if ((flags == 0) && (value != NULL)) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00001738 if ((type->builtInType != XML_SCHEMAS_STRING) &&
1739 (type->builtInType != XML_SCHEMAS_NORMSTRING)) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001740 norm = xmlSchemaCollapseString(value);
1741 if (norm != NULL)
1742 value = norm;
1743 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001744 }
1745
Daniel Veillard01fa6152004-06-29 17:04:39 +00001746 switch (type->builtInType) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001747 case XML_SCHEMAS_UNKNOWN:
Daniel Veillard01fa6152004-06-29 17:04:39 +00001748 if (type == xmlSchemaTypeAnySimpleTypeDef)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001749 goto return0;
1750 goto error;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001751 case XML_SCHEMAS_STRING:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001752 goto return0;
Daniel Veillard1516d5b2004-01-22 07:27:45 +00001753 case XML_SCHEMAS_NORMSTRING:{
1754 const xmlChar *cur = value;
1755
1756 while (*cur != 0) {
1757 if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) {
1758 goto return1;
1759 } else {
1760 cur++;
1761 }
1762 }
1763 if (val != NULL) {
1764 v = xmlSchemaNewValue(XML_SCHEMAS_NORMSTRING);
1765 if (v != NULL) {
1766 v->value.str = xmlStrdup(value);
1767 *val = v;
1768 } else {
1769 goto error;
1770 }
1771 }
1772 goto return0;
1773 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001774 case XML_SCHEMAS_DECIMAL:{
1775 const xmlChar *cur = value, *tmp;
1776 unsigned int frac = 0, len, neg = 0;
1777 unsigned long base = 0;
1778
1779 if (cur == NULL)
1780 goto return1;
1781 if (*cur == '+')
1782 cur++;
1783 else if (*cur == '-') {
1784 neg = 1;
1785 cur++;
1786 }
1787 tmp = cur;
1788 while ((*cur >= '0') && (*cur <= '9')) {
1789 base = base * 10 + (*cur - '0');
1790 cur++;
1791 }
1792 len = cur - tmp;
1793 if (*cur == '.') {
1794 cur++;
1795 tmp = cur;
1796 while ((*cur >= '0') && (*cur <= '9')) {
1797 base = base * 10 + (*cur - '0');
1798 cur++;
1799 }
1800 frac = cur - tmp;
1801 }
1802 if (*cur != 0)
1803 goto return1;
1804 if (val != NULL) {
1805 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
1806 if (v != NULL) {
1807 v->value.decimal.lo = base;
1808 v->value.decimal.sign = neg;
1809 v->value.decimal.frac = frac;
1810 v->value.decimal.total = frac + len;
1811 *val = v;
1812 }
1813 }
1814 goto return0;
1815 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001816 case XML_SCHEMAS_TIME:
1817 case XML_SCHEMAS_GDAY:
1818 case XML_SCHEMAS_GMONTH:
1819 case XML_SCHEMAS_GMONTHDAY:
1820 case XML_SCHEMAS_GYEAR:
1821 case XML_SCHEMAS_GYEARMONTH:
1822 case XML_SCHEMAS_DATE:
1823 case XML_SCHEMAS_DATETIME:
Daniel Veillard01fa6152004-06-29 17:04:39 +00001824 ret = xmlSchemaValidateDates(type->builtInType, value, val);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001825 break;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001826 case XML_SCHEMAS_DURATION:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001827 ret = xmlSchemaValidateDuration(type, value, val);
1828 break;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001829 case XML_SCHEMAS_FLOAT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001830 case XML_SCHEMAS_DOUBLE:{
1831 const xmlChar *cur = value;
1832 int neg = 0;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001833
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001834 if (cur == NULL)
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00001835 goto return1;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001836 if ((cur[0] == 'N') && (cur[1] == 'a') && (cur[2] == 'N')) {
1837 cur += 3;
1838 if (*cur != 0)
1839 goto return1;
1840 if (val != NULL) {
1841 if (type == xmlSchemaTypeFloatDef) {
1842 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1843 if (v != NULL) {
1844 v->value.f = (float) xmlXPathNAN;
1845 } else {
1846 xmlSchemaFreeValue(v);
1847 goto error;
1848 }
1849 } else {
1850 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1851 if (v != NULL) {
1852 v->value.d = xmlXPathNAN;
1853 } else {
1854 xmlSchemaFreeValue(v);
1855 goto error;
1856 }
1857 }
1858 *val = v;
1859 }
1860 goto return0;
1861 }
1862 if (*cur == '-') {
1863 neg = 1;
1864 cur++;
1865 }
1866 if ((cur[0] == 'I') && (cur[1] == 'N') && (cur[2] == 'F')) {
1867 cur += 3;
1868 if (*cur != 0)
1869 goto return1;
1870 if (val != NULL) {
1871 if (type == xmlSchemaTypeFloatDef) {
1872 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1873 if (v != NULL) {
1874 if (neg)
1875 v->value.f = (float) xmlXPathNINF;
1876 else
1877 v->value.f = (float) xmlXPathPINF;
1878 } else {
1879 xmlSchemaFreeValue(v);
1880 goto error;
1881 }
1882 } else {
1883 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1884 if (v != NULL) {
1885 if (neg)
1886 v->value.d = xmlXPathNINF;
1887 else
1888 v->value.d = xmlXPathPINF;
1889 } else {
1890 xmlSchemaFreeValue(v);
1891 goto error;
1892 }
1893 }
1894 *val = v;
1895 }
1896 goto return0;
1897 }
1898 if ((neg == 0) && (*cur == '+'))
1899 cur++;
1900 if ((cur[0] == 0) || (cur[0] == '+') || (cur[0] == '-'))
1901 goto return1;
1902 while ((*cur >= '0') && (*cur <= '9')) {
1903 cur++;
1904 }
1905 if (*cur == '.') {
1906 cur++;
1907 while ((*cur >= '0') && (*cur <= '9'))
1908 cur++;
1909 }
1910 if ((*cur == 'e') || (*cur == 'E')) {
1911 cur++;
1912 if ((*cur == '-') || (*cur == '+'))
1913 cur++;
1914 while ((*cur >= '0') && (*cur <= '9'))
1915 cur++;
1916 }
1917 if (*cur != 0)
1918 goto return1;
1919 if (val != NULL) {
1920 if (type == xmlSchemaTypeFloatDef) {
1921 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1922 if (v != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001923 if (sscanf((const char *) value, "%f",
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001924 &(v->value.f)) == 1) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00001925 *val = v;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001926 } else {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001927 xmlSchemaFreeValue(v);
1928 goto return1;
1929 }
1930 } else {
1931 goto error;
1932 }
1933 } else {
1934 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1935 if (v != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001936 if (sscanf((const char *) value, "%lf",
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001937 &(v->value.d)) == 1) {
1938 *val = v;
1939 } else {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001940 xmlSchemaFreeValue(v);
1941 goto return1;
1942 }
1943 } else {
1944 goto error;
1945 }
1946 }
1947 }
1948 goto return0;
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00001949 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001950 case XML_SCHEMAS_BOOLEAN:{
1951 const xmlChar *cur = value;
1952
1953 if ((cur[0] == '0') && (cur[1] == 0))
1954 ret = 0;
1955 else if ((cur[0] == '1') && (cur[1] == 0))
1956 ret = 1;
1957 else if ((cur[0] == 't') && (cur[1] == 'r')
1958 && (cur[2] == 'u') && (cur[3] == 'e')
1959 && (cur[4] == 0))
1960 ret = 1;
1961 else if ((cur[0] == 'f') && (cur[1] == 'a')
1962 && (cur[2] == 'l') && (cur[3] == 's')
1963 && (cur[4] == 'e') && (cur[5] == 0))
1964 ret = 0;
1965 else
1966 goto return1;
1967 if (val != NULL) {
1968 v = xmlSchemaNewValue(XML_SCHEMAS_BOOLEAN);
1969 if (v != NULL) {
1970 v->value.b = ret;
1971 *val = v;
1972 } else {
1973 goto error;
1974 }
1975 }
1976 goto return0;
1977 }
1978 case XML_SCHEMAS_TOKEN:{
1979 const xmlChar *cur = value;
1980
William M. Brack76e95df2003-10-18 16:20:14 +00001981 if (IS_BLANK_CH(*cur))
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001982 goto return1;
1983
1984 while (*cur != 0) {
1985 if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) {
1986 goto return1;
1987 } else if (*cur == ' ') {
1988 cur++;
1989 if (*cur == 0)
1990 goto return1;
1991 if (*cur == ' ')
1992 goto return1;
1993 } else {
1994 cur++;
1995 }
1996 }
1997 if (val != NULL) {
1998 v = xmlSchemaNewValue(XML_SCHEMAS_TOKEN);
1999 if (v != NULL) {
2000 v->value.str = xmlStrdup(value);
2001 *val = v;
2002 } else {
2003 goto error;
2004 }
2005 }
2006 goto return0;
2007 }
2008 case XML_SCHEMAS_LANGUAGE:
2009 if (xmlCheckLanguageID(value) == 1) {
2010 if (val != NULL) {
2011 v = xmlSchemaNewValue(XML_SCHEMAS_LANGUAGE);
2012 if (v != NULL) {
2013 v->value.str = xmlStrdup(value);
2014 *val = v;
2015 } else {
2016 goto error;
2017 }
2018 }
2019 goto return0;
2020 }
2021 goto return1;
2022 case XML_SCHEMAS_NMTOKEN:
2023 if (xmlValidateNMToken(value, 1) == 0) {
2024 if (val != NULL) {
2025 v = xmlSchemaNewValue(XML_SCHEMAS_NMTOKEN);
2026 if (v != NULL) {
2027 v->value.str = xmlStrdup(value);
2028 *val = v;
2029 } else {
2030 goto error;
2031 }
2032 }
2033 goto return0;
2034 }
2035 goto return1;
2036 case XML_SCHEMAS_NMTOKENS:
2037 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeNmtokenDef,
2038 value, val, node);
2039 if (ret > 0)
2040 ret = 0;
2041 else
2042 ret = 1;
2043 goto done;
2044 case XML_SCHEMAS_NAME:
2045 ret = xmlValidateName(value, 1);
2046 if ((ret == 0) && (val != NULL)) {
2047 TODO;
2048 }
2049 goto done;
2050 case XML_SCHEMAS_QNAME:{
2051 xmlChar *uri = NULL;
2052 xmlChar *local = NULL;
2053
2054 ret = xmlValidateQName(value, 1);
2055 if ((ret == 0) && (node != NULL)) {
2056 xmlChar *prefix;
2057
2058 local = xmlSplitQName2(value, &prefix);
2059 if (prefix != NULL) {
2060 xmlNsPtr ns;
2061
2062 ns = xmlSearchNs(node->doc, node, prefix);
2063 if (ns == NULL)
2064 ret = 1;
2065 else if (val != NULL)
2066 uri = xmlStrdup(ns->href);
2067 }
2068 if ((local != NULL) && ((val == NULL) || (ret != 0)))
2069 xmlFree(local);
2070 if (prefix != NULL)
2071 xmlFree(prefix);
2072 }
2073 if ((ret == 0) && (val != NULL)) {
2074 v = xmlSchemaNewValue(XML_SCHEMAS_QNAME);
2075 if (v != NULL) {
2076 if (local != NULL)
2077 v->value.qname.name = local;
2078 else
2079 v->value.qname.name = xmlStrdup(value);
2080 if (uri != NULL)
2081 v->value.qname.uri = uri;
2082
2083 *val = v;
2084 } else {
2085 if (local != NULL)
2086 xmlFree(local);
2087 if (uri != NULL)
2088 xmlFree(uri);
2089 goto error;
2090 }
2091 }
2092 goto done;
2093 }
2094 case XML_SCHEMAS_NCNAME:
2095 ret = xmlValidateNCName(value, 1);
2096 if ((ret == 0) && (val != NULL)) {
2097 v = xmlSchemaNewValue(XML_SCHEMAS_NCNAME);
2098 if (v != NULL) {
2099 v->value.str = xmlStrdup(value);
2100 *val = v;
2101 } else {
2102 goto error;
2103 }
2104 }
2105 goto done;
2106 case XML_SCHEMAS_ID:
2107 ret = xmlValidateNCName(value, 1);
2108 if ((ret == 0) && (val != NULL)) {
2109 v = xmlSchemaNewValue(XML_SCHEMAS_ID);
2110 if (v != NULL) {
2111 v->value.str = xmlStrdup(value);
2112 *val = v;
2113 } else {
2114 goto error;
2115 }
2116 }
2117 if ((ret == 0) && (node != NULL) &&
2118 (node->type == XML_ATTRIBUTE_NODE)) {
2119 xmlAttrPtr attr = (xmlAttrPtr) node;
2120
2121 /*
2122 * NOTE: the IDness might have already be declared in the DTD
2123 */
2124 if (attr->atype != XML_ATTRIBUTE_ID) {
2125 xmlIDPtr res;
2126 xmlChar *strip;
2127
2128 strip = xmlSchemaStrip(value);
2129 if (strip != NULL) {
2130 res = xmlAddID(NULL, node->doc, strip, attr);
2131 xmlFree(strip);
2132 } else
2133 res = xmlAddID(NULL, node->doc, value, attr);
2134 if (res == NULL) {
2135 ret = 2;
2136 } else {
2137 attr->atype = XML_ATTRIBUTE_ID;
2138 }
2139 }
2140 }
2141 goto done;
2142 case XML_SCHEMAS_IDREF:
2143 ret = xmlValidateNCName(value, 1);
2144 if ((ret == 0) && (val != NULL)) {
2145 TODO;
2146 }
2147 if ((ret == 0) && (node != NULL) &&
2148 (node->type == XML_ATTRIBUTE_NODE)) {
2149 xmlAttrPtr attr = (xmlAttrPtr) node;
2150 xmlChar *strip;
2151
2152 strip = xmlSchemaStrip(value);
2153 if (strip != NULL) {
2154 xmlAddRef(NULL, node->doc, strip, attr);
2155 xmlFree(strip);
2156 } else
2157 xmlAddRef(NULL, node->doc, value, attr);
2158 attr->atype = XML_ATTRIBUTE_IDREF;
2159 }
2160 goto done;
2161 case XML_SCHEMAS_IDREFS:
2162 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeIdrefDef,
2163 value, val, node);
2164 if (ret < 0)
2165 ret = 2;
2166 else
2167 ret = 0;
2168 if ((ret == 0) && (node != NULL) &&
2169 (node->type == XML_ATTRIBUTE_NODE)) {
2170 xmlAttrPtr attr = (xmlAttrPtr) node;
2171
2172 attr->atype = XML_ATTRIBUTE_IDREFS;
2173 }
2174 goto done;
2175 case XML_SCHEMAS_ENTITY:{
2176 xmlChar *strip;
2177
2178 ret = xmlValidateNCName(value, 1);
2179 if ((node == NULL) || (node->doc == NULL))
2180 ret = 3;
2181 if (ret == 0) {
2182 xmlEntityPtr ent;
2183
2184 strip = xmlSchemaStrip(value);
2185 if (strip != NULL) {
2186 ent = xmlGetDocEntity(node->doc, strip);
2187 xmlFree(strip);
2188 } else {
2189 ent = xmlGetDocEntity(node->doc, value);
2190 }
2191 if ((ent == NULL) ||
2192 (ent->etype !=
2193 XML_EXTERNAL_GENERAL_UNPARSED_ENTITY))
2194 ret = 4;
2195 }
2196 if ((ret == 0) && (val != NULL)) {
2197 TODO;
2198 }
2199 if ((ret == 0) && (node != NULL) &&
2200 (node->type == XML_ATTRIBUTE_NODE)) {
2201 xmlAttrPtr attr = (xmlAttrPtr) node;
2202
2203 attr->atype = XML_ATTRIBUTE_ENTITY;
2204 }
2205 goto done;
2206 }
2207 case XML_SCHEMAS_ENTITIES:
2208 if ((node == NULL) || (node->doc == NULL))
2209 goto return3;
2210 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeEntityDef,
2211 value, val, node);
2212 if (ret <= 0)
2213 ret = 1;
2214 else
2215 ret = 0;
2216 if ((ret == 0) && (node != NULL) &&
2217 (node->type == XML_ATTRIBUTE_NODE)) {
2218 xmlAttrPtr attr = (xmlAttrPtr) node;
2219
2220 attr->atype = XML_ATTRIBUTE_ENTITIES;
2221 }
2222 goto done;
2223 case XML_SCHEMAS_NOTATION:{
2224 xmlChar *uri = NULL;
2225 xmlChar *local = NULL;
2226
2227 ret = xmlValidateQName(value, 1);
2228 if ((ret == 0) && (node != NULL)) {
2229 xmlChar *prefix;
2230
2231 local = xmlSplitQName2(value, &prefix);
2232 if (prefix != NULL) {
2233 xmlNsPtr ns;
2234
2235 ns = xmlSearchNs(node->doc, node, prefix);
2236 if (ns == NULL)
2237 ret = 1;
2238 else if (val != NULL)
2239 uri = xmlStrdup(ns->href);
2240 }
2241 if ((local != NULL) && ((val == NULL) || (ret != 0)))
2242 xmlFree(local);
2243 if (prefix != NULL)
2244 xmlFree(prefix);
2245 }
2246 if ((node == NULL) || (node->doc == NULL))
2247 ret = 3;
2248 if (ret == 0) {
2249 ret = xmlValidateNotationUse(NULL, node->doc, value);
2250 if (ret == 1)
2251 ret = 0;
2252 else
2253 ret = 1;
2254 }
2255 if ((ret == 0) && (val != NULL)) {
2256 v = xmlSchemaNewValue(XML_SCHEMAS_NOTATION);
2257 if (v != NULL) {
2258 if (local != NULL)
2259 v->value.qname.name = local;
2260 else
2261 v->value.qname.name = xmlStrdup(value);
2262 if (uri != NULL)
2263 v->value.qname.uri = uri;
2264
2265 *val = v;
2266 } else {
2267 if (local != NULL)
2268 xmlFree(local);
2269 if (uri != NULL)
2270 xmlFree(uri);
2271 goto error;
2272 }
2273 }
2274 goto done;
2275 }
2276 case XML_SCHEMAS_ANYURI:{
Daniel Veillard11c466a2004-03-14 12:20:15 +00002277 if (*value != 0) {
2278 xmlURIPtr uri = xmlParseURI((const char *) value);
2279 if (uri == NULL)
2280 goto return1;
2281 xmlFreeURI(uri);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002282 }
Daniel Veillard11c466a2004-03-14 12:20:15 +00002283
2284 if (val != NULL) {
2285 v = xmlSchemaNewValue(XML_SCHEMAS_ANYURI);
2286 if (v == NULL)
2287 goto error;
2288 v->value.str = xmlStrdup(value);
2289 *val = v;
2290 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002291 goto return0;
2292 }
2293 case XML_SCHEMAS_HEXBINARY:{
2294 const xmlChar *cur = value;
2295 xmlChar *base;
2296 int total, i = 0;
2297
2298 if (cur == NULL)
2299 goto return1;
2300
2301 while (((*cur >= '0') && (*cur <= '9')) ||
2302 ((*cur >= 'A') && (*cur <= 'F')) ||
2303 ((*cur >= 'a') && (*cur <= 'f'))) {
2304 i++;
2305 cur++;
2306 }
2307
2308 if (*cur != 0)
2309 goto return1;
2310 if ((i % 2) != 0)
2311 goto return1;
2312
2313 if (val != NULL) {
2314
2315 v = xmlSchemaNewValue(XML_SCHEMAS_HEXBINARY);
2316 if (v == NULL)
2317 goto error;
2318
2319 cur = xmlStrdup(value);
2320 if (cur == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002321 xmlSchemaTypeErrMemory(node, "allocating hexbin data");
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002322 xmlFree(v);
2323 goto return1;
2324 }
2325
2326 total = i / 2; /* number of octets */
2327
2328 base = (xmlChar *) cur;
2329 while (i-- > 0) {
2330 if (*base >= 'a')
2331 *base = *base - ('a' - 'A');
2332 base++;
2333 }
2334
2335 v->value.hex.str = (xmlChar *) cur;
2336 v->value.hex.total = total;
2337 *val = v;
2338 }
2339 goto return0;
2340 }
2341 case XML_SCHEMAS_BASE64BINARY:{
2342 /* ISSUE:
2343 *
2344 * Ignore all stray characters? (yes, currently)
2345 * Worry about long lines? (no, currently)
2346 *
2347 * rfc2045.txt:
2348 *
2349 * "The encoded output stream must be represented in lines of
2350 * no more than 76 characters each. All line breaks or other
2351 * characters not found in Table 1 must be ignored by decoding
2352 * software. In base64 data, characters other than those in
2353 * Table 1, line breaks, and other white space probably
2354 * indicate a transmission error, about which a warning
2355 * message or even a message rejection might be appropriate
2356 * under some circumstances." */
2357 const xmlChar *cur = value;
2358 xmlChar *base;
2359 int total, i = 0, pad = 0;
2360
2361 if (cur == NULL)
2362 goto return1;
2363
2364 for (; *cur; ++cur) {
2365 int decc;
2366
2367 decc = _xmlSchemaBase64Decode(*cur);
2368 if (decc < 0) ;
2369 else if (decc < 64)
2370 i++;
2371 else
2372 break;
2373 }
2374 for (; *cur; ++cur) {
2375 int decc;
2376
2377 decc = _xmlSchemaBase64Decode(*cur);
2378 if (decc < 0) ;
2379 else if (decc < 64)
2380 goto return1;
2381 if (decc == 64)
2382 pad++;
2383 }
2384
2385 /* rfc2045.txt: "Special processing is performed if fewer than
2386 * 24 bits are available at the end of the data being encoded.
2387 * A full encoding quantum is always completed at the end of a
2388 * body. When fewer than 24 input bits are available in an
2389 * input group, zero bits are added (on the right) to form an
2390 * integral number of 6-bit groups. Padding at the end of the
2391 * data is performed using the "=" character. Since all
2392 * base64 input is an integral number of octets, only the
2393 * following cases can arise: (1) the final quantum of
2394 * encoding input is an integral multiple of 24 bits; here,
2395 * the final unit of encoded output will be an integral
2396 * multiple ofindent: Standard input:701: Warning:old style
2397 * assignment ambiguity in "=*". Assuming "= *" 4 characters
2398 * with no "=" padding, (2) the final
2399 * quantum of encoding input is exactly 8 bits; here, the
2400 * final unit of encoded output will be two characters
2401 * followed by two "=" padding characters, or (3) the final
2402 * quantum of encoding input is exactly 16 bits; here, the
2403 * final unit of encoded output will be three characters
2404 * followed by one "=" padding character." */
2405
2406 total = 3 * (i / 4);
2407 if (pad == 0) {
2408 if (i % 4 != 0)
2409 goto return1;
2410 } else if (pad == 1) {
2411 int decc;
2412
2413 if (i % 4 != 3)
2414 goto return1;
2415 for (decc = _xmlSchemaBase64Decode(*cur);
2416 (decc < 0) || (decc > 63);
2417 decc = _xmlSchemaBase64Decode(*cur))
2418 --cur;
2419 /* 16bits in 24bits means 2 pad bits: nnnnnn nnmmmm mmmm00*/
2420 /* 00111100 -> 0x3c */
2421 if (decc & ~0x3c)
2422 goto return1;
2423 total += 2;
2424 } else if (pad == 2) {
2425 int decc;
2426
2427 if (i % 4 != 2)
2428 goto return1;
2429 for (decc = _xmlSchemaBase64Decode(*cur);
2430 (decc < 0) || (decc > 63);
2431 decc = _xmlSchemaBase64Decode(*cur))
2432 --cur;
2433 /* 8bits in 12bits means 4 pad bits: nnnnnn nn0000 */
2434 /* 00110000 -> 0x30 */
2435 if (decc & ~0x30)
2436 goto return1;
2437 total += 1;
2438 } else
2439 goto return1;
2440
2441 if (val != NULL) {
2442 v = xmlSchemaNewValue(XML_SCHEMAS_BASE64BINARY);
2443 if (v == NULL)
2444 goto error;
2445 base =
2446 (xmlChar *) xmlMallocAtomic((i + pad + 1) *
2447 sizeof(xmlChar));
2448 if (base == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002449 xmlSchemaTypeErrMemory(node, "allocating base64 data");
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002450 xmlFree(v);
2451 goto return1;
2452 }
2453 v->value.base64.str = base;
2454 for (cur = value; *cur; ++cur)
2455 if (_xmlSchemaBase64Decode(*cur) >= 0) {
2456 *base = *cur;
2457 ++base;
2458 }
2459 *base = 0;
2460 v->value.base64.total = total;
2461 *val = v;
2462 }
2463 goto return0;
2464 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002465 case XML_SCHEMAS_INTEGER:
2466 case XML_SCHEMAS_PINTEGER:
2467 case XML_SCHEMAS_NPINTEGER:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002468 case XML_SCHEMAS_NINTEGER:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002469 case XML_SCHEMAS_NNINTEGER:{
2470 const xmlChar *cur = value;
2471 unsigned long lo, mi, hi;
2472 int sign = 0;
2473
2474 if (cur == NULL)
2475 goto return1;
2476 if (*cur == '-') {
2477 sign = 1;
2478 cur++;
2479 } else if (*cur == '+')
2480 cur++;
2481 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2482 if (ret == 0)
2483 goto return1;
2484 if (*cur != 0)
2485 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002486 if (type->builtInType == XML_SCHEMAS_NPINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002487 if ((sign == 0) &&
2488 ((hi != 0) || (mi != 0) || (lo != 0)))
2489 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002490 } else if (type->builtInType == XML_SCHEMAS_PINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002491 if (sign == 1)
2492 goto return1;
2493 if ((hi == 0) && (mi == 0) && (lo == 0))
2494 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002495 } else if (type->builtInType == XML_SCHEMAS_NINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002496 if (sign == 0)
2497 goto return1;
2498 if ((hi == 0) && (mi == 0) && (lo == 0))
2499 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002500 } else if (type->builtInType == XML_SCHEMAS_NNINTEGER) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002501 if ((sign == 1) &&
2502 ((hi != 0) || (mi != 0) || (lo != 0)))
2503 goto return1;
2504 }
2505 /*
2506 * We can store a value only if no overflow occured
2507 */
2508 if ((ret > 0) && (val != NULL)) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00002509 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002510 if (v != NULL) {
2511 v->value.decimal.lo = lo;
2512 v->value.decimal.mi = lo;
2513 v->value.decimal.hi = lo;
2514 v->value.decimal.sign = sign;
2515 v->value.decimal.frac = 0;
2516 v->value.decimal.total = cur - value;
2517 *val = v;
2518 }
2519 }
2520 goto return0;
2521 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002522 case XML_SCHEMAS_LONG:
2523 case XML_SCHEMAS_BYTE:
2524 case XML_SCHEMAS_SHORT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002525 case XML_SCHEMAS_INT:{
2526 const xmlChar *cur = value;
2527 unsigned long lo, mi, hi;
2528 int total = 0;
2529 int sign = 0;
2530
2531 if (cur == NULL)
2532 goto return1;
2533 if (*cur == '-') {
2534 sign = 1;
2535 cur++;
2536 } else if (*cur == '+')
2537 cur++;
2538 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2539 if (ret <= 0)
2540 goto return1;
2541 if (*cur != 0)
2542 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002543 if (type->builtInType == XML_SCHEMAS_LONG) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002544 if (hi >= 922) {
2545 if (hi > 922)
2546 goto return1;
2547 if (mi >= 33720368) {
2548 if (mi > 33720368)
2549 goto return1;
2550 if ((sign == 0) && (lo > 54775807))
2551 goto return1;
2552 if ((sign == 1) && (lo > 54775808))
2553 goto return1;
2554 }
2555 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002556 } else if (type->builtInType == XML_SCHEMAS_INT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002557 if (hi != 0)
2558 goto return1;
2559 if (mi >= 21) {
2560 if (mi > 21)
2561 goto return1;
2562 if ((sign == 0) && (lo > 47483647))
2563 goto return1;
2564 if ((sign == 1) && (lo > 47483648))
2565 goto return1;
2566 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002567 } else if (type->builtInType == XML_SCHEMAS_SHORT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002568 if ((mi != 0) || (hi != 0))
2569 goto return1;
2570 if ((sign == 1) && (lo > 32768))
2571 goto return1;
2572 if ((sign == 0) && (lo > 32767))
2573 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002574 } else if (type->builtInType == XML_SCHEMAS_BYTE) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002575 if ((mi != 0) || (hi != 0))
2576 goto return1;
2577 if ((sign == 1) && (lo > 128))
2578 goto return1;
2579 if ((sign == 0) && (lo > 127))
2580 goto return1;
2581 }
2582 if (val != NULL) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00002583 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002584 if (v != NULL) {
2585 v->value.decimal.lo = lo;
2586 v->value.decimal.mi = lo;
2587 v->value.decimal.hi = lo;
2588 v->value.decimal.sign = sign;
2589 v->value.decimal.frac = 0;
2590 v->value.decimal.total = total;
2591 *val = v;
2592 }
2593 }
2594 goto return0;
2595 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002596 case XML_SCHEMAS_UINT:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002597 case XML_SCHEMAS_ULONG:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002598 case XML_SCHEMAS_USHORT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002599 case XML_SCHEMAS_UBYTE:{
2600 const xmlChar *cur = value;
2601 unsigned long lo, mi, hi;
2602 int total = 0;
2603
2604 if (cur == NULL)
2605 goto return1;
2606 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2607 if (ret <= 0)
2608 goto return1;
2609 if (*cur != 0)
2610 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002611 if (type->builtInType == XML_SCHEMAS_ULONG) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002612 if (hi >= 1844) {
2613 if (hi > 1844)
2614 goto return1;
2615 if (mi >= 67440737) {
2616 if (mi > 67440737)
2617 goto return1;
2618 if (lo > 9551615)
2619 goto return1;
2620 }
2621 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002622 } else if (type->builtInType == XML_SCHEMAS_UINT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002623 if (hi != 0)
2624 goto return1;
2625 if (mi >= 42) {
2626 if (mi > 42)
2627 goto return1;
2628 if (lo > 94967295)
2629 goto return1;
2630 }
Daniel Veillard01fa6152004-06-29 17:04:39 +00002631 } else if (type->builtInType == XML_SCHEMAS_USHORT) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002632 if ((mi != 0) || (hi != 0))
2633 goto return1;
2634 if (lo > 65535)
2635 goto return1;
Daniel Veillard01fa6152004-06-29 17:04:39 +00002636 } else if (type->builtInType == XML_SCHEMAS_UBYTE) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002637 if ((mi != 0) || (hi != 0))
2638 goto return1;
2639 if (lo > 255)
2640 goto return1;
2641 }
2642 if (val != NULL) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00002643 v = xmlSchemaNewValue(type->builtInType);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002644 if (v != NULL) {
2645 v->value.decimal.lo = lo;
2646 v->value.decimal.mi = mi;
2647 v->value.decimal.hi = hi;
2648 v->value.decimal.sign = 0;
2649 v->value.decimal.frac = 0;
2650 v->value.decimal.total = total;
2651 *val = v;
2652 }
2653 }
2654 goto return0;
2655 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002656 }
2657
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002658 done:
2659 if (norm != NULL)
2660 xmlFree(norm);
2661 return (ret);
2662 return3:
2663 if (norm != NULL)
2664 xmlFree(norm);
2665 return (3);
2666 return1:
2667 if (norm != NULL)
2668 xmlFree(norm);
2669 return (1);
2670 return0:
2671 if (norm != NULL)
2672 xmlFree(norm);
2673 return (0);
2674 error:
2675 if (norm != NULL)
2676 xmlFree(norm);
2677 return (-1);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002678}
2679
2680/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002681 * xmlSchemaValPredefTypeNode:
Daniel Veillard4255d502002-04-16 15:50:10 +00002682 * @type: the predefined type
2683 * @value: the value to check
2684 * @val: the return computed value
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002685 * @node: the node containing the value
Daniel Veillard4255d502002-04-16 15:50:10 +00002686 *
2687 * Check that a value conforms to the lexical space of the predefined type.
2688 * if true a value is computed and returned in @val.
2689 *
2690 * Returns 0 if this validates, a positive error code number otherwise
2691 * and -1 in case of internal or API error.
2692 */
2693int
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002694xmlSchemaValPredefTypeNode(xmlSchemaTypePtr type, const xmlChar *value,
2695 xmlSchemaValPtr *val, xmlNodePtr node) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002696 return(xmlSchemaValAtomicType(type, value, val, node, 0));
Daniel Veillard4255d502002-04-16 15:50:10 +00002697}
2698
2699/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002700 * xmlSchemaValidatePredefinedType:
2701 * @type: the predefined type
2702 * @value: the value to check
2703 * @val: the return computed value
2704 *
2705 * Check that a value conforms to the lexical space of the predefined type.
2706 * if true a value is computed and returned in @val.
2707 *
2708 * Returns 0 if this validates, a positive error code number otherwise
2709 * and -1 in case of internal or API error.
2710 */
2711int
2712xmlSchemaValidatePredefinedType(xmlSchemaTypePtr type, const xmlChar *value,
2713 xmlSchemaValPtr *val) {
2714 return(xmlSchemaValPredefTypeNode(type, value, val, NULL));
2715}
2716
2717/**
Daniel Veillard4255d502002-04-16 15:50:10 +00002718 * xmlSchemaCompareDecimals:
2719 * @x: a first decimal value
2720 * @y: a second decimal value
2721 *
2722 * Compare 2 decimals
2723 *
2724 * Returns -1 if x < y, 0 if x == y, 1 if x > y and -2 in case of error
2725 */
2726static int
2727xmlSchemaCompareDecimals(xmlSchemaValPtr x, xmlSchemaValPtr y)
2728{
2729 xmlSchemaValPtr swp;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002730 int order = 1, p;
Daniel Veillard4255d502002-04-16 15:50:10 +00002731 unsigned long tmp;
2732
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002733 if ((x->value.decimal.sign) &&
2734 ((x->value.decimal.lo != 0) ||
2735 (x->value.decimal.mi != 0) ||
2736 (x->value.decimal.hi != 0))) {
2737 if ((y->value.decimal.sign) &&
2738 ((y->value.decimal.lo != 0) ||
2739 (y->value.decimal.mi != 0) ||
2740 (y->value.decimal.hi != 0)))
Daniel Veillard80b19092003-03-28 13:29:53 +00002741 order = -1;
2742 else
2743 return (-1);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002744 } else if ((y->value.decimal.sign) &&
2745 ((y->value.decimal.lo != 0) ||
2746 (y->value.decimal.mi != 0) ||
2747 (y->value.decimal.hi != 0))) {
Daniel Veillard4255d502002-04-16 15:50:10 +00002748 return (1);
Daniel Veillard80b19092003-03-28 13:29:53 +00002749 }
Daniel Veillard4255d502002-04-16 15:50:10 +00002750 if (x->value.decimal.frac == y->value.decimal.frac) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002751 if (x->value.decimal.hi < y->value.decimal.hi)
2752 return (-order);
Daniel Veillard01fa6152004-06-29 17:04:39 +00002753 if (x->value.decimal.hi > y->value.decimal.hi)
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002754 return (order);
2755 if (x->value.decimal.mi < y->value.decimal.mi)
2756 return (-order);
Daniel Veillard01fa6152004-06-29 17:04:39 +00002757 if (x->value.decimal.mi > y->value.decimal.mi)
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002758 return (order);
2759 if (x->value.decimal.lo < y->value.decimal.lo)
Daniel Veillard80b19092003-03-28 13:29:53 +00002760 return (-order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002761 if (x->value.decimal.lo > y->value.decimal.lo)
Daniel Veillard80b19092003-03-28 13:29:53 +00002762 return(order);
2763 return(0);
Daniel Veillard4255d502002-04-16 15:50:10 +00002764 }
2765 if (y->value.decimal.frac > x->value.decimal.frac) {
2766 swp = y;
2767 y = x;
2768 x = swp;
2769 order = -order;
2770 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002771 p = powten[x->value.decimal.frac - y->value.decimal.frac];
2772 tmp = x->value.decimal.lo / p;
2773 if (tmp > y->value.decimal.lo)
Daniel Veillard4255d502002-04-16 15:50:10 +00002774 return (order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002775 if (tmp < y->value.decimal.lo)
Daniel Veillard4255d502002-04-16 15:50:10 +00002776 return (-order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002777 tmp = y->value.decimal.lo * p;
2778 if (x->value.decimal.lo < tmp)
Daniel Veillard4255d502002-04-16 15:50:10 +00002779 return (-order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002780 if (x->value.decimal.lo == tmp)
Daniel Veillard4255d502002-04-16 15:50:10 +00002781 return (0);
2782 return (order);
2783}
2784
2785/**
Daniel Veillard070803b2002-05-03 07:29:38 +00002786 * xmlSchemaCompareDurations:
2787 * @x: a first duration value
2788 * @y: a second duration value
2789 *
2790 * Compare 2 durations
2791 *
2792 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
2793 * case of error
2794 */
2795static int
2796xmlSchemaCompareDurations(xmlSchemaValPtr x, xmlSchemaValPtr y)
2797{
2798 long carry, mon, day;
2799 double sec;
Daniel Veillard80b19092003-03-28 13:29:53 +00002800 int invert = 1;
2801 long xmon, xday, myear, minday, maxday;
Daniel Veillard070803b2002-05-03 07:29:38 +00002802 static const long dayRange [2][12] = {
2803 { 0, 28, 59, 89, 120, 150, 181, 212, 242, 273, 303, 334, },
2804 { 0, 31, 62, 92, 123, 153, 184, 215, 245, 276, 306, 337} };
2805
2806 if ((x == NULL) || (y == NULL))
Daniel Veillard5a872412002-05-22 06:40:27 +00002807 return -2;
Daniel Veillard070803b2002-05-03 07:29:38 +00002808
2809 /* months */
2810 mon = x->value.dur.mon - y->value.dur.mon;
2811
2812 /* seconds */
2813 sec = x->value.dur.sec - y->value.dur.sec;
2814 carry = (long)sec / SECS_PER_DAY;
2815 sec -= (double)(carry * SECS_PER_DAY);
2816
2817 /* days */
2818 day = x->value.dur.day - y->value.dur.day + carry;
2819
2820 /* easy test */
2821 if (mon == 0) {
2822 if (day == 0)
2823 if (sec == 0.0)
2824 return 0;
2825 else if (sec < 0.0)
2826 return -1;
2827 else
2828 return 1;
2829 else if (day < 0)
2830 return -1;
2831 else
2832 return 1;
2833 }
2834
2835 if (mon > 0) {
2836 if ((day >= 0) && (sec >= 0.0))
2837 return 1;
2838 else {
2839 xmon = mon;
2840 xday = -day;
2841 }
2842 } else if ((day <= 0) && (sec <= 0.0)) {
2843 return -1;
2844 } else {
Daniel Veillard80b19092003-03-28 13:29:53 +00002845 invert = -1;
Daniel Veillard070803b2002-05-03 07:29:38 +00002846 xmon = -mon;
2847 xday = day;
2848 }
2849
2850 myear = xmon / 12;
Daniel Veillard80b19092003-03-28 13:29:53 +00002851 if (myear == 0) {
2852 minday = 0;
2853 maxday = 0;
2854 } else {
2855 maxday = 366 * ((myear + 3) / 4) +
2856 365 * ((myear - 1) % 4);
2857 minday = maxday - 1;
2858 }
2859
Daniel Veillard070803b2002-05-03 07:29:38 +00002860 xmon = xmon % 12;
2861 minday += dayRange[0][xmon];
2862 maxday += dayRange[1][xmon];
2863
Daniel Veillard80b19092003-03-28 13:29:53 +00002864 if ((maxday == minday) && (maxday == xday))
2865 return(0); /* can this really happen ? */
Daniel Veillard070803b2002-05-03 07:29:38 +00002866 if (maxday < xday)
Daniel Veillard80b19092003-03-28 13:29:53 +00002867 return(-invert);
2868 if (minday > xday)
2869 return(invert);
Daniel Veillard070803b2002-05-03 07:29:38 +00002870
2871 /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00002872 return 2;
2873}
2874
2875/*
2876 * macros for adding date/times and durations
2877 */
2878#define FQUOTIENT(a,b) (floor(((double)a/(double)b)))
2879#define MODULO(a,b) (a - FQUOTIENT(a,b) * b)
2880#define FQUOTIENT_RANGE(a,low,high) (FQUOTIENT((a-low),(high-low)))
2881#define MODULO_RANGE(a,low,high) ((MODULO((a-low),(high-low)))+low)
2882
2883/**
Daniel Veillard669adfc2004-05-29 20:12:46 +00002884 * xmlSchemaDupVal:
2885 * @v: the #xmlSchemaValPtr value to duplicate
2886 *
2887 * Makes a copy of @v. The calling program is responsible for freeing
2888 * the returned value.
2889 *
2890 * returns a pointer to a duplicated #xmlSchemaValPtr or NULL if error.
2891 */
2892static xmlSchemaValPtr
2893xmlSchemaDupVal (xmlSchemaValPtr v)
2894{
2895 xmlSchemaValPtr ret = xmlSchemaNewValue(v->type);
2896 if (ret == NULL)
2897 return NULL;
2898
2899 memcpy(ret, v, sizeof(xmlSchemaVal));
2900 return ret;
2901}
2902
2903/**
Daniel Veillard5a872412002-05-22 06:40:27 +00002904 * _xmlSchemaDateAdd:
2905 * @dt: an #xmlSchemaValPtr
2906 * @dur: an #xmlSchemaValPtr of type #XS_DURATION
2907 *
2908 * Compute a new date/time from @dt and @dur. This function assumes @dt
2909 * is either #XML_SCHEMAS_DATETIME, #XML_SCHEMAS_DATE, #XML_SCHEMAS_GYEARMONTH,
Daniel Veillard669adfc2004-05-29 20:12:46 +00002910 * or #XML_SCHEMAS_GYEAR. The returned #xmlSchemaVal is the same type as
2911 * @dt. The calling program is responsible for freeing the returned value.
Daniel Veillard5a872412002-05-22 06:40:27 +00002912 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00002913 * Returns a pointer to a new #xmlSchemaVal or NULL if error.
Daniel Veillard5a872412002-05-22 06:40:27 +00002914 */
2915static xmlSchemaValPtr
2916_xmlSchemaDateAdd (xmlSchemaValPtr dt, xmlSchemaValPtr dur)
2917{
Daniel Veillard669adfc2004-05-29 20:12:46 +00002918 xmlSchemaValPtr ret, tmp;
Daniel Veillard5a872412002-05-22 06:40:27 +00002919 long carry, tempdays, temp;
2920 xmlSchemaValDatePtr r, d;
2921 xmlSchemaValDurationPtr u;
2922
2923 if ((dt == NULL) || (dur == NULL))
2924 return NULL;
2925
2926 ret = xmlSchemaNewValue(dt->type);
2927 if (ret == NULL)
2928 return NULL;
2929
Daniel Veillard669adfc2004-05-29 20:12:46 +00002930 /* make a copy so we don't alter the original value */
2931 tmp = xmlSchemaDupVal(dt);
2932 if (tmp == NULL) {
2933 xmlSchemaFreeValue(ret);
2934 return NULL;
2935 }
2936
Daniel Veillard5a872412002-05-22 06:40:27 +00002937 r = &(ret->value.date);
Daniel Veillard669adfc2004-05-29 20:12:46 +00002938 d = &(tmp->value.date);
Daniel Veillard5a872412002-05-22 06:40:27 +00002939 u = &(dur->value.dur);
2940
2941 /* normalization */
2942 if (d->mon == 0)
2943 d->mon = 1;
2944
2945 /* normalize for time zone offset */
2946 u->sec -= (d->tzo * 60);
2947 d->tzo = 0;
2948
2949 /* normalization */
2950 if (d->day == 0)
2951 d->day = 1;
2952
2953 /* month */
2954 carry = d->mon + u->mon;
Daniel Veillardebe25d42004-03-25 09:35:49 +00002955 r->mon = (unsigned int) MODULO_RANGE(carry, 1, 13);
2956 carry = (long) FQUOTIENT_RANGE(carry, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00002957
2958 /* year (may be modified later) */
2959 r->year = d->year + carry;
2960 if (r->year == 0) {
2961 if (d->year > 0)
2962 r->year--;
2963 else
2964 r->year++;
2965 }
2966
2967 /* time zone */
2968 r->tzo = d->tzo;
2969 r->tz_flag = d->tz_flag;
2970
2971 /* seconds */
2972 r->sec = d->sec + u->sec;
Daniel Veillardebe25d42004-03-25 09:35:49 +00002973 carry = (long) FQUOTIENT((long)r->sec, 60);
Daniel Veillard5a872412002-05-22 06:40:27 +00002974 if (r->sec != 0.0) {
2975 r->sec = MODULO(r->sec, 60.0);
2976 }
2977
2978 /* minute */
2979 carry += d->min;
Daniel Veillardebe25d42004-03-25 09:35:49 +00002980 r->min = (unsigned int) MODULO(carry, 60);
2981 carry = (long) FQUOTIENT(carry, 60);
Daniel Veillard5a872412002-05-22 06:40:27 +00002982
2983 /* hours */
2984 carry += d->hour;
Daniel Veillardebe25d42004-03-25 09:35:49 +00002985 r->hour = (unsigned int) MODULO(carry, 24);
2986 carry = (long)FQUOTIENT(carry, 24);
Daniel Veillard5a872412002-05-22 06:40:27 +00002987
2988 /*
2989 * days
2990 * Note we use tempdays because the temporary values may need more
2991 * than 5 bits
2992 */
2993 if ((VALID_YEAR(r->year)) && (VALID_MONTH(r->mon)) &&
2994 (d->day > MAX_DAYINMONTH(r->year, r->mon)))
2995 tempdays = MAX_DAYINMONTH(r->year, r->mon);
2996 else if (d->day < 1)
2997 tempdays = 1;
2998 else
2999 tempdays = d->day;
3000
3001 tempdays += u->day + carry;
3002
3003 while (1) {
3004 if (tempdays < 1) {
Daniel Veillardebe25d42004-03-25 09:35:49 +00003005 long tmon = (long) MODULO_RANGE(r->mon-1, 1, 13);
3006 long tyr = r->year + (long)FQUOTIENT_RANGE(r->mon-1, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00003007 if (tyr == 0)
3008 tyr--;
3009 tempdays += MAX_DAYINMONTH(tyr, tmon);
3010 carry = -1;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003011 } else if (tempdays > (long) MAX_DAYINMONTH(r->year, r->mon)) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003012 tempdays = tempdays - MAX_DAYINMONTH(r->year, r->mon);
3013 carry = 1;
3014 } else
3015 break;
3016
3017 temp = r->mon + carry;
Daniel Veillardebe25d42004-03-25 09:35:49 +00003018 r->mon = (unsigned int) MODULO_RANGE(temp, 1, 13);
3019 r->year = r->year + (unsigned int) FQUOTIENT_RANGE(temp, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00003020 if (r->year == 0) {
3021 if (temp < 1)
3022 r->year--;
3023 else
3024 r->year++;
3025 }
3026 }
3027
3028 r->day = tempdays;
3029
3030 /*
3031 * adjust the date/time type to the date values
3032 */
3033 if (ret->type != XML_SCHEMAS_DATETIME) {
3034 if ((r->hour) || (r->min) || (r->sec))
3035 ret->type = XML_SCHEMAS_DATETIME;
3036 else if (ret->type != XML_SCHEMAS_DATE) {
3037 if ((r->mon != 1) && (r->day != 1))
3038 ret->type = XML_SCHEMAS_DATE;
3039 else if ((ret->type != XML_SCHEMAS_GYEARMONTH) && (r->mon != 1))
3040 ret->type = XML_SCHEMAS_GYEARMONTH;
3041 }
3042 }
3043
Daniel Veillard669adfc2004-05-29 20:12:46 +00003044 xmlSchemaFreeValue(tmp);
Daniel Veillard5a872412002-05-22 06:40:27 +00003045
Daniel Veillard5a872412002-05-22 06:40:27 +00003046 return ret;
3047}
3048
3049/**
3050 * xmlSchemaDateNormalize:
Daniel Veillard669adfc2004-05-29 20:12:46 +00003051 * @dt: an #xmlSchemaValPtr of a date/time type value.
3052 * @offset: number of seconds to adjust @dt by.
Daniel Veillard5a872412002-05-22 06:40:27 +00003053 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00003054 * Normalize @dt to GMT time. The @offset parameter is subtracted from
3055 * the return value is a time-zone offset is present on @dt.
Daniel Veillard5a872412002-05-22 06:40:27 +00003056 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00003057 * Returns a normalized copy of @dt or NULL if error.
Daniel Veillard5a872412002-05-22 06:40:27 +00003058 */
3059static xmlSchemaValPtr
3060xmlSchemaDateNormalize (xmlSchemaValPtr dt, double offset)
3061{
3062 xmlSchemaValPtr dur, ret;
3063
3064 if (dt == NULL)
3065 return NULL;
3066
3067 if (((dt->type != XML_SCHEMAS_TIME) &&
3068 (dt->type != XML_SCHEMAS_DATETIME)) || (dt->value.date.tzo == 0))
3069 return xmlSchemaDupVal(dt);
3070
3071 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
3072 if (dur == NULL)
3073 return NULL;
3074
3075 dur->value.date.sec -= offset;
3076
3077 ret = _xmlSchemaDateAdd(dt, dur);
3078 if (ret == NULL)
3079 return NULL;
3080
3081 xmlSchemaFreeValue(dur);
3082
3083 /* ret->value.date.tzo = 0; */
3084 return ret;
3085}
3086
3087/**
3088 * _xmlSchemaDateCastYMToDays:
3089 * @dt: an #xmlSchemaValPtr
3090 *
3091 * Convert mon and year of @dt to total number of days. Take the
3092 * number of years since (or before) 1 AD and add the number of leap
3093 * years. This is a function because negative
3094 * years must be handled a little differently and there is no zero year.
3095 *
3096 * Returns number of days.
3097 */
3098static long
3099_xmlSchemaDateCastYMToDays (const xmlSchemaValPtr dt)
3100{
3101 long ret;
3102
3103 if (dt->value.date.year < 0)
3104 ret = (dt->value.date.year * 365) +
3105 (((dt->value.date.year+1)/4)-((dt->value.date.year+1)/100)+
3106 ((dt->value.date.year+1)/400)) +
3107 DAY_IN_YEAR(0, dt->value.date.mon, dt->value.date.year);
3108 else
3109 ret = ((dt->value.date.year-1) * 365) +
3110 (((dt->value.date.year-1)/4)-((dt->value.date.year-1)/100)+
3111 ((dt->value.date.year-1)/400)) +
3112 DAY_IN_YEAR(0, dt->value.date.mon, dt->value.date.year);
3113
3114 return ret;
3115}
3116
3117/**
3118 * TIME_TO_NUMBER:
3119 * @dt: an #xmlSchemaValPtr
3120 *
3121 * Calculates the number of seconds in the time portion of @dt.
3122 *
3123 * Returns seconds.
3124 */
3125#define TIME_TO_NUMBER(dt) \
3126 ((double)((dt->value.date.hour * SECS_PER_HOUR) + \
Daniel Veillardb3721c22003-03-31 11:22:25 +00003127 (dt->value.date.min * SECS_PER_MIN) + \
3128 (dt->value.date.tzo * SECS_PER_MIN)) + \
3129 dt->value.date.sec)
Daniel Veillard5a872412002-05-22 06:40:27 +00003130
3131/**
3132 * xmlSchemaCompareDates:
3133 * @x: a first date/time value
3134 * @y: a second date/time value
3135 *
3136 * Compare 2 date/times
3137 *
3138 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3139 * case of error
3140 */
3141static int
3142xmlSchemaCompareDates (xmlSchemaValPtr x, xmlSchemaValPtr y)
3143{
3144 unsigned char xmask, ymask, xor_mask, and_mask;
3145 xmlSchemaValPtr p1, p2, q1, q2;
3146 long p1d, p2d, q1d, q2d;
3147
3148 if ((x == NULL) || (y == NULL))
3149 return -2;
3150
3151 if (x->value.date.tz_flag) {
3152
3153 if (!y->value.date.tz_flag) {
3154 p1 = xmlSchemaDateNormalize(x, 0);
3155 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3156 /* normalize y + 14:00 */
3157 q1 = xmlSchemaDateNormalize(y, (14 * SECS_PER_HOUR));
3158
3159 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003160 if (p1d < q1d) {
3161 xmlSchemaFreeValue(p1);
3162 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003163 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003164 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003165 double sec;
3166
3167 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00003168 if (sec < 0.0) {
3169 xmlSchemaFreeValue(p1);
3170 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003171 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003172 } else {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003173 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003174 /* normalize y - 14:00 */
3175 q2 = xmlSchemaDateNormalize(y, -(14 * SECS_PER_HOUR));
3176 q2d = _xmlSchemaDateCastYMToDays(q2) + q2->value.date.day;
3177 if (p1d > q2d)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003178 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003179 else if (p1d == q2d) {
3180 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q2);
3181 if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003182 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003183 else
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003184 ret = 2; /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00003185 }
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003186 xmlSchemaFreeValue(p1);
3187 xmlSchemaFreeValue(q1);
3188 xmlSchemaFreeValue(q2);
3189 if (ret != 0)
3190 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003191 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00003192 } else {
3193 xmlSchemaFreeValue(p1);
3194 xmlSchemaFreeValue(q1);
3195 }
Daniel Veillard5a872412002-05-22 06:40:27 +00003196 }
3197 } else if (y->value.date.tz_flag) {
3198 q1 = xmlSchemaDateNormalize(y, 0);
3199 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
3200
3201 /* normalize x - 14:00 */
3202 p1 = xmlSchemaDateNormalize(x, -(14 * SECS_PER_HOUR));
3203 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3204
Daniel Veillardfdc91562002-07-01 21:52:03 +00003205 if (p1d < q1d) {
3206 xmlSchemaFreeValue(p1);
3207 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003208 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003209 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003210 double sec;
3211
3212 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00003213 if (sec < 0.0) {
3214 xmlSchemaFreeValue(p1);
3215 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003216 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003217 } else {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003218 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003219 /* normalize x + 14:00 */
3220 p2 = xmlSchemaDateNormalize(x, (14 * SECS_PER_HOUR));
3221 p2d = _xmlSchemaDateCastYMToDays(p2) + p2->value.date.day;
3222
Daniel Veillard6560a422003-03-27 21:25:38 +00003223 if (p2d > q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003224 ret = 1;
Daniel Veillard6560a422003-03-27 21:25:38 +00003225 } else if (p2d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003226 sec = TIME_TO_NUMBER(p2) - TIME_TO_NUMBER(q1);
3227 if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003228 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003229 else
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003230 ret = 2; /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00003231 }
Daniel Veillard6560a422003-03-27 21:25:38 +00003232 xmlSchemaFreeValue(p1);
3233 xmlSchemaFreeValue(q1);
3234 xmlSchemaFreeValue(p2);
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003235 if (ret != 0)
3236 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003237 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00003238 } else {
3239 xmlSchemaFreeValue(p1);
3240 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00003241 }
3242 }
3243
3244 /*
3245 * if the same type then calculate the difference
3246 */
3247 if (x->type == y->type) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003248 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00003249 q1 = xmlSchemaDateNormalize(y, 0);
3250 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
3251
3252 p1 = xmlSchemaDateNormalize(x, 0);
3253 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3254
Daniel Veillardfdc91562002-07-01 21:52:03 +00003255 if (p1d < q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003256 ret = -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003257 } else if (p1d > q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003258 ret = 1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00003259 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00003260 double sec;
3261
3262 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
3263 if (sec < 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003264 ret = -1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003265 else if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003266 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00003267
3268 }
Daniel Veillard4aede2e2003-10-17 12:43:59 +00003269 xmlSchemaFreeValue(p1);
3270 xmlSchemaFreeValue(q1);
3271 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00003272 }
3273
3274 switch (x->type) {
3275 case XML_SCHEMAS_DATETIME:
3276 xmask = 0xf;
3277 break;
3278 case XML_SCHEMAS_DATE:
3279 xmask = 0x7;
3280 break;
3281 case XML_SCHEMAS_GYEAR:
3282 xmask = 0x1;
3283 break;
3284 case XML_SCHEMAS_GMONTH:
3285 xmask = 0x2;
3286 break;
3287 case XML_SCHEMAS_GDAY:
3288 xmask = 0x3;
3289 break;
3290 case XML_SCHEMAS_GYEARMONTH:
3291 xmask = 0x3;
3292 break;
3293 case XML_SCHEMAS_GMONTHDAY:
3294 xmask = 0x6;
3295 break;
3296 case XML_SCHEMAS_TIME:
3297 xmask = 0x8;
3298 break;
3299 default:
3300 xmask = 0;
3301 break;
3302 }
3303
3304 switch (y->type) {
3305 case XML_SCHEMAS_DATETIME:
3306 ymask = 0xf;
3307 break;
3308 case XML_SCHEMAS_DATE:
3309 ymask = 0x7;
3310 break;
3311 case XML_SCHEMAS_GYEAR:
3312 ymask = 0x1;
3313 break;
3314 case XML_SCHEMAS_GMONTH:
3315 ymask = 0x2;
3316 break;
3317 case XML_SCHEMAS_GDAY:
3318 ymask = 0x3;
3319 break;
3320 case XML_SCHEMAS_GYEARMONTH:
3321 ymask = 0x3;
3322 break;
3323 case XML_SCHEMAS_GMONTHDAY:
3324 ymask = 0x6;
3325 break;
3326 case XML_SCHEMAS_TIME:
3327 ymask = 0x8;
3328 break;
3329 default:
3330 ymask = 0;
3331 break;
3332 }
3333
3334 xor_mask = xmask ^ ymask; /* mark type differences */
3335 and_mask = xmask & ymask; /* mark field specification */
3336
3337 /* year */
3338 if (xor_mask & 1)
3339 return 2; /* indeterminate */
3340 else if (and_mask & 1) {
3341 if (x->value.date.year < y->value.date.year)
3342 return -1;
3343 else if (x->value.date.year > y->value.date.year)
3344 return 1;
3345 }
3346
3347 /* month */
3348 if (xor_mask & 2)
3349 return 2; /* indeterminate */
3350 else if (and_mask & 2) {
3351 if (x->value.date.mon < y->value.date.mon)
3352 return -1;
3353 else if (x->value.date.mon > y->value.date.mon)
3354 return 1;
3355 }
3356
3357 /* day */
3358 if (xor_mask & 4)
3359 return 2; /* indeterminate */
3360 else if (and_mask & 4) {
3361 if (x->value.date.day < y->value.date.day)
3362 return -1;
3363 else if (x->value.date.day > y->value.date.day)
3364 return 1;
3365 }
3366
3367 /* time */
3368 if (xor_mask & 8)
3369 return 2; /* indeterminate */
3370 else if (and_mask & 8) {
3371 if (x->value.date.hour < y->value.date.hour)
3372 return -1;
3373 else if (x->value.date.hour > y->value.date.hour)
3374 return 1;
3375 else if (x->value.date.min < y->value.date.min)
3376 return -1;
3377 else if (x->value.date.min > y->value.date.min)
3378 return 1;
3379 else if (x->value.date.sec < y->value.date.sec)
3380 return -1;
3381 else if (x->value.date.sec > y->value.date.sec)
3382 return 1;
3383 }
3384
Daniel Veillard070803b2002-05-03 07:29:38 +00003385 return 0;
3386}
3387
3388/**
Daniel Veillardc4c21552003-03-29 10:53:38 +00003389 * xmlSchemaCompareNormStrings:
3390 * @x: a first string value
3391 * @y: a second string value
3392 *
3393 * Compare 2 string for their normalized values.
3394 *
3395 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
3396 * case of error
3397 */
3398static int
3399xmlSchemaCompareNormStrings(xmlSchemaValPtr x, xmlSchemaValPtr y) {
3400 const xmlChar *utf1;
3401 const xmlChar *utf2;
3402 int tmp;
3403
3404 if ((x == NULL) || (y == NULL))
3405 return(-2);
3406 utf1 = x->value.str;
3407 utf2 = y->value.str;
3408
William M. Brack76e95df2003-10-18 16:20:14 +00003409 while (IS_BLANK_CH(*utf1)) utf1++;
3410 while (IS_BLANK_CH(*utf2)) utf2++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003411 while ((*utf1 != 0) && (*utf2 != 0)) {
William M. Brack76e95df2003-10-18 16:20:14 +00003412 if (IS_BLANK_CH(*utf1)) {
3413 if (!IS_BLANK_CH(*utf2)) {
Daniel Veillardc4c21552003-03-29 10:53:38 +00003414 tmp = *utf1 - *utf2;
3415 return(tmp);
3416 }
William M. Brack76e95df2003-10-18 16:20:14 +00003417 while (IS_BLANK_CH(*utf1)) utf1++;
3418 while (IS_BLANK_CH(*utf2)) utf2++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003419 } else {
3420 tmp = *utf1++ - *utf2++;
3421 if (tmp < 0)
3422 return(-1);
3423 if (tmp > 0)
3424 return(1);
3425 }
3426 }
3427 if (*utf1 != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00003428 while (IS_BLANK_CH(*utf1)) utf1++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003429 if (*utf1 != 0)
3430 return(1);
3431 }
3432 if (*utf2 != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00003433 while (IS_BLANK_CH(*utf2)) utf2++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003434 if (*utf2 != 0)
3435 return(-1);
3436 }
3437 return(0);
3438}
3439
3440/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003441 * xmlSchemaCompareFloats:
3442 * @x: a first float or double value
3443 * @y: a second float or double value
3444 *
3445 * Compare 2 values
3446 *
3447 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3448 * case of error
3449 */
3450static int
3451xmlSchemaCompareFloats(xmlSchemaValPtr x, xmlSchemaValPtr y) {
3452 double d1, d2;
3453
3454 if ((x == NULL) || (y == NULL))
3455 return(-2);
3456
3457 /*
3458 * Cast everything to doubles.
3459 */
3460 if (x->type == XML_SCHEMAS_DOUBLE)
3461 d1 = x->value.d;
3462 else if (x->type == XML_SCHEMAS_FLOAT)
3463 d1 = x->value.f;
3464 else
3465 return(-2);
3466
3467 if (y->type == XML_SCHEMAS_DOUBLE)
3468 d2 = y->value.d;
3469 else if (y->type == XML_SCHEMAS_FLOAT)
3470 d2 = y->value.f;
3471 else
3472 return(-2);
3473
3474 /*
3475 * Check for special cases.
3476 */
3477 if (xmlXPathIsNaN(d1)) {
3478 if (xmlXPathIsNaN(d2))
3479 return(0);
3480 return(1);
3481 }
3482 if (xmlXPathIsNaN(d2))
3483 return(-1);
3484 if (d1 == xmlXPathPINF) {
3485 if (d2 == xmlXPathPINF)
3486 return(0);
3487 return(1);
3488 }
3489 if (d2 == xmlXPathPINF)
3490 return(-1);
3491 if (d1 == xmlXPathNINF) {
3492 if (d2 == xmlXPathNINF)
3493 return(0);
3494 return(-1);
3495 }
3496 if (d2 == xmlXPathNINF)
3497 return(1);
3498
3499 /*
3500 * basic tests, the last one we should have equality, but
3501 * portability is more important than speed and handling
3502 * NaN or Inf in a portable way is always a challenge, so ...
3503 */
3504 if (d1 < d2)
3505 return(-1);
3506 if (d1 > d2)
3507 return(1);
3508 if (d1 == d2)
3509 return(0);
3510 return(2);
3511}
3512
3513/**
Daniel Veillard4255d502002-04-16 15:50:10 +00003514 * xmlSchemaCompareValues:
3515 * @x: a first value
3516 * @y: a second value
3517 *
3518 * Compare 2 values
3519 *
Daniel Veillard5a872412002-05-22 06:40:27 +00003520 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3521 * case of error
Daniel Veillard4255d502002-04-16 15:50:10 +00003522 */
Daniel Veillard80b19092003-03-28 13:29:53 +00003523int
Daniel Veillard4255d502002-04-16 15:50:10 +00003524xmlSchemaCompareValues(xmlSchemaValPtr x, xmlSchemaValPtr y) {
3525 if ((x == NULL) || (y == NULL))
3526 return(-2);
3527
3528 switch (x->type) {
Daniel Veillard80b19092003-03-28 13:29:53 +00003529 case XML_SCHEMAS_UNKNOWN:
3530 return(-2);
3531 case XML_SCHEMAS_INTEGER:
3532 case XML_SCHEMAS_NPINTEGER:
3533 case XML_SCHEMAS_NINTEGER:
3534 case XML_SCHEMAS_NNINTEGER:
3535 case XML_SCHEMAS_PINTEGER:
3536 case XML_SCHEMAS_INT:
3537 case XML_SCHEMAS_UINT:
3538 case XML_SCHEMAS_LONG:
3539 case XML_SCHEMAS_ULONG:
3540 case XML_SCHEMAS_SHORT:
3541 case XML_SCHEMAS_USHORT:
3542 case XML_SCHEMAS_BYTE:
3543 case XML_SCHEMAS_UBYTE:
Daniel Veillard4255d502002-04-16 15:50:10 +00003544 case XML_SCHEMAS_DECIMAL:
Daniel Veillard80b19092003-03-28 13:29:53 +00003545 if (y->type == x->type)
3546 return(xmlSchemaCompareDecimals(x, y));
3547 if ((y->type == XML_SCHEMAS_DECIMAL) ||
3548 (y->type == XML_SCHEMAS_INTEGER) ||
3549 (y->type == XML_SCHEMAS_NPINTEGER) ||
3550 (y->type == XML_SCHEMAS_NINTEGER) ||
3551 (y->type == XML_SCHEMAS_NNINTEGER) ||
3552 (y->type == XML_SCHEMAS_PINTEGER) ||
3553 (y->type == XML_SCHEMAS_INT) ||
3554 (y->type == XML_SCHEMAS_UINT) ||
3555 (y->type == XML_SCHEMAS_LONG) ||
3556 (y->type == XML_SCHEMAS_ULONG) ||
3557 (y->type == XML_SCHEMAS_SHORT) ||
3558 (y->type == XML_SCHEMAS_USHORT) ||
3559 (y->type == XML_SCHEMAS_BYTE) ||
3560 (y->type == XML_SCHEMAS_UBYTE))
Daniel Veillard4255d502002-04-16 15:50:10 +00003561 return(xmlSchemaCompareDecimals(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00003562 return(-2);
Daniel Veillard070803b2002-05-03 07:29:38 +00003563 case XML_SCHEMAS_DURATION:
3564 if (y->type == XML_SCHEMAS_DURATION)
3565 return(xmlSchemaCompareDurations(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00003566 return(-2);
3567 case XML_SCHEMAS_TIME:
3568 case XML_SCHEMAS_GDAY:
3569 case XML_SCHEMAS_GMONTH:
3570 case XML_SCHEMAS_GMONTHDAY:
3571 case XML_SCHEMAS_GYEAR:
3572 case XML_SCHEMAS_GYEARMONTH:
3573 case XML_SCHEMAS_DATE:
3574 case XML_SCHEMAS_DATETIME:
3575 if ((y->type == XML_SCHEMAS_DATETIME) ||
3576 (y->type == XML_SCHEMAS_TIME) ||
3577 (y->type == XML_SCHEMAS_GDAY) ||
3578 (y->type == XML_SCHEMAS_GMONTH) ||
3579 (y->type == XML_SCHEMAS_GMONTHDAY) ||
3580 (y->type == XML_SCHEMAS_GYEAR) ||
3581 (y->type == XML_SCHEMAS_DATE) ||
3582 (y->type == XML_SCHEMAS_GYEARMONTH))
3583 return (xmlSchemaCompareDates(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00003584 return (-2);
Daniel Veillard80b19092003-03-28 13:29:53 +00003585 case XML_SCHEMAS_NORMSTRING:
Daniel Veillard80b19092003-03-28 13:29:53 +00003586 case XML_SCHEMAS_TOKEN:
3587 case XML_SCHEMAS_LANGUAGE:
3588 case XML_SCHEMAS_NMTOKEN:
Daniel Veillard80b19092003-03-28 13:29:53 +00003589 case XML_SCHEMAS_NAME:
Daniel Veillard80b19092003-03-28 13:29:53 +00003590 case XML_SCHEMAS_NCNAME:
3591 case XML_SCHEMAS_ID:
3592 case XML_SCHEMAS_IDREF:
Daniel Veillard80b19092003-03-28 13:29:53 +00003593 case XML_SCHEMAS_ENTITY:
Daniel Veillard80b19092003-03-28 13:29:53 +00003594 case XML_SCHEMAS_NOTATION:
3595 case XML_SCHEMAS_ANYURI:
Daniel Veillardc4c21552003-03-29 10:53:38 +00003596 if ((y->type == XML_SCHEMAS_NORMSTRING) ||
3597 (y->type == XML_SCHEMAS_TOKEN) ||
3598 (y->type == XML_SCHEMAS_LANGUAGE) ||
3599 (y->type == XML_SCHEMAS_NMTOKEN) ||
3600 (y->type == XML_SCHEMAS_NAME) ||
3601 (y->type == XML_SCHEMAS_QNAME) ||
3602 (y->type == XML_SCHEMAS_NCNAME) ||
3603 (y->type == XML_SCHEMAS_ID) ||
3604 (y->type == XML_SCHEMAS_IDREF) ||
3605 (y->type == XML_SCHEMAS_ENTITY) ||
3606 (y->type == XML_SCHEMAS_NOTATION) ||
3607 (y->type == XML_SCHEMAS_ANYURI))
3608 return (xmlSchemaCompareNormStrings(x, y));
3609 return (-2);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003610 case XML_SCHEMAS_QNAME:
3611 if (y->type == XML_SCHEMAS_QNAME) {
3612 if ((xmlStrEqual(x->value.qname.name, y->value.qname.name)) &&
3613 (xmlStrEqual(x->value.qname.uri, y->value.qname.uri)))
3614 return(0);
3615 return(2);
3616 }
3617 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00003618 case XML_SCHEMAS_FLOAT:
3619 case XML_SCHEMAS_DOUBLE:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003620 if ((y->type == XML_SCHEMAS_FLOAT) ||
3621 (y->type == XML_SCHEMAS_DOUBLE))
3622 return (xmlSchemaCompareFloats(x, y));
3623 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00003624 case XML_SCHEMAS_BOOLEAN:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003625 if (y->type == XML_SCHEMAS_BOOLEAN) {
3626 if (x->value.b == y->value.b)
3627 return(0);
3628 if (x->value.b == 0)
3629 return(-1);
3630 return(1);
3631 }
3632 return (-2);
Daniel Veillard560c2a42003-07-06 21:13:49 +00003633 case XML_SCHEMAS_HEXBINARY:
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00003634 if (y->type == XML_SCHEMAS_HEXBINARY) {
3635 if (x->value.hex.total == y->value.hex.total) {
3636 int ret = xmlStrcmp(x->value.hex.str, y->value.hex.str);
3637 if (ret > 0)
3638 return(1);
3639 else if (ret == 0)
3640 return(0);
3641 }
3642 else if (x->value.hex.total > y->value.hex.total)
3643 return(1);
3644
3645 return(-1);
3646 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00003647 return (-2);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003648 case XML_SCHEMAS_BASE64BINARY:
3649 if (y->type == XML_SCHEMAS_BASE64BINARY) {
3650 if (x->value.base64.total == y->value.base64.total) {
3651 int ret = xmlStrcmp(x->value.base64.str,
3652 y->value.base64.str);
3653 if (ret > 0)
3654 return(1);
3655 else if (ret == 0)
3656 return(0);
3657 }
3658 else if (x->value.base64.total > y->value.base64.total)
3659 return(1);
3660 else
3661 return(-1);
3662 }
3663 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00003664 case XML_SCHEMAS_STRING:
3665 case XML_SCHEMAS_IDREFS:
3666 case XML_SCHEMAS_ENTITIES:
3667 case XML_SCHEMAS_NMTOKENS:
3668 TODO
3669 break;
William M. Brack96d2eff2004-06-30 11:48:47 +00003670 case XML_SCHEMAS_ANYTYPE:
3671 case XML_SCHEMAS_ANYSIMPLETYPE:
3672 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00003673 }
Daniel Veillard5a872412002-05-22 06:40:27 +00003674 return -2;
Daniel Veillard4255d502002-04-16 15:50:10 +00003675}
3676
3677/**
Daniel Veillardc4c21552003-03-29 10:53:38 +00003678 * xmlSchemaNormLen:
3679 * @value: a string
3680 *
3681 * Computes the UTF8 length of the normalized value of the string
3682 *
3683 * Returns the length or -1 in case of error.
3684 */
3685static int
3686xmlSchemaNormLen(const xmlChar *value) {
3687 const xmlChar *utf;
3688 int ret = 0;
3689
3690 if (value == NULL)
3691 return(-1);
3692 utf = value;
William M. Brack76e95df2003-10-18 16:20:14 +00003693 while (IS_BLANK_CH(*utf)) utf++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003694 while (*utf != 0) {
3695 if (utf[0] & 0x80) {
3696 if ((utf[1] & 0xc0) != 0x80)
3697 return(-1);
3698 if ((utf[0] & 0xe0) == 0xe0) {
3699 if ((utf[2] & 0xc0) != 0x80)
3700 return(-1);
3701 if ((utf[0] & 0xf0) == 0xf0) {
3702 if ((utf[0] & 0xf8) != 0xf0 || (utf[3] & 0xc0) != 0x80)
3703 return(-1);
3704 utf += 4;
3705 } else {
3706 utf += 3;
3707 }
3708 } else {
3709 utf += 2;
3710 }
William M. Brack76e95df2003-10-18 16:20:14 +00003711 } else if (IS_BLANK_CH(*utf)) {
3712 while (IS_BLANK_CH(*utf)) utf++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003713 if (*utf == 0)
3714 break;
3715 } else {
3716 utf++;
3717 }
3718 ret++;
3719 }
3720 return(ret);
3721}
3722
3723/**
Daniel Veillard01fa6152004-06-29 17:04:39 +00003724 * xmlSchemaValidateListSimpleTypeFacet:
3725 * @facet: the facet to check
3726 * @value: the lexical repr of the value to validate
3727 * @actualLen: the number of list items
3728 * @expectedLen: the resulting expected number of list items
3729 *
3730 * Checks the value of a list simple type against a facet.
3731 *
3732 * Returns 0 if the value is valid, a positive error code
3733 * number otherwise and -1 in case of an internal error.
3734 */
3735int
3736xmlSchemaValidateListSimpleTypeFacet(xmlSchemaFacetPtr facet,
3737 const xmlChar *value,
3738 unsigned long actualLen,
3739 unsigned long *expectedLen)
3740{
3741 /*
3742 * TODO: Check if this will work with large numbers.
3743 * (compare value.decimal.mi and value.decimal.hi as well?).
3744 */
3745 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
3746 if (actualLen != facet->val->value.decimal.lo) {
3747 *expectedLen = facet->val->value.decimal.lo;
3748 return (XML_SCHEMAV_CVC_LENGTH_VALID);
3749 }
3750 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
3751 if (actualLen < facet->val->value.decimal.lo) {
3752 *expectedLen = facet->val->value.decimal.lo;
3753 return (XML_SCHEMAV_CVC_MINLENGTH_VALID);
3754 }
3755 } else if (facet->type == XML_SCHEMA_FACET_MAXLENGTH) {
3756 if (actualLen > facet->val->value.decimal.lo) {
3757 *expectedLen = facet->val->value.decimal.lo;
3758 return (XML_SCHEMAV_CVC_MAXLENGTH_VALID);
3759 }
3760 } else
3761 /*
3762 * NOTE: That we can pass NULL as xmlSchemaValPtr to
3763 * xmlSchemaValidateFacet, since the remaining facet types
3764 * are: XML_SCHEMA_FACET_PATTERN, XML_SCHEMA_FACET_ENUMERATION.
3765 */
3766 return(xmlSchemaValidateFacet(NULL, facet, value, NULL));
3767 return (0);
3768}
3769
3770/**
Daniel Veillard4255d502002-04-16 15:50:10 +00003771 * xmlSchemaValidateFacet:
Daniel Veillard01c13b52002-12-10 15:19:08 +00003772 * @base: the base type
Daniel Veillard4255d502002-04-16 15:50:10 +00003773 * @facet: the facet to check
3774 * @value: the lexical repr of the value to validate
3775 * @val: the precomputed value
3776 *
3777 * Check a value against a facet condition
3778 *
3779 * Returns 0 if the element is schemas valid, a positive error code
3780 * number otherwise and -1 in case of internal or API error.
3781 */
3782int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00003783xmlSchemaValidateFacet(xmlSchemaTypePtr base ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +00003784 xmlSchemaFacetPtr facet,
Daniel Veillard4255d502002-04-16 15:50:10 +00003785 const xmlChar *value, xmlSchemaValPtr val)
3786{
3787 int ret;
3788
3789 switch (facet->type) {
3790 case XML_SCHEMA_FACET_PATTERN:
3791 ret = xmlRegexpExec(facet->regexp, value);
3792 if (ret == 1)
3793 return(0);
3794 if (ret == 0) {
Daniel Veillard01fa6152004-06-29 17:04:39 +00003795 return(XML_SCHEMAV_CVC_PATTERN_VALID);
Daniel Veillard4255d502002-04-16 15:50:10 +00003796 }
3797 return(ret);
3798 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
3799 ret = xmlSchemaCompareValues(val, facet->val);
3800 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003801 /* TODO error code */
Daniel Veillard4255d502002-04-16 15:50:10 +00003802 return(-1);
3803 }
3804 if (ret == -1)
3805 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00003806 /* error code */
Daniel Veillard01fa6152004-06-29 17:04:39 +00003807 return(XML_SCHEMAV_CVC_MAXEXCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00003808 case XML_SCHEMA_FACET_MAXINCLUSIVE:
3809 ret = xmlSchemaCompareValues(val, facet->val);
3810 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003811 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00003812 return(-1);
3813 }
3814 if ((ret == -1) || (ret == 0))
3815 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00003816 /* error code */
Daniel Veillard01fa6152004-06-29 17:04:39 +00003817 return(XML_SCHEMAV_CVC_MAXINCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00003818 case XML_SCHEMA_FACET_MINEXCLUSIVE:
3819 ret = xmlSchemaCompareValues(val, facet->val);
3820 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003821 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00003822 return(-1);
3823 }
3824 if (ret == 1)
3825 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00003826 /* error code */
Daniel Veillard01fa6152004-06-29 17:04:39 +00003827 return(XML_SCHEMAV_CVC_MINEXCLUSIVE_VALID);
Daniel Veillard070803b2002-05-03 07:29:38 +00003828 case XML_SCHEMA_FACET_MININCLUSIVE:
3829 ret = xmlSchemaCompareValues(val, facet->val);
3830 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003831 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00003832 return(-1);
3833 }
3834 if ((ret == 1) || (ret == 0))
3835 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00003836 /* error code */
Daniel Veillard01fa6152004-06-29 17:04:39 +00003837 return(XML_SCHEMAV_CVC_MININCLUSIVE_VALID);
Daniel Veillard8651f532002-04-17 09:06:27 +00003838 case XML_SCHEMA_FACET_WHITESPACE:
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003839 /* TODO whitespaces */
Daniel Veillard01fa6152004-06-29 17:04:39 +00003840 /*
3841 * NOTE: Whitespace should be handled to normalize
3842 * the value to be validated against a the facets;
3843 * not to normalize the value in-between.
3844 */
Daniel Veillard8651f532002-04-17 09:06:27 +00003845 return(0);
Daniel Veillard88c58912002-04-23 07:12:20 +00003846 case XML_SCHEMA_FACET_ENUMERATION:
3847 if ((facet->value != NULL) &&
3848 (xmlStrEqual(facet->value, value)))
3849 return(0);
Daniel Veillard01fa6152004-06-29 17:04:39 +00003850 return(XML_SCHEMAV_CVC_ENUMERATION_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003851 case XML_SCHEMA_FACET_LENGTH:
3852 case XML_SCHEMA_FACET_MAXLENGTH:
3853 case XML_SCHEMA_FACET_MINLENGTH: {
3854 unsigned int len = 0;
3855
3856 if ((facet->val == NULL) ||
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003857 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
3858 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003859 (facet->val->value.decimal.frac != 0)) {
3860 return(-1);
3861 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00003862 if ((val != NULL) && (val->type == XML_SCHEMAS_HEXBINARY))
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00003863 len = val->value.hex.total;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003864 else if ((val != NULL) && (val->type == XML_SCHEMAS_BASE64BINARY))
3865 len = val->value.base64.total;
3866 else {
Daniel Veillard01fa6152004-06-29 17:04:39 +00003867 switch (base->builtInType) {
Daniel Veillard560c2a42003-07-06 21:13:49 +00003868 case XML_SCHEMAS_IDREF:
3869 case XML_SCHEMAS_NORMSTRING:
3870 case XML_SCHEMAS_TOKEN:
3871 case XML_SCHEMAS_LANGUAGE:
3872 case XML_SCHEMAS_NMTOKEN:
3873 case XML_SCHEMAS_NAME:
3874 case XML_SCHEMAS_NCNAME:
3875 case XML_SCHEMAS_ID:
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00003876 len = xmlSchemaNormLen(value);
3877 break;
Daniel Veillard560c2a42003-07-06 21:13:49 +00003878 case XML_SCHEMAS_STRING:
Daniel Veillard01fa6152004-06-29 17:04:39 +00003879 /*
3880 * FIXME: What exactly to do with anyURI?
3881 */
3882 case XML_SCHEMAS_ANYURI:
William M. Brackfbf2c5e2004-02-03 17:55:56 +00003883 if (value != NULL)
3884 len = xmlUTF8Strlen(value);
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00003885 break;
Daniel Veillard560c2a42003-07-06 21:13:49 +00003886 default:
3887 TODO
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00003888 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003889 }
3890 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003891 if (len != facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00003892 return(XML_SCHEMAV_CVC_LENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003893 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003894 if (len < facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00003895 return(XML_SCHEMAV_CVC_MINLENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003896 } else {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003897 if (len > facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00003898 return(XML_SCHEMAV_CVC_MAXLENGTH_VALID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003899 }
3900 break;
3901 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00003902 case XML_SCHEMA_FACET_TOTALDIGITS:
3903 case XML_SCHEMA_FACET_FRACTIONDIGITS:
3904
3905 if ((facet->val == NULL) ||
3906 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
3907 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
3908 (facet->val->value.decimal.frac != 0)) {
3909 return(-1);
3910 }
3911 if ((val == NULL) ||
3912 ((val->type != XML_SCHEMAS_DECIMAL) &&
3913 (val->type != XML_SCHEMAS_INTEGER) &&
3914 (val->type != XML_SCHEMAS_NPINTEGER) &&
3915 (val->type != XML_SCHEMAS_NINTEGER) &&
3916 (val->type != XML_SCHEMAS_NNINTEGER) &&
3917 (val->type != XML_SCHEMAS_PINTEGER) &&
3918 (val->type != XML_SCHEMAS_INT) &&
3919 (val->type != XML_SCHEMAS_UINT) &&
3920 (val->type != XML_SCHEMAS_LONG) &&
3921 (val->type != XML_SCHEMAS_ULONG) &&
3922 (val->type != XML_SCHEMAS_SHORT) &&
3923 (val->type != XML_SCHEMAS_USHORT) &&
3924 (val->type != XML_SCHEMAS_BYTE) &&
3925 (val->type != XML_SCHEMAS_UBYTE))) {
3926 return(-1);
3927 }
3928 if (facet->type == XML_SCHEMA_FACET_TOTALDIGITS) {
3929 if (val->value.decimal.total > facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00003930 return(XML_SCHEMAV_CVC_TOTALDIGITS_VALID);
Daniel Veillard560c2a42003-07-06 21:13:49 +00003931
3932 } else if (facet->type == XML_SCHEMA_FACET_FRACTIONDIGITS) {
3933 if (val->value.decimal.frac > facet->val->value.decimal.lo)
Daniel Veillard01fa6152004-06-29 17:04:39 +00003934 return(XML_SCHEMAV_CVC_FRACTIONDIGITS_VALID);
Daniel Veillard560c2a42003-07-06 21:13:49 +00003935 }
3936 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00003937 default:
3938 TODO
3939 }
3940 return(0);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003941
Daniel Veillard4255d502002-04-16 15:50:10 +00003942}
3943
3944#endif /* LIBXML_SCHEMAS_ENABLED */