blob: 6cd13ae9426859cbe3458db930220bba2c0103ac [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
42typedef enum {
43 XML_SCHEMAS_UNKNOWN = 0,
44 XML_SCHEMAS_STRING,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +000045 XML_SCHEMAS_NORMSTRING,
Daniel Veillard4255d502002-04-16 15:50:10 +000046 XML_SCHEMAS_DECIMAL,
Daniel Veillard070803b2002-05-03 07:29:38 +000047 XML_SCHEMAS_TIME,
48 XML_SCHEMAS_GDAY,
49 XML_SCHEMAS_GMONTH,
50 XML_SCHEMAS_GMONTHDAY,
51 XML_SCHEMAS_GYEAR,
52 XML_SCHEMAS_GYEARMONTH,
53 XML_SCHEMAS_DATE,
54 XML_SCHEMAS_DATETIME,
55 XML_SCHEMAS_DURATION,
Daniel Veillard84d70a42002-09-16 10:51:38 +000056 XML_SCHEMAS_FLOAT,
57 XML_SCHEMAS_DOUBLE,
Daniel Veillardc5a70f22003-02-06 23:41:59 +000058 XML_SCHEMAS_BOOLEAN,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +000059 XML_SCHEMAS_TOKEN,
60 XML_SCHEMAS_LANGUAGE,
61 XML_SCHEMAS_NMTOKEN,
62 XML_SCHEMAS_NMTOKENS,
63 XML_SCHEMAS_NAME,
64 XML_SCHEMAS_QNAME,
65 XML_SCHEMAS_NCNAME,
66 XML_SCHEMAS_ID,
67 XML_SCHEMAS_IDREF,
68 XML_SCHEMAS_IDREFS,
69 XML_SCHEMAS_ENTITY,
70 XML_SCHEMAS_ENTITIES,
71 XML_SCHEMAS_NOTATION,
72 XML_SCHEMAS_ANYURI,
73 XML_SCHEMAS_INTEGER,
74 XML_SCHEMAS_NPINTEGER,
75 XML_SCHEMAS_NINTEGER,
76 XML_SCHEMAS_NNINTEGER,
77 XML_SCHEMAS_PINTEGER,
Daniel Veillard96a4b252003-02-06 08:22:32 +000078 XML_SCHEMAS_INT,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +000079 XML_SCHEMAS_UINT,
80 XML_SCHEMAS_LONG,
81 XML_SCHEMAS_ULONG,
82 XML_SCHEMAS_SHORT,
83 XML_SCHEMAS_USHORT,
84 XML_SCHEMAS_BYTE,
Daniel Veillard560c2a42003-07-06 21:13:49 +000085 XML_SCHEMAS_UBYTE,
Daniel Veillard1ac24d32003-08-27 14:15:15 +000086 XML_SCHEMAS_HEXBINARY,
87 XML_SCHEMAS_BASE64BINARY
Daniel Veillard4255d502002-04-16 15:50:10 +000088} xmlSchemaValType;
89
Daniel Veillard5f704af2003-03-05 10:01:43 +000090static unsigned long powten[10] = {
Daniel Veillard4255d502002-04-16 15:50:10 +000091 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000L,
92 100000000L, 1000000000L
93};
94
Daniel Veillard070803b2002-05-03 07:29:38 +000095/* Date value */
96typedef struct _xmlSchemaValDate xmlSchemaValDate;
97typedef xmlSchemaValDate *xmlSchemaValDatePtr;
98struct _xmlSchemaValDate {
99 long year;
100 unsigned int mon :4; /* 1 <= mon <= 12 */
101 unsigned int day :5; /* 1 <= day <= 31 */
102 unsigned int hour :5; /* 0 <= hour <= 23 */
103 unsigned int min :6; /* 0 <= min <= 59 */
104 double sec;
Daniel Veillarda77cf712003-05-09 23:09:55 +0000105 unsigned int tz_flag :1; /* is tzo explicitely set? */
Daniel Veillard070803b2002-05-03 07:29:38 +0000106 int tzo :11; /* -1440 <= tzo <= 1440 */
107};
108
109/* Duration value */
110typedef struct _xmlSchemaValDuration xmlSchemaValDuration;
111typedef xmlSchemaValDuration *xmlSchemaValDurationPtr;
112struct _xmlSchemaValDuration {
113 long mon; /* mon stores years also */
114 long day;
115 double sec; /* sec stores min and hour also */
116};
117
Daniel Veillard4255d502002-04-16 15:50:10 +0000118typedef struct _xmlSchemaValDecimal xmlSchemaValDecimal;
119typedef xmlSchemaValDecimal *xmlSchemaValDecimalPtr;
120struct _xmlSchemaValDecimal {
121 /* would use long long but not portable */
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000122 unsigned long lo;
123 unsigned long mi;
124 unsigned long hi;
Daniel Veillard4255d502002-04-16 15:50:10 +0000125 unsigned int extra;
Daniel Veillard5a872412002-05-22 06:40:27 +0000126 unsigned int sign:1;
William M. Brackc1939562003-08-05 15:52:22 +0000127 unsigned int frac:7;
128 unsigned int total:8;
Daniel Veillard4255d502002-04-16 15:50:10 +0000129};
130
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000131typedef struct _xmlSchemaValQName xmlSchemaValQName;
132typedef xmlSchemaValQName *xmlSchemaValQNamePtr;
133struct _xmlSchemaValQName {
134 xmlChar *name;
135 xmlChar *uri;
136};
137
Daniel Veillard70bcb0e2003-08-08 14:00:28 +0000138typedef struct _xmlSchemaValHex xmlSchemaValHex;
139typedef xmlSchemaValHex *xmlSchemaValHexPtr;
140struct _xmlSchemaValHex {
141 xmlChar *str;
142 unsigned int total;
143};
144
Daniel Veillard1ac24d32003-08-27 14:15:15 +0000145typedef struct _xmlSchemaValBase64 xmlSchemaValBase64;
146typedef xmlSchemaValBase64 *xmlSchemaValBase64Ptr;
147struct _xmlSchemaValBase64 {
148 xmlChar *str;
149 unsigned int total;
150};
151
Daniel Veillard4255d502002-04-16 15:50:10 +0000152struct _xmlSchemaVal {
153 xmlSchemaValType type;
154 union {
Daniel Veillard5a872412002-05-22 06:40:27 +0000155 xmlSchemaValDecimal decimal;
Daniel Veillard070803b2002-05-03 07:29:38 +0000156 xmlSchemaValDate date;
157 xmlSchemaValDuration dur;
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000158 xmlSchemaValQName qname;
Daniel Veillard70bcb0e2003-08-08 14:00:28 +0000159 xmlSchemaValHex hex;
Daniel Veillard1ac24d32003-08-27 14:15:15 +0000160 xmlSchemaValBase64 base64;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000161 float f;
162 double d;
Daniel Veillardc5a70f22003-02-06 23:41:59 +0000163 int b;
Daniel Veillardc4c21552003-03-29 10:53:38 +0000164 xmlChar *str;
Daniel Veillard4255d502002-04-16 15:50:10 +0000165 } value;
166};
167
168static int xmlSchemaTypesInitialized = 0;
169static xmlHashTablePtr xmlSchemaTypesBank = NULL;
170
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000171/*
172 * Basic types
173 */
Daniel Veillard4255d502002-04-16 15:50:10 +0000174static xmlSchemaTypePtr xmlSchemaTypeStringDef = NULL;
175static xmlSchemaTypePtr xmlSchemaTypeAnyTypeDef = NULL;
176static xmlSchemaTypePtr xmlSchemaTypeAnySimpleTypeDef = NULL;
177static xmlSchemaTypePtr xmlSchemaTypeDecimalDef = NULL;
Daniel Veillard070803b2002-05-03 07:29:38 +0000178static xmlSchemaTypePtr xmlSchemaTypeDatetimeDef = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +0000179static xmlSchemaTypePtr xmlSchemaTypeDateDef = NULL;
Daniel Veillard070803b2002-05-03 07:29:38 +0000180static xmlSchemaTypePtr xmlSchemaTypeTimeDef = NULL;
181static xmlSchemaTypePtr xmlSchemaTypeGYearDef = NULL;
182static xmlSchemaTypePtr xmlSchemaTypeGYearMonthDef = NULL;
183static xmlSchemaTypePtr xmlSchemaTypeGDayDef = NULL;
184static xmlSchemaTypePtr xmlSchemaTypeGMonthDayDef = NULL;
185static xmlSchemaTypePtr xmlSchemaTypeGMonthDef = NULL;
186static xmlSchemaTypePtr xmlSchemaTypeDurationDef = NULL;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000187static xmlSchemaTypePtr xmlSchemaTypeFloatDef = NULL;
Daniel Veillardc5a70f22003-02-06 23:41:59 +0000188static xmlSchemaTypePtr xmlSchemaTypeBooleanDef = NULL;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000189static xmlSchemaTypePtr xmlSchemaTypeDoubleDef = NULL;
Daniel Veillard560c2a42003-07-06 21:13:49 +0000190static xmlSchemaTypePtr xmlSchemaTypeHexBinaryDef = NULL;
Daniel Veillard1ac24d32003-08-27 14:15:15 +0000191static xmlSchemaTypePtr xmlSchemaTypeBase64BinaryDef = NULL;
Daniel Veillarde5b110b2003-02-04 14:43:39 +0000192static xmlSchemaTypePtr xmlSchemaTypeAnyURIDef = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +0000193
194/*
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000195 * Derived types
196 */
197static xmlSchemaTypePtr xmlSchemaTypePositiveIntegerDef = NULL;
198static xmlSchemaTypePtr xmlSchemaTypeNonPositiveIntegerDef = NULL;
199static xmlSchemaTypePtr xmlSchemaTypeNegativeIntegerDef = NULL;
200static xmlSchemaTypePtr xmlSchemaTypeNonNegativeIntegerDef = NULL;
201static xmlSchemaTypePtr xmlSchemaTypeIntegerDef = NULL;
202static xmlSchemaTypePtr xmlSchemaTypeLongDef = NULL;
203static xmlSchemaTypePtr xmlSchemaTypeIntDef = NULL;
204static xmlSchemaTypePtr xmlSchemaTypeShortDef = NULL;
205static xmlSchemaTypePtr xmlSchemaTypeByteDef = NULL;
206static xmlSchemaTypePtr xmlSchemaTypeUnsignedLongDef = NULL;
207static xmlSchemaTypePtr xmlSchemaTypeUnsignedIntDef = NULL;
208static xmlSchemaTypePtr xmlSchemaTypeUnsignedShortDef = NULL;
209static xmlSchemaTypePtr xmlSchemaTypeUnsignedByteDef = NULL;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000210static xmlSchemaTypePtr xmlSchemaTypeNormStringDef = NULL;
211static xmlSchemaTypePtr xmlSchemaTypeTokenDef = NULL;
212static xmlSchemaTypePtr xmlSchemaTypeLanguageDef = NULL;
213static xmlSchemaTypePtr xmlSchemaTypeNameDef = NULL;
214static xmlSchemaTypePtr xmlSchemaTypeQNameDef = NULL;
Daniel Veillarde5b110b2003-02-04 14:43:39 +0000215static xmlSchemaTypePtr xmlSchemaTypeNCNameDef = NULL;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000216static xmlSchemaTypePtr xmlSchemaTypeIdDef = NULL;
217static xmlSchemaTypePtr xmlSchemaTypeIdrefDef = NULL;
218static xmlSchemaTypePtr xmlSchemaTypeIdrefsDef = NULL;
Daniel Veillarda1a9d042003-03-18 16:53:17 +0000219static xmlSchemaTypePtr xmlSchemaTypeEntityDef = NULL;
220static xmlSchemaTypePtr xmlSchemaTypeEntitiesDef = NULL;
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000221static xmlSchemaTypePtr xmlSchemaTypeNotationDef = NULL;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000222static xmlSchemaTypePtr xmlSchemaTypeNmtokenDef = NULL;
223static xmlSchemaTypePtr xmlSchemaTypeNmtokensDef = NULL;
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000224
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000225/************************************************************************
226 * *
227 * Datatype error handlers *
228 * *
229 ************************************************************************/
230/**
231 * xmlSchemaTypeErrMemory:
232 * @extra: extra informations
233 *
234 * Handle an out of memory condition
235 */
236static void
237xmlSchemaTypeErrMemory(xmlNodePtr node, const char *extra)
238{
239 __xmlSimpleError(XML_FROM_DATATYPE, XML_ERR_NO_MEMORY, node, NULL, extra);
240}
241
242/************************************************************************
243 * *
244 * Base types support *
245 * *
246 ************************************************************************/
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000247/*
Daniel Veillard4255d502002-04-16 15:50:10 +0000248 * xmlSchemaInitBasicType:
249 * @name: the type name
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000250 * @type: the value type associated
Daniel Veillard4255d502002-04-16 15:50:10 +0000251 *
252 * Initialize one default type
253 */
254static xmlSchemaTypePtr
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000255xmlSchemaInitBasicType(const char *name, xmlSchemaValType type) {
Daniel Veillard4255d502002-04-16 15:50:10 +0000256 xmlSchemaTypePtr ret;
257
258 ret = (xmlSchemaTypePtr) xmlMalloc(sizeof(xmlSchemaType));
259 if (ret == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000260 xmlSchemaTypeErrMemory(NULL, "could not initialize basic types");
Daniel Veillard4255d502002-04-16 15:50:10 +0000261 return(NULL);
262 }
263 memset(ret, 0, sizeof(xmlSchemaType));
Daniel Veillardbe9c6322003-11-22 20:37:51 +0000264 ret->name = (const xmlChar *)name;
Daniel Veillard4255d502002-04-16 15:50:10 +0000265 ret->type = XML_SCHEMA_TYPE_BASIC;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000266 ret->flags = type;
Daniel Veillard4255d502002-04-16 15:50:10 +0000267 ret->contentType = XML_SCHEMA_CONTENT_BASIC;
268 xmlHashAddEntry2(xmlSchemaTypesBank, ret->name,
269 XML_SCHEMAS_NAMESPACE_NAME, ret);
270 return(ret);
271}
272
273/*
274 * xmlSchemaInitTypes:
275 *
276 * Initialize the default XML Schemas type library
277 */
278void
Daniel Veillard6560a422003-03-27 21:25:38 +0000279xmlSchemaInitTypes(void)
280{
Daniel Veillard4255d502002-04-16 15:50:10 +0000281 if (xmlSchemaTypesInitialized != 0)
Daniel Veillard6560a422003-03-27 21:25:38 +0000282 return;
Daniel Veillard4255d502002-04-16 15:50:10 +0000283 xmlSchemaTypesBank = xmlHashCreate(40);
Daniel Veillard6560a422003-03-27 21:25:38 +0000284
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000285 /*
286 * primitive datatypes
287 */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000288 xmlSchemaTypeStringDef = xmlSchemaInitBasicType("string",
Daniel Veillard6560a422003-03-27 21:25:38 +0000289 XML_SCHEMAS_STRING);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000290 xmlSchemaTypeAnyTypeDef = xmlSchemaInitBasicType("anyType",
Daniel Veillard6560a422003-03-27 21:25:38 +0000291 XML_SCHEMAS_UNKNOWN);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000292 xmlSchemaTypeAnySimpleTypeDef = xmlSchemaInitBasicType("anySimpleType",
Daniel Veillard6560a422003-03-27 21:25:38 +0000293 XML_SCHEMAS_UNKNOWN);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000294 xmlSchemaTypeDecimalDef = xmlSchemaInitBasicType("decimal",
Daniel Veillard6560a422003-03-27 21:25:38 +0000295 XML_SCHEMAS_DECIMAL);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000296 xmlSchemaTypeDateDef = xmlSchemaInitBasicType("date",
Daniel Veillard6560a422003-03-27 21:25:38 +0000297 XML_SCHEMAS_DATE);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000298 xmlSchemaTypeDatetimeDef = xmlSchemaInitBasicType("dateTime",
Daniel Veillard6560a422003-03-27 21:25:38 +0000299 XML_SCHEMAS_DATETIME);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000300 xmlSchemaTypeTimeDef = xmlSchemaInitBasicType("time",
Daniel Veillard6560a422003-03-27 21:25:38 +0000301 XML_SCHEMAS_TIME);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000302 xmlSchemaTypeGYearDef = xmlSchemaInitBasicType("gYear",
Daniel Veillard6560a422003-03-27 21:25:38 +0000303 XML_SCHEMAS_GYEAR);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000304 xmlSchemaTypeGYearMonthDef = xmlSchemaInitBasicType("gYearMonth",
Daniel Veillard6560a422003-03-27 21:25:38 +0000305 XML_SCHEMAS_GYEARMONTH);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000306 xmlSchemaTypeGMonthDef = xmlSchemaInitBasicType("gMonth",
Daniel Veillard6560a422003-03-27 21:25:38 +0000307 XML_SCHEMAS_GMONTH);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000308 xmlSchemaTypeGMonthDayDef = xmlSchemaInitBasicType("gMonthDay",
Daniel Veillard6560a422003-03-27 21:25:38 +0000309 XML_SCHEMAS_GMONTHDAY);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000310 xmlSchemaTypeGDayDef = xmlSchemaInitBasicType("gDay",
Daniel Veillard6560a422003-03-27 21:25:38 +0000311 XML_SCHEMAS_GDAY);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000312 xmlSchemaTypeDurationDef = xmlSchemaInitBasicType("duration",
Daniel Veillard6560a422003-03-27 21:25:38 +0000313 XML_SCHEMAS_DURATION);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000314 xmlSchemaTypeFloatDef = xmlSchemaInitBasicType("float",
Daniel Veillard6560a422003-03-27 21:25:38 +0000315 XML_SCHEMAS_FLOAT);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000316 xmlSchemaTypeDoubleDef = xmlSchemaInitBasicType("double",
Daniel Veillard6560a422003-03-27 21:25:38 +0000317 XML_SCHEMAS_DOUBLE);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000318 xmlSchemaTypeBooleanDef = xmlSchemaInitBasicType("boolean",
Daniel Veillard6560a422003-03-27 21:25:38 +0000319 XML_SCHEMAS_BOOLEAN);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000320 xmlSchemaTypeAnyURIDef = xmlSchemaInitBasicType("anyURI",
Daniel Veillard6560a422003-03-27 21:25:38 +0000321 XML_SCHEMAS_ANYURI);
Daniel Veillard560c2a42003-07-06 21:13:49 +0000322 xmlSchemaTypeHexBinaryDef = xmlSchemaInitBasicType("hexBinary",
323 XML_SCHEMAS_HEXBINARY);
Daniel Veillard1ac24d32003-08-27 14:15:15 +0000324 xmlSchemaTypeBase64BinaryDef
325 = xmlSchemaInitBasicType("base64Binary", XML_SCHEMAS_BASE64BINARY);
Daniel Veillard4255d502002-04-16 15:50:10 +0000326
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000327 /*
328 * derived datatypes
329 */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000330 xmlSchemaTypeIntegerDef = xmlSchemaInitBasicType("integer",
Daniel Veillard6560a422003-03-27 21:25:38 +0000331 XML_SCHEMAS_INTEGER);;
332 xmlSchemaTypeNonPositiveIntegerDef =
333 xmlSchemaInitBasicType("nonPositiveInteger",
334 XML_SCHEMAS_NPINTEGER);;
335 xmlSchemaTypeNegativeIntegerDef =
336 xmlSchemaInitBasicType("negativeInteger", XML_SCHEMAS_NINTEGER);;
337 xmlSchemaTypeLongDef =
338 xmlSchemaInitBasicType("long", XML_SCHEMAS_LONG);;
339 xmlSchemaTypeIntDef = xmlSchemaInitBasicType("int", XML_SCHEMAS_INT);;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000340 xmlSchemaTypeShortDef = xmlSchemaInitBasicType("short",
Daniel Veillard6560a422003-03-27 21:25:38 +0000341 XML_SCHEMAS_SHORT);;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000342 xmlSchemaTypeByteDef = xmlSchemaInitBasicType("byte",
Daniel Veillard6560a422003-03-27 21:25:38 +0000343 XML_SCHEMAS_BYTE);;
344 xmlSchemaTypeNonNegativeIntegerDef =
345 xmlSchemaInitBasicType("nonNegativeInteger",
346 XML_SCHEMAS_NNINTEGER);
347 xmlSchemaTypeUnsignedLongDef =
348 xmlSchemaInitBasicType("unsignedLong", XML_SCHEMAS_ULONG);;
349 xmlSchemaTypeUnsignedIntDef =
350 xmlSchemaInitBasicType("unsignedInt", XML_SCHEMAS_UINT);;
351 xmlSchemaTypeUnsignedShortDef =
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000352 xmlSchemaInitBasicType("unsignedShort", XML_SCHEMAS_USHORT);;
Daniel Veillard6560a422003-03-27 21:25:38 +0000353 xmlSchemaTypeUnsignedByteDef =
354 xmlSchemaInitBasicType("unsignedByte", XML_SCHEMAS_UBYTE);;
355 xmlSchemaTypePositiveIntegerDef =
356 xmlSchemaInitBasicType("positiveInteger", XML_SCHEMAS_PINTEGER);
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000357
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000358 xmlSchemaTypeNormStringDef = xmlSchemaInitBasicType("normalizedString",
Daniel Veillard6560a422003-03-27 21:25:38 +0000359 XML_SCHEMAS_NORMSTRING);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000360 xmlSchemaTypeTokenDef = xmlSchemaInitBasicType("token",
Daniel Veillard6560a422003-03-27 21:25:38 +0000361 XML_SCHEMAS_TOKEN);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000362 xmlSchemaTypeLanguageDef = xmlSchemaInitBasicType("language",
Daniel Veillard6560a422003-03-27 21:25:38 +0000363 XML_SCHEMAS_LANGUAGE);
364 xmlSchemaTypeIdDef = xmlSchemaInitBasicType("ID", XML_SCHEMAS_ID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000365 xmlSchemaTypeIdrefDef = xmlSchemaInitBasicType("IDREF",
Daniel Veillard6560a422003-03-27 21:25:38 +0000366 XML_SCHEMAS_IDREF);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000367 xmlSchemaTypeIdrefsDef = xmlSchemaInitBasicType("IDREFS",
Daniel Veillard6560a422003-03-27 21:25:38 +0000368 XML_SCHEMAS_IDREFS);
Daniel Veillarda1a9d042003-03-18 16:53:17 +0000369 xmlSchemaTypeEntityDef = xmlSchemaInitBasicType("ENTITY",
Daniel Veillard6560a422003-03-27 21:25:38 +0000370 XML_SCHEMAS_ENTITY);
Daniel Veillarda1a9d042003-03-18 16:53:17 +0000371 xmlSchemaTypeEntitiesDef = xmlSchemaInitBasicType("ENTITIES",
Daniel Veillard6560a422003-03-27 21:25:38 +0000372 XML_SCHEMAS_ENTITIES);
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000373 xmlSchemaTypeNotationDef = xmlSchemaInitBasicType("NOTATION",
374 XML_SCHEMAS_NOTATION);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000375 xmlSchemaTypeNameDef = xmlSchemaInitBasicType("Name",
Daniel Veillard6560a422003-03-27 21:25:38 +0000376 XML_SCHEMAS_NAME);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000377 xmlSchemaTypeQNameDef = xmlSchemaInitBasicType("QName",
Daniel Veillard6560a422003-03-27 21:25:38 +0000378 XML_SCHEMAS_QNAME);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000379 xmlSchemaTypeNCNameDef = xmlSchemaInitBasicType("NCName",
Daniel Veillard6560a422003-03-27 21:25:38 +0000380 XML_SCHEMAS_NCNAME);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000381 xmlSchemaTypeNmtokenDef = xmlSchemaInitBasicType("NMTOKEN",
Daniel Veillard6560a422003-03-27 21:25:38 +0000382 XML_SCHEMAS_NMTOKEN);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000383 xmlSchemaTypeNmtokensDef = xmlSchemaInitBasicType("NMTOKENS",
Daniel Veillard6560a422003-03-27 21:25:38 +0000384 XML_SCHEMAS_NMTOKENS);
Daniel Veillard4255d502002-04-16 15:50:10 +0000385 xmlSchemaTypesInitialized = 1;
386}
387
388/**
389 * xmlSchemaCleanupTypes:
390 *
391 * Cleanup the default XML Schemas type library
392 */
393void
394xmlSchemaCleanupTypes(void) {
395 if (xmlSchemaTypesInitialized == 0)
396 return;
397 xmlHashFree(xmlSchemaTypesBank, (xmlHashDeallocator) xmlSchemaFreeType);
398 xmlSchemaTypesInitialized = 0;
399}
400
401/**
402 * xmlSchemaNewValue:
403 * @type: the value type
404 *
405 * Allocate a new simple type value
406 *
407 * Returns a pointer to the new value or NULL in case of error
408 */
409static xmlSchemaValPtr
410xmlSchemaNewValue(xmlSchemaValType type) {
411 xmlSchemaValPtr value;
412
413 value = (xmlSchemaValPtr) xmlMalloc(sizeof(xmlSchemaVal));
414 if (value == NULL) {
415 return(NULL);
416 }
417 memset(value, 0, sizeof(xmlSchemaVal));
418 value->type = type;
419 return(value);
420}
421
422/**
423 * xmlSchemaFreeValue:
424 * @value: the value to free
425 *
426 * Cleanup the default XML Schemas type library
427 */
428void
429xmlSchemaFreeValue(xmlSchemaValPtr value) {
430 if (value == NULL)
431 return;
Daniel Veillardc4c21552003-03-29 10:53:38 +0000432 switch (value->type) {
433 case XML_SCHEMAS_STRING:
434 case XML_SCHEMAS_NORMSTRING:
435 case XML_SCHEMAS_TOKEN:
436 case XML_SCHEMAS_LANGUAGE:
437 case XML_SCHEMAS_NMTOKEN:
438 case XML_SCHEMAS_NMTOKENS:
439 case XML_SCHEMAS_NAME:
Daniel Veillardc4c21552003-03-29 10:53:38 +0000440 case XML_SCHEMAS_NCNAME:
441 case XML_SCHEMAS_ID:
442 case XML_SCHEMAS_IDREF:
443 case XML_SCHEMAS_IDREFS:
444 case XML_SCHEMAS_ENTITY:
445 case XML_SCHEMAS_ENTITIES:
446 case XML_SCHEMAS_NOTATION:
447 case XML_SCHEMAS_ANYURI:
448 if (value->value.str != NULL)
449 xmlFree(value->value.str);
450 break;
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000451 case XML_SCHEMAS_QNAME:
452 if (value->value.qname.uri != NULL)
453 xmlFree(value->value.qname.uri);
454 if (value->value.qname.name != NULL)
455 xmlFree(value->value.qname.name);
456 break;
Daniel Veillard70bcb0e2003-08-08 14:00:28 +0000457 case XML_SCHEMAS_HEXBINARY:
458 if (value->value.hex.str != NULL)
459 xmlFree(value->value.hex.str);
460 break;
Daniel Veillard1ac24d32003-08-27 14:15:15 +0000461 case XML_SCHEMAS_BASE64BINARY:
462 if (value->value.base64.str != NULL)
463 xmlFree(value->value.base64.str);
464 break;
Daniel Veillardc4c21552003-03-29 10:53:38 +0000465 default:
466 break;
467 }
Daniel Veillard4255d502002-04-16 15:50:10 +0000468 xmlFree(value);
469}
470
471/**
472 * xmlSchemaGetPredefinedType:
473 * @name: the type name
474 * @ns: the URI of the namespace usually "http://www.w3.org/2001/XMLSchema"
475 *
476 * Lookup a type in the default XML Schemas type library
477 *
478 * Returns the type if found, NULL otherwise
479 */
480xmlSchemaTypePtr
481xmlSchemaGetPredefinedType(const xmlChar *name, const xmlChar *ns) {
482 if (xmlSchemaTypesInitialized == 0)
483 xmlSchemaInitTypes();
484 if (name == NULL)
485 return(NULL);
486 return((xmlSchemaTypePtr) xmlHashLookup2(xmlSchemaTypesBank, name, ns));
487}
Daniel Veillard070803b2002-05-03 07:29:38 +0000488
489/****************************************************************
490 * *
491 * Convenience macros and functions *
492 * *
493 ****************************************************************/
494
495#define IS_TZO_CHAR(c) \
496 ((c == 0) || (c == 'Z') || (c == '+') || (c == '-'))
497
498#define VALID_YEAR(yr) (yr != 0)
499#define VALID_MONTH(mon) ((mon >= 1) && (mon <= 12))
500/* VALID_DAY should only be used when month is unknown */
501#define VALID_DAY(day) ((day >= 1) && (day <= 31))
502#define VALID_HOUR(hr) ((hr >= 0) && (hr <= 23))
503#define VALID_MIN(min) ((min >= 0) && (min <= 59))
504#define VALID_SEC(sec) ((sec >= 0) && (sec < 60))
505#define VALID_TZO(tzo) ((tzo > -1440) && (tzo < 1440))
506#define IS_LEAP(y) \
507 (((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0))
508
Daniel Veillardebe25d42004-03-25 09:35:49 +0000509static const unsigned int daysInMonth[12] =
Daniel Veillard070803b2002-05-03 07:29:38 +0000510 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
Daniel Veillardebe25d42004-03-25 09:35:49 +0000511static const unsigned int daysInMonthLeap[12] =
Daniel Veillard070803b2002-05-03 07:29:38 +0000512 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
513
Daniel Veillard5a872412002-05-22 06:40:27 +0000514#define MAX_DAYINMONTH(yr,mon) \
515 (IS_LEAP(yr) ? daysInMonthLeap[mon - 1] : daysInMonth[mon - 1])
516
Daniel Veillard070803b2002-05-03 07:29:38 +0000517#define VALID_MDAY(dt) \
518 (IS_LEAP(dt->year) ? \
519 (dt->day <= daysInMonthLeap[dt->mon - 1]) : \
520 (dt->day <= daysInMonth[dt->mon - 1]))
521
522#define VALID_DATE(dt) \
523 (VALID_YEAR(dt->year) && VALID_MONTH(dt->mon) && VALID_MDAY(dt))
524
525#define VALID_TIME(dt) \
526 (VALID_HOUR(dt->hour) && VALID_MIN(dt->min) && \
527 VALID_SEC(dt->sec) && VALID_TZO(dt->tzo))
528
529#define VALID_DATETIME(dt) \
530 (VALID_DATE(dt) && VALID_TIME(dt))
531
532#define SECS_PER_MIN (60)
533#define SECS_PER_HOUR (60 * SECS_PER_MIN)
534#define SECS_PER_DAY (24 * SECS_PER_HOUR)
535
Daniel Veillard5a872412002-05-22 06:40:27 +0000536static const long dayInYearByMonth[12] =
537 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
538static const long dayInLeapYearByMonth[12] =
539 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 };
540
541#define DAY_IN_YEAR(day, month, year) \
542 ((IS_LEAP(year) ? \
543 dayInLeapYearByMonth[month - 1] : \
544 dayInYearByMonth[month - 1]) + day)
545
546#ifdef DEBUG
547#define DEBUG_DATE(dt) \
548 xmlGenericError(xmlGenericErrorContext, \
549 "type=%o %04ld-%02u-%02uT%02u:%02u:%03f", \
550 dt->type,dt->value.date.year,dt->value.date.mon, \
551 dt->value.date.day,dt->value.date.hour,dt->value.date.min, \
552 dt->value.date.sec); \
553 if (dt->value.date.tz_flag) \
554 if (dt->value.date.tzo != 0) \
555 xmlGenericError(xmlGenericErrorContext, \
556 "%+05d\n",dt->value.date.tzo); \
557 else \
558 xmlGenericError(xmlGenericErrorContext, "Z\n"); \
559 else \
560 xmlGenericError(xmlGenericErrorContext,"\n")
561#else
562#define DEBUG_DATE(dt)
563#endif
564
Daniel Veillard070803b2002-05-03 07:29:38 +0000565/**
566 * _xmlSchemaParseGYear:
567 * @dt: pointer to a date structure
568 * @str: pointer to the string to analyze
569 *
570 * Parses a xs:gYear without time zone and fills in the appropriate
571 * field of the @dt structure. @str is updated to point just after the
572 * xs:gYear. It is supposed that @dt->year is big enough to contain
573 * the year.
574 *
575 * Returns 0 or the error code
576 */
577static int
578_xmlSchemaParseGYear (xmlSchemaValDatePtr dt, const xmlChar **str) {
579 const xmlChar *cur = *str, *firstChar;
580 int isneg = 0, digcnt = 0;
581
582 if (((*cur < '0') || (*cur > '9')) &&
583 (*cur != '-') && (*cur != '+'))
584 return -1;
585
586 if (*cur == '-') {
587 isneg = 1;
588 cur++;
589 }
590
591 firstChar = cur;
592
593 while ((*cur >= '0') && (*cur <= '9')) {
594 dt->year = dt->year * 10 + (*cur - '0');
595 cur++;
596 digcnt++;
597 }
598
599 /* year must be at least 4 digits (CCYY); over 4
600 * digits cannot have a leading zero. */
601 if ((digcnt < 4) || ((digcnt > 4) && (*firstChar == '0')))
602 return 1;
603
604 if (isneg)
605 dt->year = - dt->year;
606
607 if (!VALID_YEAR(dt->year))
608 return 2;
609
610 *str = cur;
611 return 0;
612}
613
614/**
615 * PARSE_2_DIGITS:
616 * @num: the integer to fill in
617 * @cur: an #xmlChar *
618 * @invalid: an integer
619 *
620 * Parses a 2-digits integer and updates @num with the value. @cur is
621 * updated to point just after the integer.
622 * In case of error, @invalid is set to %TRUE, values of @num and
623 * @cur are undefined.
624 */
625#define PARSE_2_DIGITS(num, cur, invalid) \
626 if ((cur[0] < '0') || (cur[0] > '9') || \
627 (cur[1] < '0') || (cur[1] > '9')) \
628 invalid = 1; \
629 else \
630 num = (cur[0] - '0') * 10 + (cur[1] - '0'); \
631 cur += 2;
632
633/**
634 * PARSE_FLOAT:
635 * @num: the double to fill in
636 * @cur: an #xmlChar *
637 * @invalid: an integer
638 *
639 * Parses a float and updates @num with the value. @cur is
640 * updated to point just after the float. The float must have a
641 * 2-digits integer part and may or may not have a decimal part.
642 * In case of error, @invalid is set to %TRUE, values of @num and
643 * @cur are undefined.
644 */
645#define PARSE_FLOAT(num, cur, invalid) \
646 PARSE_2_DIGITS(num, cur, invalid); \
647 if (!invalid && (*cur == '.')) { \
648 double mult = 1; \
649 cur++; \
650 if ((*cur < '0') || (*cur > '9')) \
651 invalid = 1; \
652 while ((*cur >= '0') && (*cur <= '9')) { \
653 mult /= 10; \
654 num += (*cur - '0') * mult; \
655 cur++; \
656 } \
657 }
658
659/**
660 * _xmlSchemaParseGMonth:
661 * @dt: pointer to a date structure
662 * @str: pointer to the string to analyze
663 *
664 * Parses a xs:gMonth without time zone and fills in the appropriate
665 * field of the @dt structure. @str is updated to point just after the
666 * xs:gMonth.
667 *
668 * Returns 0 or the error code
669 */
670static int
671_xmlSchemaParseGMonth (xmlSchemaValDatePtr dt, const xmlChar **str) {
672 const xmlChar *cur = *str;
673 int ret = 0;
674
675 PARSE_2_DIGITS(dt->mon, cur, ret);
676 if (ret != 0)
677 return ret;
678
679 if (!VALID_MONTH(dt->mon))
680 return 2;
681
682 *str = cur;
683 return 0;
684}
685
686/**
687 * _xmlSchemaParseGDay:
688 * @dt: pointer to a date structure
689 * @str: pointer to the string to analyze
690 *
691 * Parses a xs:gDay without time zone and fills in the appropriate
692 * field of the @dt structure. @str is updated to point just after the
693 * xs:gDay.
694 *
695 * Returns 0 or the error code
696 */
697static int
698_xmlSchemaParseGDay (xmlSchemaValDatePtr dt, const xmlChar **str) {
699 const xmlChar *cur = *str;
700 int ret = 0;
701
702 PARSE_2_DIGITS(dt->day, cur, ret);
703 if (ret != 0)
704 return ret;
705
706 if (!VALID_DAY(dt->day))
707 return 2;
708
709 *str = cur;
710 return 0;
711}
712
713/**
714 * _xmlSchemaParseTime:
715 * @dt: pointer to a date structure
716 * @str: pointer to the string to analyze
717 *
718 * Parses a xs:time without time zone and fills in the appropriate
719 * fields of the @dt structure. @str is updated to point just after the
720 * xs:time.
721 * In case of error, values of @dt fields are undefined.
722 *
723 * Returns 0 or the error code
724 */
725static int
726_xmlSchemaParseTime (xmlSchemaValDatePtr dt, const xmlChar **str) {
727 const xmlChar *cur = *str;
728 unsigned int hour = 0; /* use temp var in case str is not xs:time */
729 int ret = 0;
730
731 PARSE_2_DIGITS(hour, cur, ret);
732 if (ret != 0)
733 return ret;
734
735 if (*cur != ':')
736 return 1;
737 cur++;
738
739 /* the ':' insures this string is xs:time */
740 dt->hour = hour;
741
742 PARSE_2_DIGITS(dt->min, cur, ret);
743 if (ret != 0)
744 return ret;
745
746 if (*cur != ':')
747 return 1;
748 cur++;
749
750 PARSE_FLOAT(dt->sec, cur, ret);
751 if (ret != 0)
752 return ret;
753
754 if (!VALID_TIME(dt))
755 return 2;
756
757 *str = cur;
758 return 0;
759}
760
761/**
762 * _xmlSchemaParseTimeZone:
763 * @dt: pointer to a date structure
764 * @str: pointer to the string to analyze
765 *
766 * Parses a time zone without time zone and fills in the appropriate
767 * field of the @dt structure. @str is updated to point just after the
768 * time zone.
769 *
770 * Returns 0 or the error code
771 */
772static int
773_xmlSchemaParseTimeZone (xmlSchemaValDatePtr dt, const xmlChar **str) {
774 const xmlChar *cur = *str;
775 int ret = 0;
776
777 if (str == NULL)
778 return -1;
779
780 switch (*cur) {
781 case 0:
782 dt->tz_flag = 0;
783 dt->tzo = 0;
784 break;
785
786 case 'Z':
787 dt->tz_flag = 1;
788 dt->tzo = 0;
789 cur++;
790 break;
791
792 case '+':
793 case '-': {
794 int isneg = 0, tmp = 0;
795 isneg = (*cur == '-');
796
797 cur++;
798
799 PARSE_2_DIGITS(tmp, cur, ret);
800 if (ret != 0)
801 return ret;
802 if (!VALID_HOUR(tmp))
803 return 2;
804
805 if (*cur != ':')
806 return 1;
807 cur++;
808
809 dt->tzo = tmp * 60;
810
811 PARSE_2_DIGITS(tmp, cur, ret);
812 if (ret != 0)
813 return ret;
814 if (!VALID_MIN(tmp))
815 return 2;
816
817 dt->tzo += tmp;
818 if (isneg)
819 dt->tzo = - dt->tzo;
820
821 if (!VALID_TZO(dt->tzo))
822 return 2;
823
Daniel Veillard5a872412002-05-22 06:40:27 +0000824 dt->tz_flag = 1;
Daniel Veillard070803b2002-05-03 07:29:38 +0000825 break;
826 }
827 default:
828 return 1;
829 }
830
831 *str = cur;
832 return 0;
833}
834
Daniel Veillard1ac24d32003-08-27 14:15:15 +0000835/**
836 * _xmlSchemaBase64Decode:
837 * @ch: a character
838 *
839 * Converts a base64 encoded character to its base 64 value.
840 *
841 * Returns 0-63 (value), 64 (pad), or -1 (not recognized)
842 */
843static int
844_xmlSchemaBase64Decode (const xmlChar ch) {
845 if (('A' <= ch) && (ch <= 'Z')) return ch - 'A';
846 if (('a' <= ch) && (ch <= 'z')) return ch - 'a' + 26;
847 if (('0' <= ch) && (ch <= '9')) return ch - '0' + 52;
848 if ('+' == ch) return 62;
849 if ('/' == ch) return 63;
850 if ('=' == ch) return 64;
851 return -1;
852}
853
Daniel Veillard070803b2002-05-03 07:29:38 +0000854/****************************************************************
855 * *
856 * XML Schema Dates/Times Datatypes Handling *
857 * *
858 ****************************************************************/
859
860/**
861 * PARSE_DIGITS:
862 * @num: the integer to fill in
863 * @cur: an #xmlChar *
864 * @num_type: an integer flag
865 *
866 * Parses a digits integer and updates @num with the value. @cur is
867 * updated to point just after the integer.
868 * In case of error, @num_type is set to -1, values of @num and
869 * @cur are undefined.
870 */
871#define PARSE_DIGITS(num, cur, num_type) \
872 if ((*cur < '0') || (*cur > '9')) \
873 num_type = -1; \
874 else \
875 while ((*cur >= '0') && (*cur <= '9')) { \
876 num = num * 10 + (*cur - '0'); \
877 cur++; \
878 }
879
880/**
881 * PARSE_NUM:
882 * @num: the double to fill in
883 * @cur: an #xmlChar *
884 * @num_type: an integer flag
885 *
886 * Parses a float or integer and updates @num with the value. @cur is
887 * updated to point just after the number. If the number is a float,
888 * then it must have an integer part and a decimal part; @num_type will
889 * be set to 1. If there is no decimal part, @num_type is set to zero.
890 * In case of error, @num_type is set to -1, values of @num and
891 * @cur are undefined.
892 */
893#define PARSE_NUM(num, cur, num_type) \
894 num = 0; \
895 PARSE_DIGITS(num, cur, num_type); \
896 if (!num_type && (*cur == '.')) { \
897 double mult = 1; \
898 cur++; \
899 if ((*cur < '0') || (*cur > '9')) \
900 num_type = -1; \
901 else \
902 num_type = 1; \
903 while ((*cur >= '0') && (*cur <= '9')) { \
904 mult /= 10; \
905 num += (*cur - '0') * mult; \
906 cur++; \
907 } \
908 }
909
910/**
Daniel Veillard5a872412002-05-22 06:40:27 +0000911 * xmlSchemaValidateDates:
Daniel Veillard455cc072003-03-31 10:13:23 +0000912 * @type: the expected type or XML_SCHEMAS_UNKNOWN
Daniel Veillard070803b2002-05-03 07:29:38 +0000913 * @dateTime: string to analyze
914 * @val: the return computed value
915 *
916 * Check that @dateTime conforms to the lexical space of one of the date types.
917 * if true a value is computed and returned in @val.
918 *
919 * Returns 0 if this validates, a positive error code number otherwise
920 * and -1 in case of internal or API error.
921 */
922static int
Daniel Veillard455cc072003-03-31 10:13:23 +0000923xmlSchemaValidateDates (xmlSchemaValType type,
Daniel Veillard118aed72002-09-24 14:13:13 +0000924 const xmlChar *dateTime, xmlSchemaValPtr *val) {
Daniel Veillard070803b2002-05-03 07:29:38 +0000925 xmlSchemaValPtr dt;
926 int ret;
927 const xmlChar *cur = dateTime;
928
929#define RETURN_TYPE_IF_VALID(t) \
930 if (IS_TZO_CHAR(*cur)) { \
931 ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur); \
932 if (ret == 0) { \
933 if (*cur != 0) \
934 goto error; \
935 dt->type = t; \
Daniel Veillard455cc072003-03-31 10:13:23 +0000936 goto done; \
Daniel Veillard070803b2002-05-03 07:29:38 +0000937 } \
938 }
939
940 if (dateTime == NULL)
941 return -1;
942
943 if ((*cur != '-') && (*cur < '0') && (*cur > '9'))
944 return 1;
945
946 dt = xmlSchemaNewValue(XML_SCHEMAS_UNKNOWN);
947 if (dt == NULL)
948 return -1;
949
950 if ((cur[0] == '-') && (cur[1] == '-')) {
951 /*
952 * It's an incomplete date (xs:gMonthDay, xs:gMonth or
953 * xs:gDay)
954 */
955 cur += 2;
956
957 /* is it an xs:gDay? */
958 if (*cur == '-') {
Daniel Veillard455cc072003-03-31 10:13:23 +0000959 if (type == XML_SCHEMAS_GMONTH)
960 goto error;
Daniel Veillard070803b2002-05-03 07:29:38 +0000961 ++cur;
962 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
963 if (ret != 0)
964 goto error;
965
966 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GDAY);
967
968 goto error;
969 }
970
971 /*
972 * it should be an xs:gMonthDay or xs:gMonth
973 */
974 ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
975 if (ret != 0)
976 goto error;
977
Daniel Veillardd3b9cd82003-04-09 11:24:17 +0000978 /*
979 * a '-' char could indicate this type is xs:gMonthDay or
980 * a negative time zone offset. Check for xs:gMonthDay first.
981 * Also the first three char's of a negative tzo (-MM:SS) can
982 * appear to be a valid day; so even if the day portion
983 * of the xs:gMonthDay verifies, we must insure it was not
984 * a tzo.
985 */
986 if (*cur == '-') {
987 const xmlChar *rewnd = cur;
988 cur++;
Daniel Veillard070803b2002-05-03 07:29:38 +0000989
Daniel Veillardd3b9cd82003-04-09 11:24:17 +0000990 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
991 if ((ret == 0) && ((*cur == 0) || (*cur != ':'))) {
992
993 /*
994 * we can use the VALID_MDAY macro to validate the month
995 * and day because the leap year test will flag year zero
996 * as a leap year (even though zero is an invalid year).
997 */
998 if (VALID_MDAY((&(dt->value.date)))) {
999
1000 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTHDAY);
1001
1002 goto error;
1003 }
1004 }
1005
1006 /*
1007 * not xs:gMonthDay so rewind and check if just xs:gMonth
1008 * with an optional time zone.
1009 */
1010 cur = rewnd;
1011 }
1012
1013 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTH);
Daniel Veillard070803b2002-05-03 07:29:38 +00001014
1015 goto error;
1016 }
1017
1018 /*
1019 * It's a right-truncated date or an xs:time.
1020 * Try to parse an xs:time then fallback on right-truncated dates.
1021 */
1022 if ((*cur >= '0') && (*cur <= '9')) {
1023 ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
1024 if (ret == 0) {
1025 /* it's an xs:time */
1026 RETURN_TYPE_IF_VALID(XML_SCHEMAS_TIME);
1027 }
1028 }
1029
1030 /* fallback on date parsing */
1031 cur = dateTime;
1032
1033 ret = _xmlSchemaParseGYear(&(dt->value.date), &cur);
1034 if (ret != 0)
1035 goto error;
1036
1037 /* is it an xs:gYear? */
1038 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEAR);
1039
1040 if (*cur != '-')
1041 goto error;
1042 cur++;
1043
1044 ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
1045 if (ret != 0)
1046 goto error;
1047
1048 /* is it an xs:gYearMonth? */
1049 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEARMONTH);
1050
1051 if (*cur != '-')
1052 goto error;
1053 cur++;
1054
1055 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
1056 if ((ret != 0) || !VALID_DATE((&(dt->value.date))))
1057 goto error;
1058
1059 /* is it an xs:date? */
1060 RETURN_TYPE_IF_VALID(XML_SCHEMAS_DATE);
1061
1062 if (*cur != 'T')
1063 goto error;
1064 cur++;
1065
1066 /* it should be an xs:dateTime */
1067 ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
1068 if (ret != 0)
1069 goto error;
1070
1071 ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur);
1072 if ((ret != 0) || (*cur != 0) || !VALID_DATETIME((&(dt->value.date))))
1073 goto error;
1074
Daniel Veillard455cc072003-03-31 10:13:23 +00001075
Daniel Veillard070803b2002-05-03 07:29:38 +00001076 dt->type = XML_SCHEMAS_DATETIME;
1077
Daniel Veillard455cc072003-03-31 10:13:23 +00001078done:
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001079#if 1
1080 if ((type != XML_SCHEMAS_UNKNOWN) && (type != dt->type))
1081 goto error;
1082#else
1083 /*
1084 * insure the parsed type is equal to or less significant (right
1085 * truncated) than the desired type.
1086 */
1087 if ((type != XML_SCHEMAS_UNKNOWN) && (type != dt->type)) {
1088
1089 /* time only matches time */
1090 if ((type == XML_SCHEMAS_TIME) && (dt->type == XML_SCHEMAS_TIME))
1091 goto error;
1092
1093 if ((type == XML_SCHEMAS_DATETIME) &&
1094 ((dt->type != XML_SCHEMAS_DATE) ||
1095 (dt->type != XML_SCHEMAS_GYEARMONTH) ||
1096 (dt->type != XML_SCHEMAS_GYEAR)))
1097 goto error;
1098
1099 if ((type == XML_SCHEMAS_DATE) &&
1100 ((dt->type != XML_SCHEMAS_GYEAR) ||
1101 (dt->type != XML_SCHEMAS_GYEARMONTH)))
1102 goto error;
1103
1104 if ((type == XML_SCHEMAS_GYEARMONTH) && (dt->type != XML_SCHEMAS_GYEAR))
1105 goto error;
1106
1107 if ((type == XML_SCHEMAS_GMONTHDAY) && (dt->type != XML_SCHEMAS_GMONTH))
1108 goto error;
1109 }
Daniel Veillard455cc072003-03-31 10:13:23 +00001110#endif
1111
Daniel Veillard070803b2002-05-03 07:29:38 +00001112 if (val != NULL)
1113 *val = dt;
Daniel Veillard80b19092003-03-28 13:29:53 +00001114 else
1115 xmlSchemaFreeValue(dt);
Daniel Veillard070803b2002-05-03 07:29:38 +00001116
1117 return 0;
1118
1119error:
1120 if (dt != NULL)
1121 xmlSchemaFreeValue(dt);
1122 return 1;
1123}
1124
1125/**
Daniel Veillard5a872412002-05-22 06:40:27 +00001126 * xmlSchemaValidateDuration:
Daniel Veillard070803b2002-05-03 07:29:38 +00001127 * @type: the predefined type
1128 * @duration: string to analyze
1129 * @val: the return computed value
1130 *
1131 * Check that @duration conforms to the lexical space of the duration type.
1132 * if true a value is computed and returned in @val.
1133 *
1134 * Returns 0 if this validates, a positive error code number otherwise
1135 * and -1 in case of internal or API error.
1136 */
1137static int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00001138xmlSchemaValidateDuration (xmlSchemaTypePtr type ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +00001139 const xmlChar *duration, xmlSchemaValPtr *val) {
Daniel Veillard070803b2002-05-03 07:29:38 +00001140 const xmlChar *cur = duration;
1141 xmlSchemaValPtr dur;
1142 int isneg = 0;
1143 unsigned int seq = 0;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001144 double num;
1145 int num_type = 0; /* -1 = invalid, 0 = int, 1 = floating */
1146 const xmlChar desig[] = {'Y', 'M', 'D', 'H', 'M', 'S'};
1147 const double multi[] = { 0.0, 0.0, 86400.0, 3600.0, 60.0, 1.0, 0.0};
Daniel Veillard070803b2002-05-03 07:29:38 +00001148
1149 if (duration == NULL)
1150 return -1;
1151
1152 if (*cur == '-') {
1153 isneg = 1;
1154 cur++;
1155 }
1156
1157 /* duration must start with 'P' (after sign) */
1158 if (*cur++ != 'P')
1159 return 1;
1160
Daniel Veillard80b19092003-03-28 13:29:53 +00001161 if (*cur == 0)
1162 return 1;
1163
Daniel Veillard070803b2002-05-03 07:29:38 +00001164 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
1165 if (dur == NULL)
1166 return -1;
1167
1168 while (*cur != 0) {
Daniel Veillard070803b2002-05-03 07:29:38 +00001169
1170 /* input string should be empty or invalid date/time item */
1171 if (seq >= sizeof(desig))
1172 goto error;
1173
1174 /* T designator must be present for time items */
1175 if (*cur == 'T') {
1176 if (seq <= 3) {
1177 seq = 3;
1178 cur++;
1179 } else
1180 return 1;
1181 } else if (seq == 3)
1182 goto error;
1183
1184 /* parse the number portion of the item */
1185 PARSE_NUM(num, cur, num_type);
1186
1187 if ((num_type == -1) || (*cur == 0))
1188 goto error;
1189
1190 /* update duration based on item type */
1191 while (seq < sizeof(desig)) {
1192 if (*cur == desig[seq]) {
1193
1194 /* verify numeric type; only seconds can be float */
1195 if ((num_type != 0) && (seq < (sizeof(desig)-1)))
1196 goto error;
1197
1198 switch (seq) {
1199 case 0:
1200 dur->value.dur.mon = (long)num * 12;
1201 break;
1202 case 1:
1203 dur->value.dur.mon += (long)num;
1204 break;
1205 default:
1206 /* convert to seconds using multiplier */
1207 dur->value.dur.sec += num * multi[seq];
1208 seq++;
1209 break;
1210 }
1211
1212 break; /* exit loop */
1213 }
1214 /* no date designators found? */
1215 if (++seq == 3)
1216 goto error;
1217 }
1218 cur++;
1219 }
1220
1221 if (isneg) {
1222 dur->value.dur.mon = -dur->value.dur.mon;
1223 dur->value.dur.day = -dur->value.dur.day;
1224 dur->value.dur.sec = -dur->value.dur.sec;
1225 }
1226
1227 if (val != NULL)
1228 *val = dur;
Daniel Veillard80b19092003-03-28 13:29:53 +00001229 else
1230 xmlSchemaFreeValue(dur);
Daniel Veillard070803b2002-05-03 07:29:38 +00001231
1232 return 0;
1233
1234error:
1235 if (dur != NULL)
1236 xmlSchemaFreeValue(dur);
1237 return 1;
1238}
1239
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001240/**
1241 * xmlSchemaStrip:
1242 * @value: a value
1243 *
1244 * Removes the leading and ending spaces of a string
1245 *
1246 * Returns the new string or NULL if no change was required.
1247 */
1248static xmlChar *
1249xmlSchemaStrip(const xmlChar *value) {
1250 const xmlChar *start = value, *end, *f;
1251
1252 if (value == NULL) return(NULL);
William M. Brack76e95df2003-10-18 16:20:14 +00001253 while ((*start != 0) && (IS_BLANK_CH(*start))) start++;
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001254 end = start;
1255 while (*end != 0) end++;
1256 f = end;
1257 end--;
William M. Brack76e95df2003-10-18 16:20:14 +00001258 while ((end > start) && (IS_BLANK_CH(*end))) end--;
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001259 end++;
1260 if ((start == value) && (f == end)) return(NULL);
1261 return(xmlStrndup(start, end - start));
1262}
Daniel Veillard96a4b252003-02-06 08:22:32 +00001263
1264/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001265 * xmlSchemaCollapseString:
1266 * @value: a value
1267 *
1268 * Removes and normalize white spaces in the string
1269 *
1270 * Returns the new string or NULL if no change was required.
1271 */
1272static xmlChar *
1273xmlSchemaCollapseString(const xmlChar *value) {
1274 const xmlChar *start = value, *end, *f;
1275 xmlChar *g;
1276 int col = 0;
1277
1278 if (value == NULL) return(NULL);
William M. Brack76e95df2003-10-18 16:20:14 +00001279 while ((*start != 0) && (IS_BLANK_CH(*start))) start++;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001280 end = start;
1281 while (*end != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00001282 if ((*end == ' ') && (IS_BLANK_CH(end[1]))) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001283 col = end - start;
1284 break;
1285 } else if ((*end == 0xa) || (*end == 0x9) || (*end == 0xd)) {
1286 col = end - start;
1287 break;
1288 }
1289 end++;
1290 }
1291 if (col == 0) {
1292 f = end;
1293 end--;
William M. Brack76e95df2003-10-18 16:20:14 +00001294 while ((end > start) && (IS_BLANK_CH(*end))) end--;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001295 end++;
1296 if ((start == value) && (f == end)) return(NULL);
1297 return(xmlStrndup(start, end - start));
1298 }
1299 start = xmlStrdup(start);
1300 if (start == NULL) return(NULL);
1301 g = (xmlChar *) (start + col);
1302 end = g;
1303 while (*end != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00001304 if (IS_BLANK_CH(*end)) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001305 end++;
William M. Brack76e95df2003-10-18 16:20:14 +00001306 while (IS_BLANK_CH(*end)) end++;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001307 if (*end != 0)
1308 *g++ = ' ';
1309 } else
1310 *g++ = *end++;
1311 }
1312 *g = 0;
1313 return((xmlChar *) start);
1314}
1315
1316/**
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001317 * xmlSchemaValAtomicListNode:
1318 * @type: the predefined atomic type for a token in the list
1319 * @value: the list value to check
1320 * @ret: the return computed value
1321 * @node: the node containing the value
1322 *
1323 * Check that a value conforms to the lexical space of the predefined
1324 * list type. if true a value is computed and returned in @ret.
1325 *
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001326 * Returns the number of items if this validates, a negative error code
1327 * number otherwise
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001328 */
1329static int
1330xmlSchemaValAtomicListNode(xmlSchemaTypePtr type, const xmlChar *value,
1331 xmlSchemaValPtr *ret, xmlNodePtr node) {
1332 xmlChar *val, *cur, *endval;
1333 int nb_values = 0;
Daniel Veillard580ced82003-03-21 21:22:48 +00001334 int tmp = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001335
1336 if (value == NULL) {
1337 return(-1);
1338 }
1339 val = xmlStrdup(value);
1340 if (val == NULL) {
1341 return(-1);
1342 }
1343 cur = val;
1344 /*
1345 * Split the list
1346 */
William M. Brack76e95df2003-10-18 16:20:14 +00001347 while (IS_BLANK_CH(*cur)) *cur++ = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001348 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00001349 if (IS_BLANK_CH(*cur)) {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001350 *cur = 0;
1351 cur++;
William M. Brack76e95df2003-10-18 16:20:14 +00001352 while (IS_BLANK_CH(*cur)) *cur++ = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001353 } else {
1354 nb_values++;
1355 cur++;
William M. Brack76e95df2003-10-18 16:20:14 +00001356 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001357 }
1358 }
1359 if (nb_values == 0) {
1360 if (ret != NULL) {
1361 TODO
1362 }
1363 xmlFree(val);
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001364 return(nb_values);
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001365 }
1366 endval = cur;
1367 cur = val;
1368 while ((*cur == 0) && (cur != endval)) cur++;
1369 while (cur != endval) {
1370 tmp = xmlSchemaValPredefTypeNode(type, cur, NULL, node);
1371 if (tmp != 0)
1372 break;
1373 while (*cur != 0) cur++;
1374 while ((*cur == 0) && (cur != endval)) cur++;
1375 }
1376 xmlFree(val);
1377 if (ret != NULL) {
1378 TODO
1379 }
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001380 if (tmp == 0)
1381 return(nb_values);
1382 return(-1);
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001383}
1384
1385/**
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001386 * xmlSchemaParseUInt:
1387 * @str: pointer to the string R/W
1388 * @llo: pointer to the low result
1389 * @lmi: pointer to the mid result
1390 * @lhi: pointer to the high result
1391 *
1392 * Parse an unsigned long into 3 fields.
1393 *
1394 * Returns the number of chars parsed or -1 if overflow of the capacity
1395 */
1396static int
1397xmlSchemaParseUInt(const xmlChar **str, unsigned long *llo,
1398 unsigned long *lmi, unsigned long *lhi) {
1399 unsigned long lo = 0, mi = 0, hi = 0;
1400 const xmlChar *tmp, *cur = *str;
1401 int ret = 0, i = 0;
1402
1403 while (*cur == '0') {
1404 ret++;
1405 cur++;
1406 }
1407 tmp = cur;
1408 while ((*tmp != 0) && (*tmp >= '0') && (*tmp <= '9')) {
1409 i++;tmp++;ret++;
1410 }
1411 if (i > 24) {
1412 *str = tmp;
1413 return(-1);
1414 }
1415 while (i > 16) {
1416 hi = hi * 10 + (*cur++ - '0');
1417 i--;
1418 }
1419 while (i > 8) {
1420 mi = mi * 10 + (*cur++ - '0');
1421 i--;
1422 }
1423 while (i > 0) {
1424 lo = lo * 10 + (*cur++ - '0');
1425 i--;
1426 }
1427
1428 *str = cur;
1429 *llo = lo;
1430 *lmi = mi;
1431 *lhi = hi;
1432 return(ret);
1433}
1434
1435/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001436 * xmlSchemaValAtomicType:
1437 * @type: the predefined type
1438 * @value: the value to check
1439 * @val: the return computed value
1440 * @node: the node containing the value
1441 * flags: flags to control the vlidation
1442 *
1443 * Check that a value conforms to the lexical space of the atomic type.
1444 * if true a value is computed and returned in @val.
1445 *
1446 * Returns 0 if this validates, a positive error code number otherwise
1447 * and -1 in case of internal or API error.
1448 */
1449static int
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001450xmlSchemaValAtomicType(xmlSchemaTypePtr type, const xmlChar * value,
1451 xmlSchemaValPtr * val, xmlNodePtr node, int flags)
1452{
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001453 xmlSchemaValPtr v;
1454 xmlChar *norm = NULL;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001455 int ret = 0;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001456
1457 if (xmlSchemaTypesInitialized == 0)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001458 return (-1);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001459 if (type == NULL)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001460 return (-1);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001461
1462 if (val != NULL)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001463 *val = NULL;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001464 if ((flags == 0) && (value != NULL)) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001465 if ((type->flags != XML_SCHEMAS_STRING) &&
1466 (type->flags != XML_SCHEMAS_NORMSTRING)) {
1467 norm = xmlSchemaCollapseString(value);
1468 if (norm != NULL)
1469 value = norm;
1470 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001471 }
1472
1473 switch (type->flags) {
1474 case XML_SCHEMAS_UNKNOWN:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001475 if (type == xmlSchemaTypeAnyTypeDef)
1476 goto return0;
1477 goto error;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001478 case XML_SCHEMAS_STRING:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001479 goto return0;
Daniel Veillard1516d5b2004-01-22 07:27:45 +00001480 case XML_SCHEMAS_NORMSTRING:{
1481 const xmlChar *cur = value;
1482
1483 while (*cur != 0) {
1484 if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) {
1485 goto return1;
1486 } else {
1487 cur++;
1488 }
1489 }
1490 if (val != NULL) {
1491 v = xmlSchemaNewValue(XML_SCHEMAS_NORMSTRING);
1492 if (v != NULL) {
1493 v->value.str = xmlStrdup(value);
1494 *val = v;
1495 } else {
1496 goto error;
1497 }
1498 }
1499 goto return0;
1500 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001501 case XML_SCHEMAS_DECIMAL:{
1502 const xmlChar *cur = value, *tmp;
1503 unsigned int frac = 0, len, neg = 0;
1504 unsigned long base = 0;
1505
1506 if (cur == NULL)
1507 goto return1;
1508 if (*cur == '+')
1509 cur++;
1510 else if (*cur == '-') {
1511 neg = 1;
1512 cur++;
1513 }
1514 tmp = cur;
1515 while ((*cur >= '0') && (*cur <= '9')) {
1516 base = base * 10 + (*cur - '0');
1517 cur++;
1518 }
1519 len = cur - tmp;
1520 if (*cur == '.') {
1521 cur++;
1522 tmp = cur;
1523 while ((*cur >= '0') && (*cur <= '9')) {
1524 base = base * 10 + (*cur - '0');
1525 cur++;
1526 }
1527 frac = cur - tmp;
1528 }
1529 if (*cur != 0)
1530 goto return1;
1531 if (val != NULL) {
1532 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
1533 if (v != NULL) {
1534 v->value.decimal.lo = base;
1535 v->value.decimal.sign = neg;
1536 v->value.decimal.frac = frac;
1537 v->value.decimal.total = frac + len;
1538 *val = v;
1539 }
1540 }
1541 goto return0;
1542 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001543 case XML_SCHEMAS_TIME:
1544 case XML_SCHEMAS_GDAY:
1545 case XML_SCHEMAS_GMONTH:
1546 case XML_SCHEMAS_GMONTHDAY:
1547 case XML_SCHEMAS_GYEAR:
1548 case XML_SCHEMAS_GYEARMONTH:
1549 case XML_SCHEMAS_DATE:
1550 case XML_SCHEMAS_DATETIME:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001551 ret = xmlSchemaValidateDates(type->flags, value, val);
1552 break;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001553 case XML_SCHEMAS_DURATION:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001554 ret = xmlSchemaValidateDuration(type, value, val);
1555 break;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001556 case XML_SCHEMAS_FLOAT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001557 case XML_SCHEMAS_DOUBLE:{
1558 const xmlChar *cur = value;
1559 int neg = 0;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001560
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001561 if (cur == NULL)
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00001562 goto return1;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001563 if ((cur[0] == 'N') && (cur[1] == 'a') && (cur[2] == 'N')) {
1564 cur += 3;
1565 if (*cur != 0)
1566 goto return1;
1567 if (val != NULL) {
1568 if (type == xmlSchemaTypeFloatDef) {
1569 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1570 if (v != NULL) {
1571 v->value.f = (float) xmlXPathNAN;
1572 } else {
1573 xmlSchemaFreeValue(v);
1574 goto error;
1575 }
1576 } else {
1577 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1578 if (v != NULL) {
1579 v->value.d = xmlXPathNAN;
1580 } else {
1581 xmlSchemaFreeValue(v);
1582 goto error;
1583 }
1584 }
1585 *val = v;
1586 }
1587 goto return0;
1588 }
1589 if (*cur == '-') {
1590 neg = 1;
1591 cur++;
1592 }
1593 if ((cur[0] == 'I') && (cur[1] == 'N') && (cur[2] == 'F')) {
1594 cur += 3;
1595 if (*cur != 0)
1596 goto return1;
1597 if (val != NULL) {
1598 if (type == xmlSchemaTypeFloatDef) {
1599 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1600 if (v != NULL) {
1601 if (neg)
1602 v->value.f = (float) xmlXPathNINF;
1603 else
1604 v->value.f = (float) xmlXPathPINF;
1605 } else {
1606 xmlSchemaFreeValue(v);
1607 goto error;
1608 }
1609 } else {
1610 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1611 if (v != NULL) {
1612 if (neg)
1613 v->value.d = xmlXPathNINF;
1614 else
1615 v->value.d = xmlXPathPINF;
1616 } else {
1617 xmlSchemaFreeValue(v);
1618 goto error;
1619 }
1620 }
1621 *val = v;
1622 }
1623 goto return0;
1624 }
1625 if ((neg == 0) && (*cur == '+'))
1626 cur++;
1627 if ((cur[0] == 0) || (cur[0] == '+') || (cur[0] == '-'))
1628 goto return1;
1629 while ((*cur >= '0') && (*cur <= '9')) {
1630 cur++;
1631 }
1632 if (*cur == '.') {
1633 cur++;
1634 while ((*cur >= '0') && (*cur <= '9'))
1635 cur++;
1636 }
1637 if ((*cur == 'e') || (*cur == 'E')) {
1638 cur++;
1639 if ((*cur == '-') || (*cur == '+'))
1640 cur++;
1641 while ((*cur >= '0') && (*cur <= '9'))
1642 cur++;
1643 }
1644 if (*cur != 0)
1645 goto return1;
1646 if (val != NULL) {
1647 if (type == xmlSchemaTypeFloatDef) {
1648 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1649 if (v != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001650 if (sscanf((const char *) value, "%f",
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001651 &(v->value.f)) == 1) {
1652 *val = v;
1653 } else {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001654 xmlSchemaFreeValue(v);
1655 goto return1;
1656 }
1657 } else {
1658 goto error;
1659 }
1660 } else {
1661 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1662 if (v != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001663 if (sscanf((const char *) value, "%lf",
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001664 &(v->value.d)) == 1) {
1665 *val = v;
1666 } else {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001667 xmlSchemaFreeValue(v);
1668 goto return1;
1669 }
1670 } else {
1671 goto error;
1672 }
1673 }
1674 }
1675 goto return0;
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00001676 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001677 case XML_SCHEMAS_BOOLEAN:{
1678 const xmlChar *cur = value;
1679
1680 if ((cur[0] == '0') && (cur[1] == 0))
1681 ret = 0;
1682 else if ((cur[0] == '1') && (cur[1] == 0))
1683 ret = 1;
1684 else if ((cur[0] == 't') && (cur[1] == 'r')
1685 && (cur[2] == 'u') && (cur[3] == 'e')
1686 && (cur[4] == 0))
1687 ret = 1;
1688 else if ((cur[0] == 'f') && (cur[1] == 'a')
1689 && (cur[2] == 'l') && (cur[3] == 's')
1690 && (cur[4] == 'e') && (cur[5] == 0))
1691 ret = 0;
1692 else
1693 goto return1;
1694 if (val != NULL) {
1695 v = xmlSchemaNewValue(XML_SCHEMAS_BOOLEAN);
1696 if (v != NULL) {
1697 v->value.b = ret;
1698 *val = v;
1699 } else {
1700 goto error;
1701 }
1702 }
1703 goto return0;
1704 }
1705 case XML_SCHEMAS_TOKEN:{
1706 const xmlChar *cur = value;
1707
William M. Brack76e95df2003-10-18 16:20:14 +00001708 if (IS_BLANK_CH(*cur))
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001709 goto return1;
1710
1711 while (*cur != 0) {
1712 if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) {
1713 goto return1;
1714 } else if (*cur == ' ') {
1715 cur++;
1716 if (*cur == 0)
1717 goto return1;
1718 if (*cur == ' ')
1719 goto return1;
1720 } else {
1721 cur++;
1722 }
1723 }
1724 if (val != NULL) {
1725 v = xmlSchemaNewValue(XML_SCHEMAS_TOKEN);
1726 if (v != NULL) {
1727 v->value.str = xmlStrdup(value);
1728 *val = v;
1729 } else {
1730 goto error;
1731 }
1732 }
1733 goto return0;
1734 }
1735 case XML_SCHEMAS_LANGUAGE:
1736 if (xmlCheckLanguageID(value) == 1) {
1737 if (val != NULL) {
1738 v = xmlSchemaNewValue(XML_SCHEMAS_LANGUAGE);
1739 if (v != NULL) {
1740 v->value.str = xmlStrdup(value);
1741 *val = v;
1742 } else {
1743 goto error;
1744 }
1745 }
1746 goto return0;
1747 }
1748 goto return1;
1749 case XML_SCHEMAS_NMTOKEN:
1750 if (xmlValidateNMToken(value, 1) == 0) {
1751 if (val != NULL) {
1752 v = xmlSchemaNewValue(XML_SCHEMAS_NMTOKEN);
1753 if (v != NULL) {
1754 v->value.str = xmlStrdup(value);
1755 *val = v;
1756 } else {
1757 goto error;
1758 }
1759 }
1760 goto return0;
1761 }
1762 goto return1;
1763 case XML_SCHEMAS_NMTOKENS:
1764 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeNmtokenDef,
1765 value, val, node);
1766 if (ret > 0)
1767 ret = 0;
1768 else
1769 ret = 1;
1770 goto done;
1771 case XML_SCHEMAS_NAME:
1772 ret = xmlValidateName(value, 1);
1773 if ((ret == 0) && (val != NULL)) {
1774 TODO;
1775 }
1776 goto done;
1777 case XML_SCHEMAS_QNAME:{
1778 xmlChar *uri = NULL;
1779 xmlChar *local = NULL;
1780
1781 ret = xmlValidateQName(value, 1);
1782 if ((ret == 0) && (node != NULL)) {
1783 xmlChar *prefix;
1784
1785 local = xmlSplitQName2(value, &prefix);
1786 if (prefix != NULL) {
1787 xmlNsPtr ns;
1788
1789 ns = xmlSearchNs(node->doc, node, prefix);
1790 if (ns == NULL)
1791 ret = 1;
1792 else if (val != NULL)
1793 uri = xmlStrdup(ns->href);
1794 }
1795 if ((local != NULL) && ((val == NULL) || (ret != 0)))
1796 xmlFree(local);
1797 if (prefix != NULL)
1798 xmlFree(prefix);
1799 }
1800 if ((ret == 0) && (val != NULL)) {
1801 v = xmlSchemaNewValue(XML_SCHEMAS_QNAME);
1802 if (v != NULL) {
1803 if (local != NULL)
1804 v->value.qname.name = local;
1805 else
1806 v->value.qname.name = xmlStrdup(value);
1807 if (uri != NULL)
1808 v->value.qname.uri = uri;
1809
1810 *val = v;
1811 } else {
1812 if (local != NULL)
1813 xmlFree(local);
1814 if (uri != NULL)
1815 xmlFree(uri);
1816 goto error;
1817 }
1818 }
1819 goto done;
1820 }
1821 case XML_SCHEMAS_NCNAME:
1822 ret = xmlValidateNCName(value, 1);
1823 if ((ret == 0) && (val != NULL)) {
1824 v = xmlSchemaNewValue(XML_SCHEMAS_NCNAME);
1825 if (v != NULL) {
1826 v->value.str = xmlStrdup(value);
1827 *val = v;
1828 } else {
1829 goto error;
1830 }
1831 }
1832 goto done;
1833 case XML_SCHEMAS_ID:
1834 ret = xmlValidateNCName(value, 1);
1835 if ((ret == 0) && (val != NULL)) {
1836 v = xmlSchemaNewValue(XML_SCHEMAS_ID);
1837 if (v != NULL) {
1838 v->value.str = xmlStrdup(value);
1839 *val = v;
1840 } else {
1841 goto error;
1842 }
1843 }
1844 if ((ret == 0) && (node != NULL) &&
1845 (node->type == XML_ATTRIBUTE_NODE)) {
1846 xmlAttrPtr attr = (xmlAttrPtr) node;
1847
1848 /*
1849 * NOTE: the IDness might have already be declared in the DTD
1850 */
1851 if (attr->atype != XML_ATTRIBUTE_ID) {
1852 xmlIDPtr res;
1853 xmlChar *strip;
1854
1855 strip = xmlSchemaStrip(value);
1856 if (strip != NULL) {
1857 res = xmlAddID(NULL, node->doc, strip, attr);
1858 xmlFree(strip);
1859 } else
1860 res = xmlAddID(NULL, node->doc, value, attr);
1861 if (res == NULL) {
1862 ret = 2;
1863 } else {
1864 attr->atype = XML_ATTRIBUTE_ID;
1865 }
1866 }
1867 }
1868 goto done;
1869 case XML_SCHEMAS_IDREF:
1870 ret = xmlValidateNCName(value, 1);
1871 if ((ret == 0) && (val != NULL)) {
1872 TODO;
1873 }
1874 if ((ret == 0) && (node != NULL) &&
1875 (node->type == XML_ATTRIBUTE_NODE)) {
1876 xmlAttrPtr attr = (xmlAttrPtr) node;
1877 xmlChar *strip;
1878
1879 strip = xmlSchemaStrip(value);
1880 if (strip != NULL) {
1881 xmlAddRef(NULL, node->doc, strip, attr);
1882 xmlFree(strip);
1883 } else
1884 xmlAddRef(NULL, node->doc, value, attr);
1885 attr->atype = XML_ATTRIBUTE_IDREF;
1886 }
1887 goto done;
1888 case XML_SCHEMAS_IDREFS:
1889 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeIdrefDef,
1890 value, val, node);
1891 if (ret < 0)
1892 ret = 2;
1893 else
1894 ret = 0;
1895 if ((ret == 0) && (node != NULL) &&
1896 (node->type == XML_ATTRIBUTE_NODE)) {
1897 xmlAttrPtr attr = (xmlAttrPtr) node;
1898
1899 attr->atype = XML_ATTRIBUTE_IDREFS;
1900 }
1901 goto done;
1902 case XML_SCHEMAS_ENTITY:{
1903 xmlChar *strip;
1904
1905 ret = xmlValidateNCName(value, 1);
1906 if ((node == NULL) || (node->doc == NULL))
1907 ret = 3;
1908 if (ret == 0) {
1909 xmlEntityPtr ent;
1910
1911 strip = xmlSchemaStrip(value);
1912 if (strip != NULL) {
1913 ent = xmlGetDocEntity(node->doc, strip);
1914 xmlFree(strip);
1915 } else {
1916 ent = xmlGetDocEntity(node->doc, value);
1917 }
1918 if ((ent == NULL) ||
1919 (ent->etype !=
1920 XML_EXTERNAL_GENERAL_UNPARSED_ENTITY))
1921 ret = 4;
1922 }
1923 if ((ret == 0) && (val != NULL)) {
1924 TODO;
1925 }
1926 if ((ret == 0) && (node != NULL) &&
1927 (node->type == XML_ATTRIBUTE_NODE)) {
1928 xmlAttrPtr attr = (xmlAttrPtr) node;
1929
1930 attr->atype = XML_ATTRIBUTE_ENTITY;
1931 }
1932 goto done;
1933 }
1934 case XML_SCHEMAS_ENTITIES:
1935 if ((node == NULL) || (node->doc == NULL))
1936 goto return3;
1937 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeEntityDef,
1938 value, val, node);
1939 if (ret <= 0)
1940 ret = 1;
1941 else
1942 ret = 0;
1943 if ((ret == 0) && (node != NULL) &&
1944 (node->type == XML_ATTRIBUTE_NODE)) {
1945 xmlAttrPtr attr = (xmlAttrPtr) node;
1946
1947 attr->atype = XML_ATTRIBUTE_ENTITIES;
1948 }
1949 goto done;
1950 case XML_SCHEMAS_NOTATION:{
1951 xmlChar *uri = NULL;
1952 xmlChar *local = NULL;
1953
1954 ret = xmlValidateQName(value, 1);
1955 if ((ret == 0) && (node != NULL)) {
1956 xmlChar *prefix;
1957
1958 local = xmlSplitQName2(value, &prefix);
1959 if (prefix != NULL) {
1960 xmlNsPtr ns;
1961
1962 ns = xmlSearchNs(node->doc, node, prefix);
1963 if (ns == NULL)
1964 ret = 1;
1965 else if (val != NULL)
1966 uri = xmlStrdup(ns->href);
1967 }
1968 if ((local != NULL) && ((val == NULL) || (ret != 0)))
1969 xmlFree(local);
1970 if (prefix != NULL)
1971 xmlFree(prefix);
1972 }
1973 if ((node == NULL) || (node->doc == NULL))
1974 ret = 3;
1975 if (ret == 0) {
1976 ret = xmlValidateNotationUse(NULL, node->doc, value);
1977 if (ret == 1)
1978 ret = 0;
1979 else
1980 ret = 1;
1981 }
1982 if ((ret == 0) && (val != NULL)) {
1983 v = xmlSchemaNewValue(XML_SCHEMAS_NOTATION);
1984 if (v != NULL) {
1985 if (local != NULL)
1986 v->value.qname.name = local;
1987 else
1988 v->value.qname.name = xmlStrdup(value);
1989 if (uri != NULL)
1990 v->value.qname.uri = uri;
1991
1992 *val = v;
1993 } else {
1994 if (local != NULL)
1995 xmlFree(local);
1996 if (uri != NULL)
1997 xmlFree(uri);
1998 goto error;
1999 }
2000 }
2001 goto done;
2002 }
2003 case XML_SCHEMAS_ANYURI:{
Daniel Veillard11c466a2004-03-14 12:20:15 +00002004 if (*value != 0) {
2005 xmlURIPtr uri = xmlParseURI((const char *) value);
2006 if (uri == NULL)
2007 goto return1;
2008 xmlFreeURI(uri);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002009 }
Daniel Veillard11c466a2004-03-14 12:20:15 +00002010
2011 if (val != NULL) {
2012 v = xmlSchemaNewValue(XML_SCHEMAS_ANYURI);
2013 if (v == NULL)
2014 goto error;
2015 v->value.str = xmlStrdup(value);
2016 *val = v;
2017 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002018 goto return0;
2019 }
2020 case XML_SCHEMAS_HEXBINARY:{
2021 const xmlChar *cur = value;
2022 xmlChar *base;
2023 int total, i = 0;
2024
2025 if (cur == NULL)
2026 goto return1;
2027
2028 while (((*cur >= '0') && (*cur <= '9')) ||
2029 ((*cur >= 'A') && (*cur <= 'F')) ||
2030 ((*cur >= 'a') && (*cur <= 'f'))) {
2031 i++;
2032 cur++;
2033 }
2034
2035 if (*cur != 0)
2036 goto return1;
2037 if ((i % 2) != 0)
2038 goto return1;
2039
2040 if (val != NULL) {
2041
2042 v = xmlSchemaNewValue(XML_SCHEMAS_HEXBINARY);
2043 if (v == NULL)
2044 goto error;
2045
2046 cur = xmlStrdup(value);
2047 if (cur == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002048 xmlSchemaTypeErrMemory(node, "allocating hexbin data");
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002049 xmlFree(v);
2050 goto return1;
2051 }
2052
2053 total = i / 2; /* number of octets */
2054
2055 base = (xmlChar *) cur;
2056 while (i-- > 0) {
2057 if (*base >= 'a')
2058 *base = *base - ('a' - 'A');
2059 base++;
2060 }
2061
2062 v->value.hex.str = (xmlChar *) cur;
2063 v->value.hex.total = total;
2064 *val = v;
2065 }
2066 goto return0;
2067 }
2068 case XML_SCHEMAS_BASE64BINARY:{
2069 /* ISSUE:
2070 *
2071 * Ignore all stray characters? (yes, currently)
2072 * Worry about long lines? (no, currently)
2073 *
2074 * rfc2045.txt:
2075 *
2076 * "The encoded output stream must be represented in lines of
2077 * no more than 76 characters each. All line breaks or other
2078 * characters not found in Table 1 must be ignored by decoding
2079 * software. In base64 data, characters other than those in
2080 * Table 1, line breaks, and other white space probably
2081 * indicate a transmission error, about which a warning
2082 * message or even a message rejection might be appropriate
2083 * under some circumstances." */
2084 const xmlChar *cur = value;
2085 xmlChar *base;
2086 int total, i = 0, pad = 0;
2087
2088 if (cur == NULL)
2089 goto return1;
2090
2091 for (; *cur; ++cur) {
2092 int decc;
2093
2094 decc = _xmlSchemaBase64Decode(*cur);
2095 if (decc < 0) ;
2096 else if (decc < 64)
2097 i++;
2098 else
2099 break;
2100 }
2101 for (; *cur; ++cur) {
2102 int decc;
2103
2104 decc = _xmlSchemaBase64Decode(*cur);
2105 if (decc < 0) ;
2106 else if (decc < 64)
2107 goto return1;
2108 if (decc == 64)
2109 pad++;
2110 }
2111
2112 /* rfc2045.txt: "Special processing is performed if fewer than
2113 * 24 bits are available at the end of the data being encoded.
2114 * A full encoding quantum is always completed at the end of a
2115 * body. When fewer than 24 input bits are available in an
2116 * input group, zero bits are added (on the right) to form an
2117 * integral number of 6-bit groups. Padding at the end of the
2118 * data is performed using the "=" character. Since all
2119 * base64 input is an integral number of octets, only the
2120 * following cases can arise: (1) the final quantum of
2121 * encoding input is an integral multiple of 24 bits; here,
2122 * the final unit of encoded output will be an integral
2123 * multiple ofindent: Standard input:701: Warning:old style
2124 * assignment ambiguity in "=*". Assuming "= *" 4 characters
2125 * with no "=" padding, (2) the final
2126 * quantum of encoding input is exactly 8 bits; here, the
2127 * final unit of encoded output will be two characters
2128 * followed by two "=" padding characters, or (3) the final
2129 * quantum of encoding input is exactly 16 bits; here, the
2130 * final unit of encoded output will be three characters
2131 * followed by one "=" padding character." */
2132
2133 total = 3 * (i / 4);
2134 if (pad == 0) {
2135 if (i % 4 != 0)
2136 goto return1;
2137 } else if (pad == 1) {
2138 int decc;
2139
2140 if (i % 4 != 3)
2141 goto return1;
2142 for (decc = _xmlSchemaBase64Decode(*cur);
2143 (decc < 0) || (decc > 63);
2144 decc = _xmlSchemaBase64Decode(*cur))
2145 --cur;
2146 /* 16bits in 24bits means 2 pad bits: nnnnnn nnmmmm mmmm00*/
2147 /* 00111100 -> 0x3c */
2148 if (decc & ~0x3c)
2149 goto return1;
2150 total += 2;
2151 } else if (pad == 2) {
2152 int decc;
2153
2154 if (i % 4 != 2)
2155 goto return1;
2156 for (decc = _xmlSchemaBase64Decode(*cur);
2157 (decc < 0) || (decc > 63);
2158 decc = _xmlSchemaBase64Decode(*cur))
2159 --cur;
2160 /* 8bits in 12bits means 4 pad bits: nnnnnn nn0000 */
2161 /* 00110000 -> 0x30 */
2162 if (decc & ~0x30)
2163 goto return1;
2164 total += 1;
2165 } else
2166 goto return1;
2167
2168 if (val != NULL) {
2169 v = xmlSchemaNewValue(XML_SCHEMAS_BASE64BINARY);
2170 if (v == NULL)
2171 goto error;
2172 base =
2173 (xmlChar *) xmlMallocAtomic((i + pad + 1) *
2174 sizeof(xmlChar));
2175 if (base == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002176 xmlSchemaTypeErrMemory(node, "allocating base64 data");
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002177 xmlFree(v);
2178 goto return1;
2179 }
2180 v->value.base64.str = base;
2181 for (cur = value; *cur; ++cur)
2182 if (_xmlSchemaBase64Decode(*cur) >= 0) {
2183 *base = *cur;
2184 ++base;
2185 }
2186 *base = 0;
2187 v->value.base64.total = total;
2188 *val = v;
2189 }
2190 goto return0;
2191 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002192 case XML_SCHEMAS_INTEGER:
2193 case XML_SCHEMAS_PINTEGER:
2194 case XML_SCHEMAS_NPINTEGER:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002195 case XML_SCHEMAS_NINTEGER:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002196 case XML_SCHEMAS_NNINTEGER:{
2197 const xmlChar *cur = value;
2198 unsigned long lo, mi, hi;
2199 int sign = 0;
2200
2201 if (cur == NULL)
2202 goto return1;
2203 if (*cur == '-') {
2204 sign = 1;
2205 cur++;
2206 } else if (*cur == '+')
2207 cur++;
2208 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2209 if (ret == 0)
2210 goto return1;
2211 if (*cur != 0)
2212 goto return1;
2213 if (type->flags == XML_SCHEMAS_NPINTEGER) {
2214 if ((sign == 0) &&
2215 ((hi != 0) || (mi != 0) || (lo != 0)))
2216 goto return1;
2217 } else if (type->flags == XML_SCHEMAS_PINTEGER) {
2218 if (sign == 1)
2219 goto return1;
2220 if ((hi == 0) && (mi == 0) && (lo == 0))
2221 goto return1;
2222 } else if (type->flags == XML_SCHEMAS_NINTEGER) {
2223 if (sign == 0)
2224 goto return1;
2225 if ((hi == 0) && (mi == 0) && (lo == 0))
2226 goto return1;
2227 } else if (type->flags == XML_SCHEMAS_NNINTEGER) {
2228 if ((sign == 1) &&
2229 ((hi != 0) || (mi != 0) || (lo != 0)))
2230 goto return1;
2231 }
2232 /*
2233 * We can store a value only if no overflow occured
2234 */
2235 if ((ret > 0) && (val != NULL)) {
2236 v = xmlSchemaNewValue(type->flags);
2237 if (v != NULL) {
2238 v->value.decimal.lo = lo;
2239 v->value.decimal.mi = lo;
2240 v->value.decimal.hi = lo;
2241 v->value.decimal.sign = sign;
2242 v->value.decimal.frac = 0;
2243 v->value.decimal.total = cur - value;
2244 *val = v;
2245 }
2246 }
2247 goto return0;
2248 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002249 case XML_SCHEMAS_LONG:
2250 case XML_SCHEMAS_BYTE:
2251 case XML_SCHEMAS_SHORT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002252 case XML_SCHEMAS_INT:{
2253 const xmlChar *cur = value;
2254 unsigned long lo, mi, hi;
2255 int total = 0;
2256 int sign = 0;
2257
2258 if (cur == NULL)
2259 goto return1;
2260 if (*cur == '-') {
2261 sign = 1;
2262 cur++;
2263 } else if (*cur == '+')
2264 cur++;
2265 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2266 if (ret <= 0)
2267 goto return1;
2268 if (*cur != 0)
2269 goto return1;
2270 if (type->flags == XML_SCHEMAS_LONG) {
2271 if (hi >= 922) {
2272 if (hi > 922)
2273 goto return1;
2274 if (mi >= 33720368) {
2275 if (mi > 33720368)
2276 goto return1;
2277 if ((sign == 0) && (lo > 54775807))
2278 goto return1;
2279 if ((sign == 1) && (lo > 54775808))
2280 goto return1;
2281 }
2282 }
2283 } else if (type->flags == XML_SCHEMAS_INT) {
2284 if (hi != 0)
2285 goto return1;
2286 if (mi >= 21) {
2287 if (mi > 21)
2288 goto return1;
2289 if ((sign == 0) && (lo > 47483647))
2290 goto return1;
2291 if ((sign == 1) && (lo > 47483648))
2292 goto return1;
2293 }
2294 } else if (type->flags == XML_SCHEMAS_SHORT) {
2295 if ((mi != 0) || (hi != 0))
2296 goto return1;
2297 if ((sign == 1) && (lo > 32768))
2298 goto return1;
2299 if ((sign == 0) && (lo > 32767))
2300 goto return1;
2301 } else if (type->flags == XML_SCHEMAS_BYTE) {
2302 if ((mi != 0) || (hi != 0))
2303 goto return1;
2304 if ((sign == 1) && (lo > 128))
2305 goto return1;
2306 if ((sign == 0) && (lo > 127))
2307 goto return1;
2308 }
2309 if (val != NULL) {
2310 v = xmlSchemaNewValue(type->flags);
2311 if (v != NULL) {
2312 v->value.decimal.lo = lo;
2313 v->value.decimal.mi = lo;
2314 v->value.decimal.hi = lo;
2315 v->value.decimal.sign = sign;
2316 v->value.decimal.frac = 0;
2317 v->value.decimal.total = total;
2318 *val = v;
2319 }
2320 }
2321 goto return0;
2322 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002323 case XML_SCHEMAS_UINT:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002324 case XML_SCHEMAS_ULONG:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002325 case XML_SCHEMAS_USHORT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002326 case XML_SCHEMAS_UBYTE:{
2327 const xmlChar *cur = value;
2328 unsigned long lo, mi, hi;
2329 int total = 0;
2330
2331 if (cur == NULL)
2332 goto return1;
2333 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2334 if (ret <= 0)
2335 goto return1;
2336 if (*cur != 0)
2337 goto return1;
2338 if (type->flags == XML_SCHEMAS_ULONG) {
2339 if (hi >= 1844) {
2340 if (hi > 1844)
2341 goto return1;
2342 if (mi >= 67440737) {
2343 if (mi > 67440737)
2344 goto return1;
2345 if (lo > 9551615)
2346 goto return1;
2347 }
2348 }
2349 } else if (type->flags == XML_SCHEMAS_UINT) {
2350 if (hi != 0)
2351 goto return1;
2352 if (mi >= 42) {
2353 if (mi > 42)
2354 goto return1;
2355 if (lo > 94967295)
2356 goto return1;
2357 }
2358 } else if (type->flags == XML_SCHEMAS_USHORT) {
2359 if ((mi != 0) || (hi != 0))
2360 goto return1;
2361 if (lo > 65535)
2362 goto return1;
2363 } else if (type->flags == XML_SCHEMAS_UBYTE) {
2364 if ((mi != 0) || (hi != 0))
2365 goto return1;
2366 if (lo > 255)
2367 goto return1;
2368 }
2369 if (val != NULL) {
2370 v = xmlSchemaNewValue(type->flags);
2371 if (v != NULL) {
2372 v->value.decimal.lo = lo;
2373 v->value.decimal.mi = mi;
2374 v->value.decimal.hi = hi;
2375 v->value.decimal.sign = 0;
2376 v->value.decimal.frac = 0;
2377 v->value.decimal.total = total;
2378 *val = v;
2379 }
2380 }
2381 goto return0;
2382 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002383 }
2384
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002385 done:
2386 if (norm != NULL)
2387 xmlFree(norm);
2388 return (ret);
2389 return3:
2390 if (norm != NULL)
2391 xmlFree(norm);
2392 return (3);
2393 return1:
2394 if (norm != NULL)
2395 xmlFree(norm);
2396 return (1);
2397 return0:
2398 if (norm != NULL)
2399 xmlFree(norm);
2400 return (0);
2401 error:
2402 if (norm != NULL)
2403 xmlFree(norm);
2404 return (-1);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002405}
2406
2407/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002408 * xmlSchemaValPredefTypeNode:
Daniel Veillard4255d502002-04-16 15:50:10 +00002409 * @type: the predefined type
2410 * @value: the value to check
2411 * @val: the return computed value
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002412 * @node: the node containing the value
Daniel Veillard4255d502002-04-16 15:50:10 +00002413 *
2414 * Check that a value conforms to the lexical space of the predefined type.
2415 * if true a value is computed and returned in @val.
2416 *
2417 * Returns 0 if this validates, a positive error code number otherwise
2418 * and -1 in case of internal or API error.
2419 */
2420int
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002421xmlSchemaValPredefTypeNode(xmlSchemaTypePtr type, const xmlChar *value,
2422 xmlSchemaValPtr *val, xmlNodePtr node) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002423 return(xmlSchemaValAtomicType(type, value, val, node, 0));
Daniel Veillard4255d502002-04-16 15:50:10 +00002424}
2425
2426/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002427 * xmlSchemaValidatePredefinedType:
2428 * @type: the predefined type
2429 * @value: the value to check
2430 * @val: the return computed value
2431 *
2432 * Check that a value conforms to the lexical space of the predefined type.
2433 * if true a value is computed and returned in @val.
2434 *
2435 * Returns 0 if this validates, a positive error code number otherwise
2436 * and -1 in case of internal or API error.
2437 */
2438int
2439xmlSchemaValidatePredefinedType(xmlSchemaTypePtr type, const xmlChar *value,
2440 xmlSchemaValPtr *val) {
2441 return(xmlSchemaValPredefTypeNode(type, value, val, NULL));
2442}
2443
2444/**
Daniel Veillard4255d502002-04-16 15:50:10 +00002445 * xmlSchemaCompareDecimals:
2446 * @x: a first decimal value
2447 * @y: a second decimal value
2448 *
2449 * Compare 2 decimals
2450 *
2451 * Returns -1 if x < y, 0 if x == y, 1 if x > y and -2 in case of error
2452 */
2453static int
2454xmlSchemaCompareDecimals(xmlSchemaValPtr x, xmlSchemaValPtr y)
2455{
2456 xmlSchemaValPtr swp;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002457 int order = 1, p;
Daniel Veillard4255d502002-04-16 15:50:10 +00002458 unsigned long tmp;
2459
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002460 if ((x->value.decimal.sign) &&
2461 ((x->value.decimal.lo != 0) ||
2462 (x->value.decimal.mi != 0) ||
2463 (x->value.decimal.hi != 0))) {
2464 if ((y->value.decimal.sign) &&
2465 ((y->value.decimal.lo != 0) ||
2466 (y->value.decimal.mi != 0) ||
2467 (y->value.decimal.hi != 0)))
Daniel Veillard80b19092003-03-28 13:29:53 +00002468 order = -1;
2469 else
2470 return (-1);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002471 } else if ((y->value.decimal.sign) &&
2472 ((y->value.decimal.lo != 0) ||
2473 (y->value.decimal.mi != 0) ||
2474 (y->value.decimal.hi != 0))) {
Daniel Veillard4255d502002-04-16 15:50:10 +00002475 return (1);
Daniel Veillard80b19092003-03-28 13:29:53 +00002476 }
Daniel Veillard4255d502002-04-16 15:50:10 +00002477 if (x->value.decimal.frac == y->value.decimal.frac) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002478 if (x->value.decimal.hi < y->value.decimal.hi)
2479 return (-order);
2480 if (x->value.decimal.hi < y->value.decimal.hi)
2481 return (order);
2482 if (x->value.decimal.mi < y->value.decimal.mi)
2483 return (-order);
2484 if (x->value.decimal.mi < y->value.decimal.mi)
2485 return (order);
2486 if (x->value.decimal.lo < y->value.decimal.lo)
Daniel Veillard80b19092003-03-28 13:29:53 +00002487 return (-order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002488 if (x->value.decimal.lo > y->value.decimal.lo)
Daniel Veillard80b19092003-03-28 13:29:53 +00002489 return(order);
2490 return(0);
Daniel Veillard4255d502002-04-16 15:50:10 +00002491 }
2492 if (y->value.decimal.frac > x->value.decimal.frac) {
2493 swp = y;
2494 y = x;
2495 x = swp;
2496 order = -order;
2497 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002498 p = powten[x->value.decimal.frac - y->value.decimal.frac];
2499 tmp = x->value.decimal.lo / p;
2500 if (tmp > y->value.decimal.lo)
Daniel Veillard4255d502002-04-16 15:50:10 +00002501 return (order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002502 if (tmp < y->value.decimal.lo)
Daniel Veillard4255d502002-04-16 15:50:10 +00002503 return (-order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002504 tmp = y->value.decimal.lo * p;
2505 if (x->value.decimal.lo < tmp)
Daniel Veillard4255d502002-04-16 15:50:10 +00002506 return (-order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002507 if (x->value.decimal.lo == tmp)
Daniel Veillard4255d502002-04-16 15:50:10 +00002508 return (0);
2509 return (order);
2510}
2511
2512/**
Daniel Veillard070803b2002-05-03 07:29:38 +00002513 * xmlSchemaCompareDurations:
2514 * @x: a first duration value
2515 * @y: a second duration value
2516 *
2517 * Compare 2 durations
2518 *
2519 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
2520 * case of error
2521 */
2522static int
2523xmlSchemaCompareDurations(xmlSchemaValPtr x, xmlSchemaValPtr y)
2524{
2525 long carry, mon, day;
2526 double sec;
Daniel Veillard80b19092003-03-28 13:29:53 +00002527 int invert = 1;
2528 long xmon, xday, myear, minday, maxday;
Daniel Veillard070803b2002-05-03 07:29:38 +00002529 static const long dayRange [2][12] = {
2530 { 0, 28, 59, 89, 120, 150, 181, 212, 242, 273, 303, 334, },
2531 { 0, 31, 62, 92, 123, 153, 184, 215, 245, 276, 306, 337} };
2532
2533 if ((x == NULL) || (y == NULL))
Daniel Veillard5a872412002-05-22 06:40:27 +00002534 return -2;
Daniel Veillard070803b2002-05-03 07:29:38 +00002535
2536 /* months */
2537 mon = x->value.dur.mon - y->value.dur.mon;
2538
2539 /* seconds */
2540 sec = x->value.dur.sec - y->value.dur.sec;
2541 carry = (long)sec / SECS_PER_DAY;
2542 sec -= (double)(carry * SECS_PER_DAY);
2543
2544 /* days */
2545 day = x->value.dur.day - y->value.dur.day + carry;
2546
2547 /* easy test */
2548 if (mon == 0) {
2549 if (day == 0)
2550 if (sec == 0.0)
2551 return 0;
2552 else if (sec < 0.0)
2553 return -1;
2554 else
2555 return 1;
2556 else if (day < 0)
2557 return -1;
2558 else
2559 return 1;
2560 }
2561
2562 if (mon > 0) {
2563 if ((day >= 0) && (sec >= 0.0))
2564 return 1;
2565 else {
2566 xmon = mon;
2567 xday = -day;
2568 }
2569 } else if ((day <= 0) && (sec <= 0.0)) {
2570 return -1;
2571 } else {
Daniel Veillard80b19092003-03-28 13:29:53 +00002572 invert = -1;
Daniel Veillard070803b2002-05-03 07:29:38 +00002573 xmon = -mon;
2574 xday = day;
2575 }
2576
2577 myear = xmon / 12;
Daniel Veillard80b19092003-03-28 13:29:53 +00002578 if (myear == 0) {
2579 minday = 0;
2580 maxday = 0;
2581 } else {
2582 maxday = 366 * ((myear + 3) / 4) +
2583 365 * ((myear - 1) % 4);
2584 minday = maxday - 1;
2585 }
2586
Daniel Veillard070803b2002-05-03 07:29:38 +00002587 xmon = xmon % 12;
2588 minday += dayRange[0][xmon];
2589 maxday += dayRange[1][xmon];
2590
Daniel Veillard80b19092003-03-28 13:29:53 +00002591 if ((maxday == minday) && (maxday == xday))
2592 return(0); /* can this really happen ? */
Daniel Veillard070803b2002-05-03 07:29:38 +00002593 if (maxday < xday)
Daniel Veillard80b19092003-03-28 13:29:53 +00002594 return(-invert);
2595 if (minday > xday)
2596 return(invert);
Daniel Veillard070803b2002-05-03 07:29:38 +00002597
2598 /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00002599 return 2;
2600}
2601
2602/*
2603 * macros for adding date/times and durations
2604 */
2605#define FQUOTIENT(a,b) (floor(((double)a/(double)b)))
2606#define MODULO(a,b) (a - FQUOTIENT(a,b) * b)
2607#define FQUOTIENT_RANGE(a,low,high) (FQUOTIENT((a-low),(high-low)))
2608#define MODULO_RANGE(a,low,high) ((MODULO((a-low),(high-low)))+low)
2609
2610/**
Daniel Veillard669adfc2004-05-29 20:12:46 +00002611 * xmlSchemaDupVal:
2612 * @v: the #xmlSchemaValPtr value to duplicate
2613 *
2614 * Makes a copy of @v. The calling program is responsible for freeing
2615 * the returned value.
2616 *
2617 * returns a pointer to a duplicated #xmlSchemaValPtr or NULL if error.
2618 */
2619static xmlSchemaValPtr
2620xmlSchemaDupVal (xmlSchemaValPtr v)
2621{
2622 xmlSchemaValPtr ret = xmlSchemaNewValue(v->type);
2623 if (ret == NULL)
2624 return NULL;
2625
2626 memcpy(ret, v, sizeof(xmlSchemaVal));
2627 return ret;
2628}
2629
2630/**
Daniel Veillard5a872412002-05-22 06:40:27 +00002631 * _xmlSchemaDateAdd:
2632 * @dt: an #xmlSchemaValPtr
2633 * @dur: an #xmlSchemaValPtr of type #XS_DURATION
2634 *
2635 * Compute a new date/time from @dt and @dur. This function assumes @dt
2636 * is either #XML_SCHEMAS_DATETIME, #XML_SCHEMAS_DATE, #XML_SCHEMAS_GYEARMONTH,
Daniel Veillard669adfc2004-05-29 20:12:46 +00002637 * or #XML_SCHEMAS_GYEAR. The returned #xmlSchemaVal is the same type as
2638 * @dt. The calling program is responsible for freeing the returned value.
Daniel Veillard5a872412002-05-22 06:40:27 +00002639 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00002640 * Returns a pointer to a new #xmlSchemaVal or NULL if error.
Daniel Veillard5a872412002-05-22 06:40:27 +00002641 */
2642static xmlSchemaValPtr
2643_xmlSchemaDateAdd (xmlSchemaValPtr dt, xmlSchemaValPtr dur)
2644{
Daniel Veillard669adfc2004-05-29 20:12:46 +00002645 xmlSchemaValPtr ret, tmp;
Daniel Veillard5a872412002-05-22 06:40:27 +00002646 long carry, tempdays, temp;
2647 xmlSchemaValDatePtr r, d;
2648 xmlSchemaValDurationPtr u;
2649
2650 if ((dt == NULL) || (dur == NULL))
2651 return NULL;
2652
2653 ret = xmlSchemaNewValue(dt->type);
2654 if (ret == NULL)
2655 return NULL;
2656
Daniel Veillard669adfc2004-05-29 20:12:46 +00002657 /* make a copy so we don't alter the original value */
2658 tmp = xmlSchemaDupVal(dt);
2659 if (tmp == NULL) {
2660 xmlSchemaFreeValue(ret);
2661 return NULL;
2662 }
2663
Daniel Veillard5a872412002-05-22 06:40:27 +00002664 r = &(ret->value.date);
Daniel Veillard669adfc2004-05-29 20:12:46 +00002665 d = &(tmp->value.date);
Daniel Veillard5a872412002-05-22 06:40:27 +00002666 u = &(dur->value.dur);
2667
2668 /* normalization */
2669 if (d->mon == 0)
2670 d->mon = 1;
2671
2672 /* normalize for time zone offset */
2673 u->sec -= (d->tzo * 60);
2674 d->tzo = 0;
2675
2676 /* normalization */
2677 if (d->day == 0)
2678 d->day = 1;
2679
2680 /* month */
2681 carry = d->mon + u->mon;
Daniel Veillardebe25d42004-03-25 09:35:49 +00002682 r->mon = (unsigned int) MODULO_RANGE(carry, 1, 13);
2683 carry = (long) FQUOTIENT_RANGE(carry, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00002684
2685 /* year (may be modified later) */
2686 r->year = d->year + carry;
2687 if (r->year == 0) {
2688 if (d->year > 0)
2689 r->year--;
2690 else
2691 r->year++;
2692 }
2693
2694 /* time zone */
2695 r->tzo = d->tzo;
2696 r->tz_flag = d->tz_flag;
2697
2698 /* seconds */
2699 r->sec = d->sec + u->sec;
Daniel Veillardebe25d42004-03-25 09:35:49 +00002700 carry = (long) FQUOTIENT((long)r->sec, 60);
Daniel Veillard5a872412002-05-22 06:40:27 +00002701 if (r->sec != 0.0) {
2702 r->sec = MODULO(r->sec, 60.0);
2703 }
2704
2705 /* minute */
2706 carry += d->min;
Daniel Veillardebe25d42004-03-25 09:35:49 +00002707 r->min = (unsigned int) MODULO(carry, 60);
2708 carry = (long) FQUOTIENT(carry, 60);
Daniel Veillard5a872412002-05-22 06:40:27 +00002709
2710 /* hours */
2711 carry += d->hour;
Daniel Veillardebe25d42004-03-25 09:35:49 +00002712 r->hour = (unsigned int) MODULO(carry, 24);
2713 carry = (long)FQUOTIENT(carry, 24);
Daniel Veillard5a872412002-05-22 06:40:27 +00002714
2715 /*
2716 * days
2717 * Note we use tempdays because the temporary values may need more
2718 * than 5 bits
2719 */
2720 if ((VALID_YEAR(r->year)) && (VALID_MONTH(r->mon)) &&
2721 (d->day > MAX_DAYINMONTH(r->year, r->mon)))
2722 tempdays = MAX_DAYINMONTH(r->year, r->mon);
2723 else if (d->day < 1)
2724 tempdays = 1;
2725 else
2726 tempdays = d->day;
2727
2728 tempdays += u->day + carry;
2729
2730 while (1) {
2731 if (tempdays < 1) {
Daniel Veillardebe25d42004-03-25 09:35:49 +00002732 long tmon = (long) MODULO_RANGE(r->mon-1, 1, 13);
2733 long tyr = r->year + (long)FQUOTIENT_RANGE(r->mon-1, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00002734 if (tyr == 0)
2735 tyr--;
2736 tempdays += MAX_DAYINMONTH(tyr, tmon);
2737 carry = -1;
Daniel Veillardebe25d42004-03-25 09:35:49 +00002738 } else if (tempdays > (long) MAX_DAYINMONTH(r->year, r->mon)) {
Daniel Veillard5a872412002-05-22 06:40:27 +00002739 tempdays = tempdays - MAX_DAYINMONTH(r->year, r->mon);
2740 carry = 1;
2741 } else
2742 break;
2743
2744 temp = r->mon + carry;
Daniel Veillardebe25d42004-03-25 09:35:49 +00002745 r->mon = (unsigned int) MODULO_RANGE(temp, 1, 13);
2746 r->year = r->year + (unsigned int) FQUOTIENT_RANGE(temp, 1, 13);
Daniel Veillard5a872412002-05-22 06:40:27 +00002747 if (r->year == 0) {
2748 if (temp < 1)
2749 r->year--;
2750 else
2751 r->year++;
2752 }
2753 }
2754
2755 r->day = tempdays;
2756
2757 /*
2758 * adjust the date/time type to the date values
2759 */
2760 if (ret->type != XML_SCHEMAS_DATETIME) {
2761 if ((r->hour) || (r->min) || (r->sec))
2762 ret->type = XML_SCHEMAS_DATETIME;
2763 else if (ret->type != XML_SCHEMAS_DATE) {
2764 if ((r->mon != 1) && (r->day != 1))
2765 ret->type = XML_SCHEMAS_DATE;
2766 else if ((ret->type != XML_SCHEMAS_GYEARMONTH) && (r->mon != 1))
2767 ret->type = XML_SCHEMAS_GYEARMONTH;
2768 }
2769 }
2770
Daniel Veillard669adfc2004-05-29 20:12:46 +00002771 xmlSchemaFreeValue(tmp);
Daniel Veillard5a872412002-05-22 06:40:27 +00002772
Daniel Veillard5a872412002-05-22 06:40:27 +00002773 return ret;
2774}
2775
2776/**
2777 * xmlSchemaDateNormalize:
Daniel Veillard669adfc2004-05-29 20:12:46 +00002778 * @dt: an #xmlSchemaValPtr of a date/time type value.
2779 * @offset: number of seconds to adjust @dt by.
Daniel Veillard5a872412002-05-22 06:40:27 +00002780 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00002781 * Normalize @dt to GMT time. The @offset parameter is subtracted from
2782 * the return value is a time-zone offset is present on @dt.
Daniel Veillard5a872412002-05-22 06:40:27 +00002783 *
Daniel Veillard669adfc2004-05-29 20:12:46 +00002784 * Returns a normalized copy of @dt or NULL if error.
Daniel Veillard5a872412002-05-22 06:40:27 +00002785 */
2786static xmlSchemaValPtr
2787xmlSchemaDateNormalize (xmlSchemaValPtr dt, double offset)
2788{
2789 xmlSchemaValPtr dur, ret;
2790
2791 if (dt == NULL)
2792 return NULL;
2793
2794 if (((dt->type != XML_SCHEMAS_TIME) &&
2795 (dt->type != XML_SCHEMAS_DATETIME)) || (dt->value.date.tzo == 0))
2796 return xmlSchemaDupVal(dt);
2797
2798 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
2799 if (dur == NULL)
2800 return NULL;
2801
2802 dur->value.date.sec -= offset;
2803
2804 ret = _xmlSchemaDateAdd(dt, dur);
2805 if (ret == NULL)
2806 return NULL;
2807
2808 xmlSchemaFreeValue(dur);
2809
2810 /* ret->value.date.tzo = 0; */
2811 return ret;
2812}
2813
2814/**
2815 * _xmlSchemaDateCastYMToDays:
2816 * @dt: an #xmlSchemaValPtr
2817 *
2818 * Convert mon and year of @dt to total number of days. Take the
2819 * number of years since (or before) 1 AD and add the number of leap
2820 * years. This is a function because negative
2821 * years must be handled a little differently and there is no zero year.
2822 *
2823 * Returns number of days.
2824 */
2825static long
2826_xmlSchemaDateCastYMToDays (const xmlSchemaValPtr dt)
2827{
2828 long ret;
2829
2830 if (dt->value.date.year < 0)
2831 ret = (dt->value.date.year * 365) +
2832 (((dt->value.date.year+1)/4)-((dt->value.date.year+1)/100)+
2833 ((dt->value.date.year+1)/400)) +
2834 DAY_IN_YEAR(0, dt->value.date.mon, dt->value.date.year);
2835 else
2836 ret = ((dt->value.date.year-1) * 365) +
2837 (((dt->value.date.year-1)/4)-((dt->value.date.year-1)/100)+
2838 ((dt->value.date.year-1)/400)) +
2839 DAY_IN_YEAR(0, dt->value.date.mon, dt->value.date.year);
2840
2841 return ret;
2842}
2843
2844/**
2845 * TIME_TO_NUMBER:
2846 * @dt: an #xmlSchemaValPtr
2847 *
2848 * Calculates the number of seconds in the time portion of @dt.
2849 *
2850 * Returns seconds.
2851 */
2852#define TIME_TO_NUMBER(dt) \
2853 ((double)((dt->value.date.hour * SECS_PER_HOUR) + \
Daniel Veillardb3721c22003-03-31 11:22:25 +00002854 (dt->value.date.min * SECS_PER_MIN) + \
2855 (dt->value.date.tzo * SECS_PER_MIN)) + \
2856 dt->value.date.sec)
Daniel Veillard5a872412002-05-22 06:40:27 +00002857
2858/**
2859 * xmlSchemaCompareDates:
2860 * @x: a first date/time value
2861 * @y: a second date/time value
2862 *
2863 * Compare 2 date/times
2864 *
2865 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
2866 * case of error
2867 */
2868static int
2869xmlSchemaCompareDates (xmlSchemaValPtr x, xmlSchemaValPtr y)
2870{
2871 unsigned char xmask, ymask, xor_mask, and_mask;
2872 xmlSchemaValPtr p1, p2, q1, q2;
2873 long p1d, p2d, q1d, q2d;
2874
2875 if ((x == NULL) || (y == NULL))
2876 return -2;
2877
2878 if (x->value.date.tz_flag) {
2879
2880 if (!y->value.date.tz_flag) {
2881 p1 = xmlSchemaDateNormalize(x, 0);
2882 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
2883 /* normalize y + 14:00 */
2884 q1 = xmlSchemaDateNormalize(y, (14 * SECS_PER_HOUR));
2885
2886 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002887 if (p1d < q1d) {
2888 xmlSchemaFreeValue(p1);
2889 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002890 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002891 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00002892 double sec;
2893
2894 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00002895 if (sec < 0.0) {
2896 xmlSchemaFreeValue(p1);
2897 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002898 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002899 } else {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00002900 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00002901 /* normalize y - 14:00 */
2902 q2 = xmlSchemaDateNormalize(y, -(14 * SECS_PER_HOUR));
2903 q2d = _xmlSchemaDateCastYMToDays(q2) + q2->value.date.day;
2904 if (p1d > q2d)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00002905 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00002906 else if (p1d == q2d) {
2907 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q2);
2908 if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00002909 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00002910 else
Daniel Veillard4aede2e2003-10-17 12:43:59 +00002911 ret = 2; /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00002912 }
Daniel Veillard4aede2e2003-10-17 12:43:59 +00002913 xmlSchemaFreeValue(p1);
2914 xmlSchemaFreeValue(q1);
2915 xmlSchemaFreeValue(q2);
2916 if (ret != 0)
2917 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00002918 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00002919 } else {
2920 xmlSchemaFreeValue(p1);
2921 xmlSchemaFreeValue(q1);
2922 }
Daniel Veillard5a872412002-05-22 06:40:27 +00002923 }
2924 } else if (y->value.date.tz_flag) {
2925 q1 = xmlSchemaDateNormalize(y, 0);
2926 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
2927
2928 /* normalize x - 14:00 */
2929 p1 = xmlSchemaDateNormalize(x, -(14 * SECS_PER_HOUR));
2930 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
2931
Daniel Veillardfdc91562002-07-01 21:52:03 +00002932 if (p1d < q1d) {
2933 xmlSchemaFreeValue(p1);
2934 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002935 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002936 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00002937 double sec;
2938
2939 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00002940 if (sec < 0.0) {
2941 xmlSchemaFreeValue(p1);
2942 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002943 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002944 } else {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00002945 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00002946 /* normalize x + 14:00 */
2947 p2 = xmlSchemaDateNormalize(x, (14 * SECS_PER_HOUR));
2948 p2d = _xmlSchemaDateCastYMToDays(p2) + p2->value.date.day;
2949
Daniel Veillard6560a422003-03-27 21:25:38 +00002950 if (p2d > q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00002951 ret = 1;
Daniel Veillard6560a422003-03-27 21:25:38 +00002952 } else if (p2d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00002953 sec = TIME_TO_NUMBER(p2) - TIME_TO_NUMBER(q1);
2954 if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00002955 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00002956 else
Daniel Veillard4aede2e2003-10-17 12:43:59 +00002957 ret = 2; /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00002958 }
Daniel Veillard6560a422003-03-27 21:25:38 +00002959 xmlSchemaFreeValue(p1);
2960 xmlSchemaFreeValue(q1);
2961 xmlSchemaFreeValue(p2);
Daniel Veillard4aede2e2003-10-17 12:43:59 +00002962 if (ret != 0)
2963 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00002964 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00002965 } else {
2966 xmlSchemaFreeValue(p1);
2967 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002968 }
2969 }
2970
2971 /*
2972 * if the same type then calculate the difference
2973 */
2974 if (x->type == y->type) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00002975 int ret = 0;
Daniel Veillard5a872412002-05-22 06:40:27 +00002976 q1 = xmlSchemaDateNormalize(y, 0);
2977 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
2978
2979 p1 = xmlSchemaDateNormalize(x, 0);
2980 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
2981
Daniel Veillardfdc91562002-07-01 21:52:03 +00002982 if (p1d < q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00002983 ret = -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002984 } else if (p1d > q1d) {
Daniel Veillard4aede2e2003-10-17 12:43:59 +00002985 ret = 1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002986 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00002987 double sec;
2988
2989 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
2990 if (sec < 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00002991 ret = -1;
Daniel Veillard5a872412002-05-22 06:40:27 +00002992 else if (sec > 0.0)
Daniel Veillard4aede2e2003-10-17 12:43:59 +00002993 ret = 1;
Daniel Veillard5a872412002-05-22 06:40:27 +00002994
2995 }
Daniel Veillard4aede2e2003-10-17 12:43:59 +00002996 xmlSchemaFreeValue(p1);
2997 xmlSchemaFreeValue(q1);
2998 return(ret);
Daniel Veillard5a872412002-05-22 06:40:27 +00002999 }
3000
3001 switch (x->type) {
3002 case XML_SCHEMAS_DATETIME:
3003 xmask = 0xf;
3004 break;
3005 case XML_SCHEMAS_DATE:
3006 xmask = 0x7;
3007 break;
3008 case XML_SCHEMAS_GYEAR:
3009 xmask = 0x1;
3010 break;
3011 case XML_SCHEMAS_GMONTH:
3012 xmask = 0x2;
3013 break;
3014 case XML_SCHEMAS_GDAY:
3015 xmask = 0x3;
3016 break;
3017 case XML_SCHEMAS_GYEARMONTH:
3018 xmask = 0x3;
3019 break;
3020 case XML_SCHEMAS_GMONTHDAY:
3021 xmask = 0x6;
3022 break;
3023 case XML_SCHEMAS_TIME:
3024 xmask = 0x8;
3025 break;
3026 default:
3027 xmask = 0;
3028 break;
3029 }
3030
3031 switch (y->type) {
3032 case XML_SCHEMAS_DATETIME:
3033 ymask = 0xf;
3034 break;
3035 case XML_SCHEMAS_DATE:
3036 ymask = 0x7;
3037 break;
3038 case XML_SCHEMAS_GYEAR:
3039 ymask = 0x1;
3040 break;
3041 case XML_SCHEMAS_GMONTH:
3042 ymask = 0x2;
3043 break;
3044 case XML_SCHEMAS_GDAY:
3045 ymask = 0x3;
3046 break;
3047 case XML_SCHEMAS_GYEARMONTH:
3048 ymask = 0x3;
3049 break;
3050 case XML_SCHEMAS_GMONTHDAY:
3051 ymask = 0x6;
3052 break;
3053 case XML_SCHEMAS_TIME:
3054 ymask = 0x8;
3055 break;
3056 default:
3057 ymask = 0;
3058 break;
3059 }
3060
3061 xor_mask = xmask ^ ymask; /* mark type differences */
3062 and_mask = xmask & ymask; /* mark field specification */
3063
3064 /* year */
3065 if (xor_mask & 1)
3066 return 2; /* indeterminate */
3067 else if (and_mask & 1) {
3068 if (x->value.date.year < y->value.date.year)
3069 return -1;
3070 else if (x->value.date.year > y->value.date.year)
3071 return 1;
3072 }
3073
3074 /* month */
3075 if (xor_mask & 2)
3076 return 2; /* indeterminate */
3077 else if (and_mask & 2) {
3078 if (x->value.date.mon < y->value.date.mon)
3079 return -1;
3080 else if (x->value.date.mon > y->value.date.mon)
3081 return 1;
3082 }
3083
3084 /* day */
3085 if (xor_mask & 4)
3086 return 2; /* indeterminate */
3087 else if (and_mask & 4) {
3088 if (x->value.date.day < y->value.date.day)
3089 return -1;
3090 else if (x->value.date.day > y->value.date.day)
3091 return 1;
3092 }
3093
3094 /* time */
3095 if (xor_mask & 8)
3096 return 2; /* indeterminate */
3097 else if (and_mask & 8) {
3098 if (x->value.date.hour < y->value.date.hour)
3099 return -1;
3100 else if (x->value.date.hour > y->value.date.hour)
3101 return 1;
3102 else if (x->value.date.min < y->value.date.min)
3103 return -1;
3104 else if (x->value.date.min > y->value.date.min)
3105 return 1;
3106 else if (x->value.date.sec < y->value.date.sec)
3107 return -1;
3108 else if (x->value.date.sec > y->value.date.sec)
3109 return 1;
3110 }
3111
Daniel Veillard070803b2002-05-03 07:29:38 +00003112 return 0;
3113}
3114
3115/**
Daniel Veillardc4c21552003-03-29 10:53:38 +00003116 * xmlSchemaCompareNormStrings:
3117 * @x: a first string value
3118 * @y: a second string value
3119 *
3120 * Compare 2 string for their normalized values.
3121 *
3122 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
3123 * case of error
3124 */
3125static int
3126xmlSchemaCompareNormStrings(xmlSchemaValPtr x, xmlSchemaValPtr y) {
3127 const xmlChar *utf1;
3128 const xmlChar *utf2;
3129 int tmp;
3130
3131 if ((x == NULL) || (y == NULL))
3132 return(-2);
3133 utf1 = x->value.str;
3134 utf2 = y->value.str;
3135
William M. Brack76e95df2003-10-18 16:20:14 +00003136 while (IS_BLANK_CH(*utf1)) utf1++;
3137 while (IS_BLANK_CH(*utf2)) utf2++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003138 while ((*utf1 != 0) && (*utf2 != 0)) {
William M. Brack76e95df2003-10-18 16:20:14 +00003139 if (IS_BLANK_CH(*utf1)) {
3140 if (!IS_BLANK_CH(*utf2)) {
Daniel Veillardc4c21552003-03-29 10:53:38 +00003141 tmp = *utf1 - *utf2;
3142 return(tmp);
3143 }
William M. Brack76e95df2003-10-18 16:20:14 +00003144 while (IS_BLANK_CH(*utf1)) utf1++;
3145 while (IS_BLANK_CH(*utf2)) utf2++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003146 } else {
3147 tmp = *utf1++ - *utf2++;
3148 if (tmp < 0)
3149 return(-1);
3150 if (tmp > 0)
3151 return(1);
3152 }
3153 }
3154 if (*utf1 != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00003155 while (IS_BLANK_CH(*utf1)) utf1++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003156 if (*utf1 != 0)
3157 return(1);
3158 }
3159 if (*utf2 != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00003160 while (IS_BLANK_CH(*utf2)) utf2++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003161 if (*utf2 != 0)
3162 return(-1);
3163 }
3164 return(0);
3165}
3166
3167/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003168 * xmlSchemaCompareFloats:
3169 * @x: a first float or double value
3170 * @y: a second float or double value
3171 *
3172 * Compare 2 values
3173 *
3174 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3175 * case of error
3176 */
3177static int
3178xmlSchemaCompareFloats(xmlSchemaValPtr x, xmlSchemaValPtr y) {
3179 double d1, d2;
3180
3181 if ((x == NULL) || (y == NULL))
3182 return(-2);
3183
3184 /*
3185 * Cast everything to doubles.
3186 */
3187 if (x->type == XML_SCHEMAS_DOUBLE)
3188 d1 = x->value.d;
3189 else if (x->type == XML_SCHEMAS_FLOAT)
3190 d1 = x->value.f;
3191 else
3192 return(-2);
3193
3194 if (y->type == XML_SCHEMAS_DOUBLE)
3195 d2 = y->value.d;
3196 else if (y->type == XML_SCHEMAS_FLOAT)
3197 d2 = y->value.f;
3198 else
3199 return(-2);
3200
3201 /*
3202 * Check for special cases.
3203 */
3204 if (xmlXPathIsNaN(d1)) {
3205 if (xmlXPathIsNaN(d2))
3206 return(0);
3207 return(1);
3208 }
3209 if (xmlXPathIsNaN(d2))
3210 return(-1);
3211 if (d1 == xmlXPathPINF) {
3212 if (d2 == xmlXPathPINF)
3213 return(0);
3214 return(1);
3215 }
3216 if (d2 == xmlXPathPINF)
3217 return(-1);
3218 if (d1 == xmlXPathNINF) {
3219 if (d2 == xmlXPathNINF)
3220 return(0);
3221 return(-1);
3222 }
3223 if (d2 == xmlXPathNINF)
3224 return(1);
3225
3226 /*
3227 * basic tests, the last one we should have equality, but
3228 * portability is more important than speed and handling
3229 * NaN or Inf in a portable way is always a challenge, so ...
3230 */
3231 if (d1 < d2)
3232 return(-1);
3233 if (d1 > d2)
3234 return(1);
3235 if (d1 == d2)
3236 return(0);
3237 return(2);
3238}
3239
3240/**
Daniel Veillard4255d502002-04-16 15:50:10 +00003241 * xmlSchemaCompareValues:
3242 * @x: a first value
3243 * @y: a second value
3244 *
3245 * Compare 2 values
3246 *
Daniel Veillard5a872412002-05-22 06:40:27 +00003247 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3248 * case of error
Daniel Veillard4255d502002-04-16 15:50:10 +00003249 */
Daniel Veillard80b19092003-03-28 13:29:53 +00003250int
Daniel Veillard4255d502002-04-16 15:50:10 +00003251xmlSchemaCompareValues(xmlSchemaValPtr x, xmlSchemaValPtr y) {
3252 if ((x == NULL) || (y == NULL))
3253 return(-2);
3254
3255 switch (x->type) {
Daniel Veillard80b19092003-03-28 13:29:53 +00003256 case XML_SCHEMAS_UNKNOWN:
3257 return(-2);
3258 case XML_SCHEMAS_INTEGER:
3259 case XML_SCHEMAS_NPINTEGER:
3260 case XML_SCHEMAS_NINTEGER:
3261 case XML_SCHEMAS_NNINTEGER:
3262 case XML_SCHEMAS_PINTEGER:
3263 case XML_SCHEMAS_INT:
3264 case XML_SCHEMAS_UINT:
3265 case XML_SCHEMAS_LONG:
3266 case XML_SCHEMAS_ULONG:
3267 case XML_SCHEMAS_SHORT:
3268 case XML_SCHEMAS_USHORT:
3269 case XML_SCHEMAS_BYTE:
3270 case XML_SCHEMAS_UBYTE:
Daniel Veillard4255d502002-04-16 15:50:10 +00003271 case XML_SCHEMAS_DECIMAL:
Daniel Veillard80b19092003-03-28 13:29:53 +00003272 if (y->type == x->type)
3273 return(xmlSchemaCompareDecimals(x, y));
3274 if ((y->type == XML_SCHEMAS_DECIMAL) ||
3275 (y->type == XML_SCHEMAS_INTEGER) ||
3276 (y->type == XML_SCHEMAS_NPINTEGER) ||
3277 (y->type == XML_SCHEMAS_NINTEGER) ||
3278 (y->type == XML_SCHEMAS_NNINTEGER) ||
3279 (y->type == XML_SCHEMAS_PINTEGER) ||
3280 (y->type == XML_SCHEMAS_INT) ||
3281 (y->type == XML_SCHEMAS_UINT) ||
3282 (y->type == XML_SCHEMAS_LONG) ||
3283 (y->type == XML_SCHEMAS_ULONG) ||
3284 (y->type == XML_SCHEMAS_SHORT) ||
3285 (y->type == XML_SCHEMAS_USHORT) ||
3286 (y->type == XML_SCHEMAS_BYTE) ||
3287 (y->type == XML_SCHEMAS_UBYTE))
Daniel Veillard4255d502002-04-16 15:50:10 +00003288 return(xmlSchemaCompareDecimals(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00003289 return(-2);
Daniel Veillard070803b2002-05-03 07:29:38 +00003290 case XML_SCHEMAS_DURATION:
3291 if (y->type == XML_SCHEMAS_DURATION)
3292 return(xmlSchemaCompareDurations(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00003293 return(-2);
3294 case XML_SCHEMAS_TIME:
3295 case XML_SCHEMAS_GDAY:
3296 case XML_SCHEMAS_GMONTH:
3297 case XML_SCHEMAS_GMONTHDAY:
3298 case XML_SCHEMAS_GYEAR:
3299 case XML_SCHEMAS_GYEARMONTH:
3300 case XML_SCHEMAS_DATE:
3301 case XML_SCHEMAS_DATETIME:
3302 if ((y->type == XML_SCHEMAS_DATETIME) ||
3303 (y->type == XML_SCHEMAS_TIME) ||
3304 (y->type == XML_SCHEMAS_GDAY) ||
3305 (y->type == XML_SCHEMAS_GMONTH) ||
3306 (y->type == XML_SCHEMAS_GMONTHDAY) ||
3307 (y->type == XML_SCHEMAS_GYEAR) ||
3308 (y->type == XML_SCHEMAS_DATE) ||
3309 (y->type == XML_SCHEMAS_GYEARMONTH))
3310 return (xmlSchemaCompareDates(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00003311 return (-2);
Daniel Veillard80b19092003-03-28 13:29:53 +00003312 case XML_SCHEMAS_NORMSTRING:
Daniel Veillard80b19092003-03-28 13:29:53 +00003313 case XML_SCHEMAS_TOKEN:
3314 case XML_SCHEMAS_LANGUAGE:
3315 case XML_SCHEMAS_NMTOKEN:
Daniel Veillard80b19092003-03-28 13:29:53 +00003316 case XML_SCHEMAS_NAME:
Daniel Veillard80b19092003-03-28 13:29:53 +00003317 case XML_SCHEMAS_NCNAME:
3318 case XML_SCHEMAS_ID:
3319 case XML_SCHEMAS_IDREF:
Daniel Veillard80b19092003-03-28 13:29:53 +00003320 case XML_SCHEMAS_ENTITY:
Daniel Veillard80b19092003-03-28 13:29:53 +00003321 case XML_SCHEMAS_NOTATION:
3322 case XML_SCHEMAS_ANYURI:
Daniel Veillardc4c21552003-03-29 10:53:38 +00003323 if ((y->type == XML_SCHEMAS_NORMSTRING) ||
3324 (y->type == XML_SCHEMAS_TOKEN) ||
3325 (y->type == XML_SCHEMAS_LANGUAGE) ||
3326 (y->type == XML_SCHEMAS_NMTOKEN) ||
3327 (y->type == XML_SCHEMAS_NAME) ||
3328 (y->type == XML_SCHEMAS_QNAME) ||
3329 (y->type == XML_SCHEMAS_NCNAME) ||
3330 (y->type == XML_SCHEMAS_ID) ||
3331 (y->type == XML_SCHEMAS_IDREF) ||
3332 (y->type == XML_SCHEMAS_ENTITY) ||
3333 (y->type == XML_SCHEMAS_NOTATION) ||
3334 (y->type == XML_SCHEMAS_ANYURI))
3335 return (xmlSchemaCompareNormStrings(x, y));
3336 return (-2);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003337 case XML_SCHEMAS_QNAME:
3338 if (y->type == XML_SCHEMAS_QNAME) {
3339 if ((xmlStrEqual(x->value.qname.name, y->value.qname.name)) &&
3340 (xmlStrEqual(x->value.qname.uri, y->value.qname.uri)))
3341 return(0);
3342 return(2);
3343 }
3344 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00003345 case XML_SCHEMAS_FLOAT:
3346 case XML_SCHEMAS_DOUBLE:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003347 if ((y->type == XML_SCHEMAS_FLOAT) ||
3348 (y->type == XML_SCHEMAS_DOUBLE))
3349 return (xmlSchemaCompareFloats(x, y));
3350 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00003351 case XML_SCHEMAS_BOOLEAN:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003352 if (y->type == XML_SCHEMAS_BOOLEAN) {
3353 if (x->value.b == y->value.b)
3354 return(0);
3355 if (x->value.b == 0)
3356 return(-1);
3357 return(1);
3358 }
3359 return (-2);
Daniel Veillard560c2a42003-07-06 21:13:49 +00003360 case XML_SCHEMAS_HEXBINARY:
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00003361 if (y->type == XML_SCHEMAS_HEXBINARY) {
3362 if (x->value.hex.total == y->value.hex.total) {
3363 int ret = xmlStrcmp(x->value.hex.str, y->value.hex.str);
3364 if (ret > 0)
3365 return(1);
3366 else if (ret == 0)
3367 return(0);
3368 }
3369 else if (x->value.hex.total > y->value.hex.total)
3370 return(1);
3371
3372 return(-1);
3373 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00003374 return (-2);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003375 case XML_SCHEMAS_BASE64BINARY:
3376 if (y->type == XML_SCHEMAS_BASE64BINARY) {
3377 if (x->value.base64.total == y->value.base64.total) {
3378 int ret = xmlStrcmp(x->value.base64.str,
3379 y->value.base64.str);
3380 if (ret > 0)
3381 return(1);
3382 else if (ret == 0)
3383 return(0);
3384 }
3385 else if (x->value.base64.total > y->value.base64.total)
3386 return(1);
3387 else
3388 return(-1);
3389 }
3390 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00003391 case XML_SCHEMAS_STRING:
3392 case XML_SCHEMAS_IDREFS:
3393 case XML_SCHEMAS_ENTITIES:
3394 case XML_SCHEMAS_NMTOKENS:
3395 TODO
3396 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00003397 }
Daniel Veillard5a872412002-05-22 06:40:27 +00003398 return -2;
Daniel Veillard4255d502002-04-16 15:50:10 +00003399}
3400
3401/**
Daniel Veillardc4c21552003-03-29 10:53:38 +00003402 * xmlSchemaNormLen:
3403 * @value: a string
3404 *
3405 * Computes the UTF8 length of the normalized value of the string
3406 *
3407 * Returns the length or -1 in case of error.
3408 */
3409static int
3410xmlSchemaNormLen(const xmlChar *value) {
3411 const xmlChar *utf;
3412 int ret = 0;
3413
3414 if (value == NULL)
3415 return(-1);
3416 utf = value;
William M. Brack76e95df2003-10-18 16:20:14 +00003417 while (IS_BLANK_CH(*utf)) utf++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003418 while (*utf != 0) {
3419 if (utf[0] & 0x80) {
3420 if ((utf[1] & 0xc0) != 0x80)
3421 return(-1);
3422 if ((utf[0] & 0xe0) == 0xe0) {
3423 if ((utf[2] & 0xc0) != 0x80)
3424 return(-1);
3425 if ((utf[0] & 0xf0) == 0xf0) {
3426 if ((utf[0] & 0xf8) != 0xf0 || (utf[3] & 0xc0) != 0x80)
3427 return(-1);
3428 utf += 4;
3429 } else {
3430 utf += 3;
3431 }
3432 } else {
3433 utf += 2;
3434 }
William M. Brack76e95df2003-10-18 16:20:14 +00003435 } else if (IS_BLANK_CH(*utf)) {
3436 while (IS_BLANK_CH(*utf)) utf++;
Daniel Veillardc4c21552003-03-29 10:53:38 +00003437 if (*utf == 0)
3438 break;
3439 } else {
3440 utf++;
3441 }
3442 ret++;
3443 }
3444 return(ret);
3445}
3446
3447/**
Daniel Veillard4255d502002-04-16 15:50:10 +00003448 * xmlSchemaValidateFacet:
Daniel Veillard01c13b52002-12-10 15:19:08 +00003449 * @base: the base type
Daniel Veillard4255d502002-04-16 15:50:10 +00003450 * @facet: the facet to check
3451 * @value: the lexical repr of the value to validate
3452 * @val: the precomputed value
3453 *
3454 * Check a value against a facet condition
3455 *
3456 * Returns 0 if the element is schemas valid, a positive error code
3457 * number otherwise and -1 in case of internal or API error.
3458 */
3459int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00003460xmlSchemaValidateFacet(xmlSchemaTypePtr base ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +00003461 xmlSchemaFacetPtr facet,
Daniel Veillard4255d502002-04-16 15:50:10 +00003462 const xmlChar *value, xmlSchemaValPtr val)
3463{
3464 int ret;
3465
3466 switch (facet->type) {
3467 case XML_SCHEMA_FACET_PATTERN:
3468 ret = xmlRegexpExec(facet->regexp, value);
3469 if (ret == 1)
3470 return(0);
3471 if (ret == 0) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003472 /* TODO error code */
Daniel Veillard4255d502002-04-16 15:50:10 +00003473 return(1);
3474 }
3475 return(ret);
3476 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
3477 ret = xmlSchemaCompareValues(val, facet->val);
3478 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003479 /* TODO error code */
Daniel Veillard4255d502002-04-16 15:50:10 +00003480 return(-1);
3481 }
3482 if (ret == -1)
3483 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00003484 /* error code */
Daniel Veillard4255d502002-04-16 15:50:10 +00003485 return(1);
Daniel Veillard070803b2002-05-03 07:29:38 +00003486 case XML_SCHEMA_FACET_MAXINCLUSIVE:
3487 ret = xmlSchemaCompareValues(val, facet->val);
3488 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003489 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00003490 return(-1);
3491 }
3492 if ((ret == -1) || (ret == 0))
3493 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00003494 /* error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00003495 return(1);
3496 case XML_SCHEMA_FACET_MINEXCLUSIVE:
3497 ret = xmlSchemaCompareValues(val, facet->val);
3498 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003499 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00003500 return(-1);
3501 }
3502 if (ret == 1)
3503 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00003504 /* error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00003505 return(1);
3506 case XML_SCHEMA_FACET_MININCLUSIVE:
3507 ret = xmlSchemaCompareValues(val, facet->val);
3508 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003509 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00003510 return(-1);
3511 }
3512 if ((ret == 1) || (ret == 0))
3513 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00003514 /* error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00003515 return(1);
Daniel Veillard8651f532002-04-17 09:06:27 +00003516 case XML_SCHEMA_FACET_WHITESPACE:
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003517 /* TODO whitespaces */
Daniel Veillard8651f532002-04-17 09:06:27 +00003518 return(0);
Daniel Veillard88c58912002-04-23 07:12:20 +00003519 case XML_SCHEMA_FACET_ENUMERATION:
3520 if ((facet->value != NULL) &&
3521 (xmlStrEqual(facet->value, value)))
3522 return(0);
3523 return(1);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003524 case XML_SCHEMA_FACET_LENGTH:
3525 case XML_SCHEMA_FACET_MAXLENGTH:
3526 case XML_SCHEMA_FACET_MINLENGTH: {
3527 unsigned int len = 0;
3528
3529 if ((facet->val == NULL) ||
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003530 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
3531 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003532 (facet->val->value.decimal.frac != 0)) {
3533 return(-1);
3534 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00003535 if ((val != NULL) && (val->type == XML_SCHEMAS_HEXBINARY))
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00003536 len = val->value.hex.total;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003537 else if ((val != NULL) && (val->type == XML_SCHEMAS_BASE64BINARY))
3538 len = val->value.base64.total;
3539 else {
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00003540 switch (base->flags) {
Daniel Veillard560c2a42003-07-06 21:13:49 +00003541 case XML_SCHEMAS_IDREF:
3542 case XML_SCHEMAS_NORMSTRING:
3543 case XML_SCHEMAS_TOKEN:
3544 case XML_SCHEMAS_LANGUAGE:
3545 case XML_SCHEMAS_NMTOKEN:
3546 case XML_SCHEMAS_NAME:
3547 case XML_SCHEMAS_NCNAME:
3548 case XML_SCHEMAS_ID:
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00003549 len = xmlSchemaNormLen(value);
3550 break;
Daniel Veillard560c2a42003-07-06 21:13:49 +00003551 case XML_SCHEMAS_STRING:
William M. Brackfbf2c5e2004-02-03 17:55:56 +00003552 if (value != NULL)
3553 len = xmlUTF8Strlen(value);
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00003554 break;
Daniel Veillard560c2a42003-07-06 21:13:49 +00003555 default:
3556 TODO
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00003557 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003558 }
3559 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003560 if (len != facet->val->value.decimal.lo)
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003561 return(1);
3562 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003563 if (len < facet->val->value.decimal.lo)
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003564 return(1);
3565 } else {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003566 if (len > facet->val->value.decimal.lo)
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003567 return(1);
3568 }
3569 break;
3570 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00003571 case XML_SCHEMA_FACET_TOTALDIGITS:
3572 case XML_SCHEMA_FACET_FRACTIONDIGITS:
3573
3574 if ((facet->val == NULL) ||
3575 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
3576 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
3577 (facet->val->value.decimal.frac != 0)) {
3578 return(-1);
3579 }
3580 if ((val == NULL) ||
3581 ((val->type != XML_SCHEMAS_DECIMAL) &&
3582 (val->type != XML_SCHEMAS_INTEGER) &&
3583 (val->type != XML_SCHEMAS_NPINTEGER) &&
3584 (val->type != XML_SCHEMAS_NINTEGER) &&
3585 (val->type != XML_SCHEMAS_NNINTEGER) &&
3586 (val->type != XML_SCHEMAS_PINTEGER) &&
3587 (val->type != XML_SCHEMAS_INT) &&
3588 (val->type != XML_SCHEMAS_UINT) &&
3589 (val->type != XML_SCHEMAS_LONG) &&
3590 (val->type != XML_SCHEMAS_ULONG) &&
3591 (val->type != XML_SCHEMAS_SHORT) &&
3592 (val->type != XML_SCHEMAS_USHORT) &&
3593 (val->type != XML_SCHEMAS_BYTE) &&
3594 (val->type != XML_SCHEMAS_UBYTE))) {
3595 return(-1);
3596 }
3597 if (facet->type == XML_SCHEMA_FACET_TOTALDIGITS) {
3598 if (val->value.decimal.total > facet->val->value.decimal.lo)
3599 return(1);
3600
3601 } else if (facet->type == XML_SCHEMA_FACET_FRACTIONDIGITS) {
3602 if (val->value.decimal.frac > facet->val->value.decimal.lo)
3603 return(1);
3604 }
3605 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00003606 default:
3607 TODO
3608 }
3609 return(0);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003610
Daniel Veillard4255d502002-04-16 15:50:10 +00003611}
3612
3613#endif /* LIBXML_SCHEMAS_ENABLED */