blob: 53c6e156125af01426dd144f18102ea3b459b7fe [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,
86 XML_SCHEMAS_HEXBINARY
Daniel Veillard4255d502002-04-16 15:50:10 +000087} xmlSchemaValType;
88
Daniel Veillard5f704af2003-03-05 10:01:43 +000089static unsigned long powten[10] = {
Daniel Veillard4255d502002-04-16 15:50:10 +000090 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000L,
91 100000000L, 1000000000L
92};
93
Daniel Veillard070803b2002-05-03 07:29:38 +000094/* Date value */
95typedef struct _xmlSchemaValDate xmlSchemaValDate;
96typedef xmlSchemaValDate *xmlSchemaValDatePtr;
97struct _xmlSchemaValDate {
98 long year;
99 unsigned int mon :4; /* 1 <= mon <= 12 */
100 unsigned int day :5; /* 1 <= day <= 31 */
101 unsigned int hour :5; /* 0 <= hour <= 23 */
102 unsigned int min :6; /* 0 <= min <= 59 */
103 double sec;
Daniel Veillarda77cf712003-05-09 23:09:55 +0000104 unsigned int tz_flag :1; /* is tzo explicitely set? */
Daniel Veillard070803b2002-05-03 07:29:38 +0000105 int tzo :11; /* -1440 <= tzo <= 1440 */
106};
107
108/* Duration value */
109typedef struct _xmlSchemaValDuration xmlSchemaValDuration;
110typedef xmlSchemaValDuration *xmlSchemaValDurationPtr;
111struct _xmlSchemaValDuration {
112 long mon; /* mon stores years also */
113 long day;
114 double sec; /* sec stores min and hour also */
115};
116
Daniel Veillard4255d502002-04-16 15:50:10 +0000117typedef struct _xmlSchemaValDecimal xmlSchemaValDecimal;
118typedef xmlSchemaValDecimal *xmlSchemaValDecimalPtr;
119struct _xmlSchemaValDecimal {
120 /* would use long long but not portable */
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000121 unsigned long lo;
122 unsigned long mi;
123 unsigned long hi;
Daniel Veillard4255d502002-04-16 15:50:10 +0000124 unsigned int extra;
Daniel Veillard5a872412002-05-22 06:40:27 +0000125 unsigned int sign:1;
William M. Brackc1939562003-08-05 15:52:22 +0000126 unsigned int frac:7;
127 unsigned int total:8;
Daniel Veillard4255d502002-04-16 15:50:10 +0000128};
129
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000130typedef struct _xmlSchemaValQName xmlSchemaValQName;
131typedef xmlSchemaValQName *xmlSchemaValQNamePtr;
132struct _xmlSchemaValQName {
133 xmlChar *name;
134 xmlChar *uri;
135};
136
Daniel Veillard70bcb0e2003-08-08 14:00:28 +0000137typedef struct _xmlSchemaValHex xmlSchemaValHex;
138typedef xmlSchemaValHex *xmlSchemaValHexPtr;
139struct _xmlSchemaValHex {
140 xmlChar *str;
141 unsigned int total;
142};
143
Daniel Veillard4255d502002-04-16 15:50:10 +0000144struct _xmlSchemaVal {
145 xmlSchemaValType type;
146 union {
Daniel Veillard5a872412002-05-22 06:40:27 +0000147 xmlSchemaValDecimal decimal;
Daniel Veillard070803b2002-05-03 07:29:38 +0000148 xmlSchemaValDate date;
149 xmlSchemaValDuration dur;
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000150 xmlSchemaValQName qname;
Daniel Veillard70bcb0e2003-08-08 14:00:28 +0000151 xmlSchemaValHex hex;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000152 float f;
153 double d;
Daniel Veillardc5a70f22003-02-06 23:41:59 +0000154 int b;
Daniel Veillardc4c21552003-03-29 10:53:38 +0000155 xmlChar *str;
Daniel Veillard4255d502002-04-16 15:50:10 +0000156 } value;
157};
158
159static int xmlSchemaTypesInitialized = 0;
160static xmlHashTablePtr xmlSchemaTypesBank = NULL;
161
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000162/*
163 * Basic types
164 */
Daniel Veillard4255d502002-04-16 15:50:10 +0000165static xmlSchemaTypePtr xmlSchemaTypeStringDef = NULL;
166static xmlSchemaTypePtr xmlSchemaTypeAnyTypeDef = NULL;
167static xmlSchemaTypePtr xmlSchemaTypeAnySimpleTypeDef = NULL;
168static xmlSchemaTypePtr xmlSchemaTypeDecimalDef = NULL;
Daniel Veillard070803b2002-05-03 07:29:38 +0000169static xmlSchemaTypePtr xmlSchemaTypeDatetimeDef = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +0000170static xmlSchemaTypePtr xmlSchemaTypeDateDef = NULL;
Daniel Veillard070803b2002-05-03 07:29:38 +0000171static xmlSchemaTypePtr xmlSchemaTypeTimeDef = NULL;
172static xmlSchemaTypePtr xmlSchemaTypeGYearDef = NULL;
173static xmlSchemaTypePtr xmlSchemaTypeGYearMonthDef = NULL;
174static xmlSchemaTypePtr xmlSchemaTypeGDayDef = NULL;
175static xmlSchemaTypePtr xmlSchemaTypeGMonthDayDef = NULL;
176static xmlSchemaTypePtr xmlSchemaTypeGMonthDef = NULL;
177static xmlSchemaTypePtr xmlSchemaTypeDurationDef = NULL;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000178static xmlSchemaTypePtr xmlSchemaTypeFloatDef = NULL;
Daniel Veillardc5a70f22003-02-06 23:41:59 +0000179static xmlSchemaTypePtr xmlSchemaTypeBooleanDef = NULL;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000180static xmlSchemaTypePtr xmlSchemaTypeDoubleDef = NULL;
Daniel Veillard560c2a42003-07-06 21:13:49 +0000181static xmlSchemaTypePtr xmlSchemaTypeHexBinaryDef = NULL;
Daniel Veillarde5b110b2003-02-04 14:43:39 +0000182static xmlSchemaTypePtr xmlSchemaTypeAnyURIDef = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +0000183
184/*
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000185 * Derived types
186 */
187static xmlSchemaTypePtr xmlSchemaTypePositiveIntegerDef = NULL;
188static xmlSchemaTypePtr xmlSchemaTypeNonPositiveIntegerDef = NULL;
189static xmlSchemaTypePtr xmlSchemaTypeNegativeIntegerDef = NULL;
190static xmlSchemaTypePtr xmlSchemaTypeNonNegativeIntegerDef = NULL;
191static xmlSchemaTypePtr xmlSchemaTypeIntegerDef = NULL;
192static xmlSchemaTypePtr xmlSchemaTypeLongDef = NULL;
193static xmlSchemaTypePtr xmlSchemaTypeIntDef = NULL;
194static xmlSchemaTypePtr xmlSchemaTypeShortDef = NULL;
195static xmlSchemaTypePtr xmlSchemaTypeByteDef = NULL;
196static xmlSchemaTypePtr xmlSchemaTypeUnsignedLongDef = NULL;
197static xmlSchemaTypePtr xmlSchemaTypeUnsignedIntDef = NULL;
198static xmlSchemaTypePtr xmlSchemaTypeUnsignedShortDef = NULL;
199static xmlSchemaTypePtr xmlSchemaTypeUnsignedByteDef = NULL;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000200static xmlSchemaTypePtr xmlSchemaTypeNormStringDef = NULL;
201static xmlSchemaTypePtr xmlSchemaTypeTokenDef = NULL;
202static xmlSchemaTypePtr xmlSchemaTypeLanguageDef = NULL;
203static xmlSchemaTypePtr xmlSchemaTypeNameDef = NULL;
204static xmlSchemaTypePtr xmlSchemaTypeQNameDef = NULL;
Daniel Veillarde5b110b2003-02-04 14:43:39 +0000205static xmlSchemaTypePtr xmlSchemaTypeNCNameDef = NULL;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000206static xmlSchemaTypePtr xmlSchemaTypeIdDef = NULL;
207static xmlSchemaTypePtr xmlSchemaTypeIdrefDef = NULL;
208static xmlSchemaTypePtr xmlSchemaTypeIdrefsDef = NULL;
Daniel Veillarda1a9d042003-03-18 16:53:17 +0000209static xmlSchemaTypePtr xmlSchemaTypeEntityDef = NULL;
210static xmlSchemaTypePtr xmlSchemaTypeEntitiesDef = NULL;
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000211static xmlSchemaTypePtr xmlSchemaTypeNotationDef = NULL;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000212static xmlSchemaTypePtr xmlSchemaTypeNmtokenDef = NULL;
213static xmlSchemaTypePtr xmlSchemaTypeNmtokensDef = NULL;
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000214
215/*
Daniel Veillard4255d502002-04-16 15:50:10 +0000216 * xmlSchemaInitBasicType:
217 * @name: the type name
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000218 * @type: the value type associated
Daniel Veillard4255d502002-04-16 15:50:10 +0000219 *
220 * Initialize one default type
221 */
222static xmlSchemaTypePtr
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000223xmlSchemaInitBasicType(const char *name, xmlSchemaValType type) {
Daniel Veillard4255d502002-04-16 15:50:10 +0000224 xmlSchemaTypePtr ret;
225
226 ret = (xmlSchemaTypePtr) xmlMalloc(sizeof(xmlSchemaType));
227 if (ret == NULL) {
228 xmlGenericError(xmlGenericErrorContext,
229 "Could not initilize type %s: out of memory\n", name);
230 return(NULL);
231 }
232 memset(ret, 0, sizeof(xmlSchemaType));
233 ret->name = xmlStrdup((const xmlChar *)name);
234 ret->type = XML_SCHEMA_TYPE_BASIC;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000235 ret->flags = type;
Daniel Veillard4255d502002-04-16 15:50:10 +0000236 ret->contentType = XML_SCHEMA_CONTENT_BASIC;
237 xmlHashAddEntry2(xmlSchemaTypesBank, ret->name,
238 XML_SCHEMAS_NAMESPACE_NAME, ret);
239 return(ret);
240}
241
242/*
243 * xmlSchemaInitTypes:
244 *
245 * Initialize the default XML Schemas type library
246 */
247void
Daniel Veillard6560a422003-03-27 21:25:38 +0000248xmlSchemaInitTypes(void)
249{
Daniel Veillard4255d502002-04-16 15:50:10 +0000250 if (xmlSchemaTypesInitialized != 0)
Daniel Veillard6560a422003-03-27 21:25:38 +0000251 return;
Daniel Veillard4255d502002-04-16 15:50:10 +0000252 xmlSchemaTypesBank = xmlHashCreate(40);
Daniel Veillard6560a422003-03-27 21:25:38 +0000253
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000254 /*
255 * primitive datatypes
256 */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000257 xmlSchemaTypeStringDef = xmlSchemaInitBasicType("string",
Daniel Veillard6560a422003-03-27 21:25:38 +0000258 XML_SCHEMAS_STRING);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000259 xmlSchemaTypeAnyTypeDef = xmlSchemaInitBasicType("anyType",
Daniel Veillard6560a422003-03-27 21:25:38 +0000260 XML_SCHEMAS_UNKNOWN);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000261 xmlSchemaTypeAnySimpleTypeDef = xmlSchemaInitBasicType("anySimpleType",
Daniel Veillard6560a422003-03-27 21:25:38 +0000262 XML_SCHEMAS_UNKNOWN);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000263 xmlSchemaTypeDecimalDef = xmlSchemaInitBasicType("decimal",
Daniel Veillard6560a422003-03-27 21:25:38 +0000264 XML_SCHEMAS_DECIMAL);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000265 xmlSchemaTypeDateDef = xmlSchemaInitBasicType("date",
Daniel Veillard6560a422003-03-27 21:25:38 +0000266 XML_SCHEMAS_DATE);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000267 xmlSchemaTypeDatetimeDef = xmlSchemaInitBasicType("dateTime",
Daniel Veillard6560a422003-03-27 21:25:38 +0000268 XML_SCHEMAS_DATETIME);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000269 xmlSchemaTypeTimeDef = xmlSchemaInitBasicType("time",
Daniel Veillard6560a422003-03-27 21:25:38 +0000270 XML_SCHEMAS_TIME);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000271 xmlSchemaTypeGYearDef = xmlSchemaInitBasicType("gYear",
Daniel Veillard6560a422003-03-27 21:25:38 +0000272 XML_SCHEMAS_GYEAR);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000273 xmlSchemaTypeGYearMonthDef = xmlSchemaInitBasicType("gYearMonth",
Daniel Veillard6560a422003-03-27 21:25:38 +0000274 XML_SCHEMAS_GYEARMONTH);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000275 xmlSchemaTypeGMonthDef = xmlSchemaInitBasicType("gMonth",
Daniel Veillard6560a422003-03-27 21:25:38 +0000276 XML_SCHEMAS_GMONTH);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000277 xmlSchemaTypeGMonthDayDef = xmlSchemaInitBasicType("gMonthDay",
Daniel Veillard6560a422003-03-27 21:25:38 +0000278 XML_SCHEMAS_GMONTHDAY);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000279 xmlSchemaTypeGDayDef = xmlSchemaInitBasicType("gDay",
Daniel Veillard6560a422003-03-27 21:25:38 +0000280 XML_SCHEMAS_GDAY);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000281 xmlSchemaTypeDurationDef = xmlSchemaInitBasicType("duration",
Daniel Veillard6560a422003-03-27 21:25:38 +0000282 XML_SCHEMAS_DURATION);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000283 xmlSchemaTypeFloatDef = xmlSchemaInitBasicType("float",
Daniel Veillard6560a422003-03-27 21:25:38 +0000284 XML_SCHEMAS_FLOAT);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000285 xmlSchemaTypeDoubleDef = xmlSchemaInitBasicType("double",
Daniel Veillard6560a422003-03-27 21:25:38 +0000286 XML_SCHEMAS_DOUBLE);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000287 xmlSchemaTypeBooleanDef = xmlSchemaInitBasicType("boolean",
Daniel Veillard6560a422003-03-27 21:25:38 +0000288 XML_SCHEMAS_BOOLEAN);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000289 xmlSchemaTypeAnyURIDef = xmlSchemaInitBasicType("anyURI",
Daniel Veillard6560a422003-03-27 21:25:38 +0000290 XML_SCHEMAS_ANYURI);
Daniel Veillard560c2a42003-07-06 21:13:49 +0000291 xmlSchemaTypeHexBinaryDef = xmlSchemaInitBasicType("hexBinary",
292 XML_SCHEMAS_HEXBINARY);
Daniel Veillard4255d502002-04-16 15:50:10 +0000293
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000294 /*
295 * derived datatypes
296 */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000297 xmlSchemaTypeIntegerDef = xmlSchemaInitBasicType("integer",
Daniel Veillard6560a422003-03-27 21:25:38 +0000298 XML_SCHEMAS_INTEGER);;
299 xmlSchemaTypeNonPositiveIntegerDef =
300 xmlSchemaInitBasicType("nonPositiveInteger",
301 XML_SCHEMAS_NPINTEGER);;
302 xmlSchemaTypeNegativeIntegerDef =
303 xmlSchemaInitBasicType("negativeInteger", XML_SCHEMAS_NINTEGER);;
304 xmlSchemaTypeLongDef =
305 xmlSchemaInitBasicType("long", XML_SCHEMAS_LONG);;
306 xmlSchemaTypeIntDef = xmlSchemaInitBasicType("int", XML_SCHEMAS_INT);;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000307 xmlSchemaTypeShortDef = xmlSchemaInitBasicType("short",
Daniel Veillard6560a422003-03-27 21:25:38 +0000308 XML_SCHEMAS_SHORT);;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000309 xmlSchemaTypeByteDef = xmlSchemaInitBasicType("byte",
Daniel Veillard6560a422003-03-27 21:25:38 +0000310 XML_SCHEMAS_BYTE);;
311 xmlSchemaTypeNonNegativeIntegerDef =
312 xmlSchemaInitBasicType("nonNegativeInteger",
313 XML_SCHEMAS_NNINTEGER);
314 xmlSchemaTypeUnsignedLongDef =
315 xmlSchemaInitBasicType("unsignedLong", XML_SCHEMAS_ULONG);;
316 xmlSchemaTypeUnsignedIntDef =
317 xmlSchemaInitBasicType("unsignedInt", XML_SCHEMAS_UINT);;
318 xmlSchemaTypeUnsignedShortDef =
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000319 xmlSchemaInitBasicType("unsignedShort", XML_SCHEMAS_USHORT);;
Daniel Veillard6560a422003-03-27 21:25:38 +0000320 xmlSchemaTypeUnsignedByteDef =
321 xmlSchemaInitBasicType("unsignedByte", XML_SCHEMAS_UBYTE);;
322 xmlSchemaTypePositiveIntegerDef =
323 xmlSchemaInitBasicType("positiveInteger", XML_SCHEMAS_PINTEGER);
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000324
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000325 xmlSchemaTypeNormStringDef = xmlSchemaInitBasicType("normalizedString",
Daniel Veillard6560a422003-03-27 21:25:38 +0000326 XML_SCHEMAS_NORMSTRING);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000327 xmlSchemaTypeTokenDef = xmlSchemaInitBasicType("token",
Daniel Veillard6560a422003-03-27 21:25:38 +0000328 XML_SCHEMAS_TOKEN);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000329 xmlSchemaTypeLanguageDef = xmlSchemaInitBasicType("language",
Daniel Veillard6560a422003-03-27 21:25:38 +0000330 XML_SCHEMAS_LANGUAGE);
331 xmlSchemaTypeIdDef = xmlSchemaInitBasicType("ID", XML_SCHEMAS_ID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000332 xmlSchemaTypeIdrefDef = xmlSchemaInitBasicType("IDREF",
Daniel Veillard6560a422003-03-27 21:25:38 +0000333 XML_SCHEMAS_IDREF);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000334 xmlSchemaTypeIdrefsDef = xmlSchemaInitBasicType("IDREFS",
Daniel Veillard6560a422003-03-27 21:25:38 +0000335 XML_SCHEMAS_IDREFS);
Daniel Veillarda1a9d042003-03-18 16:53:17 +0000336 xmlSchemaTypeEntityDef = xmlSchemaInitBasicType("ENTITY",
Daniel Veillard6560a422003-03-27 21:25:38 +0000337 XML_SCHEMAS_ENTITY);
Daniel Veillarda1a9d042003-03-18 16:53:17 +0000338 xmlSchemaTypeEntitiesDef = xmlSchemaInitBasicType("ENTITIES",
Daniel Veillard6560a422003-03-27 21:25:38 +0000339 XML_SCHEMAS_ENTITIES);
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000340 xmlSchemaTypeNotationDef = xmlSchemaInitBasicType("NOTATION",
341 XML_SCHEMAS_NOTATION);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000342 xmlSchemaTypeNameDef = xmlSchemaInitBasicType("Name",
Daniel Veillard6560a422003-03-27 21:25:38 +0000343 XML_SCHEMAS_NAME);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000344 xmlSchemaTypeQNameDef = xmlSchemaInitBasicType("QName",
Daniel Veillard6560a422003-03-27 21:25:38 +0000345 XML_SCHEMAS_QNAME);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000346 xmlSchemaTypeNCNameDef = xmlSchemaInitBasicType("NCName",
Daniel Veillard6560a422003-03-27 21:25:38 +0000347 XML_SCHEMAS_NCNAME);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000348 xmlSchemaTypeNmtokenDef = xmlSchemaInitBasicType("NMTOKEN",
Daniel Veillard6560a422003-03-27 21:25:38 +0000349 XML_SCHEMAS_NMTOKEN);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000350 xmlSchemaTypeNmtokensDef = xmlSchemaInitBasicType("NMTOKENS",
Daniel Veillard6560a422003-03-27 21:25:38 +0000351 XML_SCHEMAS_NMTOKENS);
Daniel Veillard4255d502002-04-16 15:50:10 +0000352 xmlSchemaTypesInitialized = 1;
353}
354
355/**
356 * xmlSchemaCleanupTypes:
357 *
358 * Cleanup the default XML Schemas type library
359 */
360void
361xmlSchemaCleanupTypes(void) {
362 if (xmlSchemaTypesInitialized == 0)
363 return;
364 xmlHashFree(xmlSchemaTypesBank, (xmlHashDeallocator) xmlSchemaFreeType);
365 xmlSchemaTypesInitialized = 0;
366}
367
368/**
369 * xmlSchemaNewValue:
370 * @type: the value type
371 *
372 * Allocate a new simple type value
373 *
374 * Returns a pointer to the new value or NULL in case of error
375 */
376static xmlSchemaValPtr
377xmlSchemaNewValue(xmlSchemaValType type) {
378 xmlSchemaValPtr value;
379
380 value = (xmlSchemaValPtr) xmlMalloc(sizeof(xmlSchemaVal));
381 if (value == NULL) {
382 return(NULL);
383 }
384 memset(value, 0, sizeof(xmlSchemaVal));
385 value->type = type;
386 return(value);
387}
388
389/**
390 * xmlSchemaFreeValue:
391 * @value: the value to free
392 *
393 * Cleanup the default XML Schemas type library
394 */
395void
396xmlSchemaFreeValue(xmlSchemaValPtr value) {
397 if (value == NULL)
398 return;
Daniel Veillardc4c21552003-03-29 10:53:38 +0000399 switch (value->type) {
400 case XML_SCHEMAS_STRING:
401 case XML_SCHEMAS_NORMSTRING:
402 case XML_SCHEMAS_TOKEN:
403 case XML_SCHEMAS_LANGUAGE:
404 case XML_SCHEMAS_NMTOKEN:
405 case XML_SCHEMAS_NMTOKENS:
406 case XML_SCHEMAS_NAME:
Daniel Veillardc4c21552003-03-29 10:53:38 +0000407 case XML_SCHEMAS_NCNAME:
408 case XML_SCHEMAS_ID:
409 case XML_SCHEMAS_IDREF:
410 case XML_SCHEMAS_IDREFS:
411 case XML_SCHEMAS_ENTITY:
412 case XML_SCHEMAS_ENTITIES:
413 case XML_SCHEMAS_NOTATION:
414 case XML_SCHEMAS_ANYURI:
415 if (value->value.str != NULL)
416 xmlFree(value->value.str);
417 break;
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000418 case XML_SCHEMAS_QNAME:
419 if (value->value.qname.uri != NULL)
420 xmlFree(value->value.qname.uri);
421 if (value->value.qname.name != NULL)
422 xmlFree(value->value.qname.name);
423 break;
Daniel Veillard70bcb0e2003-08-08 14:00:28 +0000424 case XML_SCHEMAS_HEXBINARY:
425 if (value->value.hex.str != NULL)
426 xmlFree(value->value.hex.str);
427 break;
Daniel Veillardc4c21552003-03-29 10:53:38 +0000428 default:
429 break;
430 }
Daniel Veillard4255d502002-04-16 15:50:10 +0000431 xmlFree(value);
432}
433
434/**
435 * xmlSchemaGetPredefinedType:
436 * @name: the type name
437 * @ns: the URI of the namespace usually "http://www.w3.org/2001/XMLSchema"
438 *
439 * Lookup a type in the default XML Schemas type library
440 *
441 * Returns the type if found, NULL otherwise
442 */
443xmlSchemaTypePtr
444xmlSchemaGetPredefinedType(const xmlChar *name, const xmlChar *ns) {
445 if (xmlSchemaTypesInitialized == 0)
446 xmlSchemaInitTypes();
447 if (name == NULL)
448 return(NULL);
449 return((xmlSchemaTypePtr) xmlHashLookup2(xmlSchemaTypesBank, name, ns));
450}
Daniel Veillard070803b2002-05-03 07:29:38 +0000451
452/****************************************************************
453 * *
454 * Convenience macros and functions *
455 * *
456 ****************************************************************/
457
458#define IS_TZO_CHAR(c) \
459 ((c == 0) || (c == 'Z') || (c == '+') || (c == '-'))
460
461#define VALID_YEAR(yr) (yr != 0)
462#define VALID_MONTH(mon) ((mon >= 1) && (mon <= 12))
463/* VALID_DAY should only be used when month is unknown */
464#define VALID_DAY(day) ((day >= 1) && (day <= 31))
465#define VALID_HOUR(hr) ((hr >= 0) && (hr <= 23))
466#define VALID_MIN(min) ((min >= 0) && (min <= 59))
467#define VALID_SEC(sec) ((sec >= 0) && (sec < 60))
468#define VALID_TZO(tzo) ((tzo > -1440) && (tzo < 1440))
469#define IS_LEAP(y) \
470 (((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0))
471
472static const long daysInMonth[12] =
473 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
474static const long daysInMonthLeap[12] =
475 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
476
Daniel Veillard5a872412002-05-22 06:40:27 +0000477#define MAX_DAYINMONTH(yr,mon) \
478 (IS_LEAP(yr) ? daysInMonthLeap[mon - 1] : daysInMonth[mon - 1])
479
Daniel Veillard070803b2002-05-03 07:29:38 +0000480#define VALID_MDAY(dt) \
481 (IS_LEAP(dt->year) ? \
482 (dt->day <= daysInMonthLeap[dt->mon - 1]) : \
483 (dt->day <= daysInMonth[dt->mon - 1]))
484
485#define VALID_DATE(dt) \
486 (VALID_YEAR(dt->year) && VALID_MONTH(dt->mon) && VALID_MDAY(dt))
487
488#define VALID_TIME(dt) \
489 (VALID_HOUR(dt->hour) && VALID_MIN(dt->min) && \
490 VALID_SEC(dt->sec) && VALID_TZO(dt->tzo))
491
492#define VALID_DATETIME(dt) \
493 (VALID_DATE(dt) && VALID_TIME(dt))
494
495#define SECS_PER_MIN (60)
496#define SECS_PER_HOUR (60 * SECS_PER_MIN)
497#define SECS_PER_DAY (24 * SECS_PER_HOUR)
498
Daniel Veillard5a872412002-05-22 06:40:27 +0000499static const long dayInYearByMonth[12] =
500 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
501static const long dayInLeapYearByMonth[12] =
502 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 };
503
504#define DAY_IN_YEAR(day, month, year) \
505 ((IS_LEAP(year) ? \
506 dayInLeapYearByMonth[month - 1] : \
507 dayInYearByMonth[month - 1]) + day)
508
509#ifdef DEBUG
510#define DEBUG_DATE(dt) \
511 xmlGenericError(xmlGenericErrorContext, \
512 "type=%o %04ld-%02u-%02uT%02u:%02u:%03f", \
513 dt->type,dt->value.date.year,dt->value.date.mon, \
514 dt->value.date.day,dt->value.date.hour,dt->value.date.min, \
515 dt->value.date.sec); \
516 if (dt->value.date.tz_flag) \
517 if (dt->value.date.tzo != 0) \
518 xmlGenericError(xmlGenericErrorContext, \
519 "%+05d\n",dt->value.date.tzo); \
520 else \
521 xmlGenericError(xmlGenericErrorContext, "Z\n"); \
522 else \
523 xmlGenericError(xmlGenericErrorContext,"\n")
524#else
525#define DEBUG_DATE(dt)
526#endif
527
Daniel Veillard070803b2002-05-03 07:29:38 +0000528/**
529 * _xmlSchemaParseGYear:
530 * @dt: pointer to a date structure
531 * @str: pointer to the string to analyze
532 *
533 * Parses a xs:gYear without time zone and fills in the appropriate
534 * field of the @dt structure. @str is updated to point just after the
535 * xs:gYear. It is supposed that @dt->year is big enough to contain
536 * the year.
537 *
538 * Returns 0 or the error code
539 */
540static int
541_xmlSchemaParseGYear (xmlSchemaValDatePtr dt, const xmlChar **str) {
542 const xmlChar *cur = *str, *firstChar;
543 int isneg = 0, digcnt = 0;
544
545 if (((*cur < '0') || (*cur > '9')) &&
546 (*cur != '-') && (*cur != '+'))
547 return -1;
548
549 if (*cur == '-') {
550 isneg = 1;
551 cur++;
552 }
553
554 firstChar = cur;
555
556 while ((*cur >= '0') && (*cur <= '9')) {
557 dt->year = dt->year * 10 + (*cur - '0');
558 cur++;
559 digcnt++;
560 }
561
562 /* year must be at least 4 digits (CCYY); over 4
563 * digits cannot have a leading zero. */
564 if ((digcnt < 4) || ((digcnt > 4) && (*firstChar == '0')))
565 return 1;
566
567 if (isneg)
568 dt->year = - dt->year;
569
570 if (!VALID_YEAR(dt->year))
571 return 2;
572
573 *str = cur;
574 return 0;
575}
576
577/**
578 * PARSE_2_DIGITS:
579 * @num: the integer to fill in
580 * @cur: an #xmlChar *
581 * @invalid: an integer
582 *
583 * Parses a 2-digits integer and updates @num with the value. @cur is
584 * updated to point just after the integer.
585 * In case of error, @invalid is set to %TRUE, values of @num and
586 * @cur are undefined.
587 */
588#define PARSE_2_DIGITS(num, cur, invalid) \
589 if ((cur[0] < '0') || (cur[0] > '9') || \
590 (cur[1] < '0') || (cur[1] > '9')) \
591 invalid = 1; \
592 else \
593 num = (cur[0] - '0') * 10 + (cur[1] - '0'); \
594 cur += 2;
595
596/**
597 * PARSE_FLOAT:
598 * @num: the double to fill in
599 * @cur: an #xmlChar *
600 * @invalid: an integer
601 *
602 * Parses a float and updates @num with the value. @cur is
603 * updated to point just after the float. The float must have a
604 * 2-digits integer part and may or may not have a decimal part.
605 * In case of error, @invalid is set to %TRUE, values of @num and
606 * @cur are undefined.
607 */
608#define PARSE_FLOAT(num, cur, invalid) \
609 PARSE_2_DIGITS(num, cur, invalid); \
610 if (!invalid && (*cur == '.')) { \
611 double mult = 1; \
612 cur++; \
613 if ((*cur < '0') || (*cur > '9')) \
614 invalid = 1; \
615 while ((*cur >= '0') && (*cur <= '9')) { \
616 mult /= 10; \
617 num += (*cur - '0') * mult; \
618 cur++; \
619 } \
620 }
621
622/**
623 * _xmlSchemaParseGMonth:
624 * @dt: pointer to a date structure
625 * @str: pointer to the string to analyze
626 *
627 * Parses a xs:gMonth without time zone and fills in the appropriate
628 * field of the @dt structure. @str is updated to point just after the
629 * xs:gMonth.
630 *
631 * Returns 0 or the error code
632 */
633static int
634_xmlSchemaParseGMonth (xmlSchemaValDatePtr dt, const xmlChar **str) {
635 const xmlChar *cur = *str;
636 int ret = 0;
637
638 PARSE_2_DIGITS(dt->mon, cur, ret);
639 if (ret != 0)
640 return ret;
641
642 if (!VALID_MONTH(dt->mon))
643 return 2;
644
645 *str = cur;
646 return 0;
647}
648
649/**
650 * _xmlSchemaParseGDay:
651 * @dt: pointer to a date structure
652 * @str: pointer to the string to analyze
653 *
654 * Parses a xs:gDay without time zone and fills in the appropriate
655 * field of the @dt structure. @str is updated to point just after the
656 * xs:gDay.
657 *
658 * Returns 0 or the error code
659 */
660static int
661_xmlSchemaParseGDay (xmlSchemaValDatePtr dt, const xmlChar **str) {
662 const xmlChar *cur = *str;
663 int ret = 0;
664
665 PARSE_2_DIGITS(dt->day, cur, ret);
666 if (ret != 0)
667 return ret;
668
669 if (!VALID_DAY(dt->day))
670 return 2;
671
672 *str = cur;
673 return 0;
674}
675
676/**
677 * _xmlSchemaParseTime:
678 * @dt: pointer to a date structure
679 * @str: pointer to the string to analyze
680 *
681 * Parses a xs:time without time zone and fills in the appropriate
682 * fields of the @dt structure. @str is updated to point just after the
683 * xs:time.
684 * In case of error, values of @dt fields are undefined.
685 *
686 * Returns 0 or the error code
687 */
688static int
689_xmlSchemaParseTime (xmlSchemaValDatePtr dt, const xmlChar **str) {
690 const xmlChar *cur = *str;
691 unsigned int hour = 0; /* use temp var in case str is not xs:time */
692 int ret = 0;
693
694 PARSE_2_DIGITS(hour, cur, ret);
695 if (ret != 0)
696 return ret;
697
698 if (*cur != ':')
699 return 1;
700 cur++;
701
702 /* the ':' insures this string is xs:time */
703 dt->hour = hour;
704
705 PARSE_2_DIGITS(dt->min, cur, ret);
706 if (ret != 0)
707 return ret;
708
709 if (*cur != ':')
710 return 1;
711 cur++;
712
713 PARSE_FLOAT(dt->sec, cur, ret);
714 if (ret != 0)
715 return ret;
716
717 if (!VALID_TIME(dt))
718 return 2;
719
720 *str = cur;
721 return 0;
722}
723
724/**
725 * _xmlSchemaParseTimeZone:
726 * @dt: pointer to a date structure
727 * @str: pointer to the string to analyze
728 *
729 * Parses a time zone without time zone and fills in the appropriate
730 * field of the @dt structure. @str is updated to point just after the
731 * time zone.
732 *
733 * Returns 0 or the error code
734 */
735static int
736_xmlSchemaParseTimeZone (xmlSchemaValDatePtr dt, const xmlChar **str) {
737 const xmlChar *cur = *str;
738 int ret = 0;
739
740 if (str == NULL)
741 return -1;
742
743 switch (*cur) {
744 case 0:
745 dt->tz_flag = 0;
746 dt->tzo = 0;
747 break;
748
749 case 'Z':
750 dt->tz_flag = 1;
751 dt->tzo = 0;
752 cur++;
753 break;
754
755 case '+':
756 case '-': {
757 int isneg = 0, tmp = 0;
758 isneg = (*cur == '-');
759
760 cur++;
761
762 PARSE_2_DIGITS(tmp, cur, ret);
763 if (ret != 0)
764 return ret;
765 if (!VALID_HOUR(tmp))
766 return 2;
767
768 if (*cur != ':')
769 return 1;
770 cur++;
771
772 dt->tzo = tmp * 60;
773
774 PARSE_2_DIGITS(tmp, cur, ret);
775 if (ret != 0)
776 return ret;
777 if (!VALID_MIN(tmp))
778 return 2;
779
780 dt->tzo += tmp;
781 if (isneg)
782 dt->tzo = - dt->tzo;
783
784 if (!VALID_TZO(dt->tzo))
785 return 2;
786
Daniel Veillard5a872412002-05-22 06:40:27 +0000787 dt->tz_flag = 1;
Daniel Veillard070803b2002-05-03 07:29:38 +0000788 break;
789 }
790 default:
791 return 1;
792 }
793
794 *str = cur;
795 return 0;
796}
797
798/****************************************************************
799 * *
800 * XML Schema Dates/Times Datatypes Handling *
801 * *
802 ****************************************************************/
803
804/**
805 * PARSE_DIGITS:
806 * @num: the integer to fill in
807 * @cur: an #xmlChar *
808 * @num_type: an integer flag
809 *
810 * Parses a digits integer and updates @num with the value. @cur is
811 * updated to point just after the integer.
812 * In case of error, @num_type is set to -1, values of @num and
813 * @cur are undefined.
814 */
815#define PARSE_DIGITS(num, cur, num_type) \
816 if ((*cur < '0') || (*cur > '9')) \
817 num_type = -1; \
818 else \
819 while ((*cur >= '0') && (*cur <= '9')) { \
820 num = num * 10 + (*cur - '0'); \
821 cur++; \
822 }
823
824/**
825 * PARSE_NUM:
826 * @num: the double to fill in
827 * @cur: an #xmlChar *
828 * @num_type: an integer flag
829 *
830 * Parses a float or integer and updates @num with the value. @cur is
831 * updated to point just after the number. If the number is a float,
832 * then it must have an integer part and a decimal part; @num_type will
833 * be set to 1. If there is no decimal part, @num_type is set to zero.
834 * In case of error, @num_type is set to -1, values of @num and
835 * @cur are undefined.
836 */
837#define PARSE_NUM(num, cur, num_type) \
838 num = 0; \
839 PARSE_DIGITS(num, cur, num_type); \
840 if (!num_type && (*cur == '.')) { \
841 double mult = 1; \
842 cur++; \
843 if ((*cur < '0') || (*cur > '9')) \
844 num_type = -1; \
845 else \
846 num_type = 1; \
847 while ((*cur >= '0') && (*cur <= '9')) { \
848 mult /= 10; \
849 num += (*cur - '0') * mult; \
850 cur++; \
851 } \
852 }
853
854/**
Daniel Veillard5a872412002-05-22 06:40:27 +0000855 * xmlSchemaValidateDates:
Daniel Veillard455cc072003-03-31 10:13:23 +0000856 * @type: the expected type or XML_SCHEMAS_UNKNOWN
Daniel Veillard070803b2002-05-03 07:29:38 +0000857 * @dateTime: string to analyze
858 * @val: the return computed value
859 *
860 * Check that @dateTime conforms to the lexical space of one of the date types.
861 * if true a value is computed and returned in @val.
862 *
863 * Returns 0 if this validates, a positive error code number otherwise
864 * and -1 in case of internal or API error.
865 */
866static int
Daniel Veillard455cc072003-03-31 10:13:23 +0000867xmlSchemaValidateDates (xmlSchemaValType type,
Daniel Veillard118aed72002-09-24 14:13:13 +0000868 const xmlChar *dateTime, xmlSchemaValPtr *val) {
Daniel Veillard070803b2002-05-03 07:29:38 +0000869 xmlSchemaValPtr dt;
870 int ret;
871 const xmlChar *cur = dateTime;
872
873#define RETURN_TYPE_IF_VALID(t) \
874 if (IS_TZO_CHAR(*cur)) { \
875 ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur); \
876 if (ret == 0) { \
877 if (*cur != 0) \
878 goto error; \
879 dt->type = t; \
Daniel Veillard455cc072003-03-31 10:13:23 +0000880 goto done; \
Daniel Veillard070803b2002-05-03 07:29:38 +0000881 } \
882 }
883
884 if (dateTime == NULL)
885 return -1;
886
887 if ((*cur != '-') && (*cur < '0') && (*cur > '9'))
888 return 1;
889
890 dt = xmlSchemaNewValue(XML_SCHEMAS_UNKNOWN);
891 if (dt == NULL)
892 return -1;
893
894 if ((cur[0] == '-') && (cur[1] == '-')) {
895 /*
896 * It's an incomplete date (xs:gMonthDay, xs:gMonth or
897 * xs:gDay)
898 */
899 cur += 2;
900
901 /* is it an xs:gDay? */
902 if (*cur == '-') {
Daniel Veillard455cc072003-03-31 10:13:23 +0000903 if (type == XML_SCHEMAS_GMONTH)
904 goto error;
Daniel Veillard070803b2002-05-03 07:29:38 +0000905 ++cur;
906 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
907 if (ret != 0)
908 goto error;
909
910 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GDAY);
911
912 goto error;
913 }
914
915 /*
916 * it should be an xs:gMonthDay or xs:gMonth
917 */
918 ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
919 if (ret != 0)
920 goto error;
921
Daniel Veillardd3b9cd82003-04-09 11:24:17 +0000922 /*
923 * a '-' char could indicate this type is xs:gMonthDay or
924 * a negative time zone offset. Check for xs:gMonthDay first.
925 * Also the first three char's of a negative tzo (-MM:SS) can
926 * appear to be a valid day; so even if the day portion
927 * of the xs:gMonthDay verifies, we must insure it was not
928 * a tzo.
929 */
930 if (*cur == '-') {
931 const xmlChar *rewnd = cur;
932 cur++;
Daniel Veillard070803b2002-05-03 07:29:38 +0000933
Daniel Veillardd3b9cd82003-04-09 11:24:17 +0000934 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
935 if ((ret == 0) && ((*cur == 0) || (*cur != ':'))) {
936
937 /*
938 * we can use the VALID_MDAY macro to validate the month
939 * and day because the leap year test will flag year zero
940 * as a leap year (even though zero is an invalid year).
941 */
942 if (VALID_MDAY((&(dt->value.date)))) {
943
944 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTHDAY);
945
946 goto error;
947 }
948 }
949
950 /*
951 * not xs:gMonthDay so rewind and check if just xs:gMonth
952 * with an optional time zone.
953 */
954 cur = rewnd;
955 }
956
957 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTH);
Daniel Veillard070803b2002-05-03 07:29:38 +0000958
959 goto error;
960 }
961
962 /*
963 * It's a right-truncated date or an xs:time.
964 * Try to parse an xs:time then fallback on right-truncated dates.
965 */
966 if ((*cur >= '0') && (*cur <= '9')) {
967 ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
968 if (ret == 0) {
969 /* it's an xs:time */
970 RETURN_TYPE_IF_VALID(XML_SCHEMAS_TIME);
971 }
972 }
973
974 /* fallback on date parsing */
975 cur = dateTime;
976
977 ret = _xmlSchemaParseGYear(&(dt->value.date), &cur);
978 if (ret != 0)
979 goto error;
980
981 /* is it an xs:gYear? */
982 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEAR);
983
984 if (*cur != '-')
985 goto error;
986 cur++;
987
988 ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
989 if (ret != 0)
990 goto error;
991
992 /* is it an xs:gYearMonth? */
993 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEARMONTH);
994
995 if (*cur != '-')
996 goto error;
997 cur++;
998
999 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
1000 if ((ret != 0) || !VALID_DATE((&(dt->value.date))))
1001 goto error;
1002
1003 /* is it an xs:date? */
1004 RETURN_TYPE_IF_VALID(XML_SCHEMAS_DATE);
1005
1006 if (*cur != 'T')
1007 goto error;
1008 cur++;
1009
1010 /* it should be an xs:dateTime */
1011 ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
1012 if (ret != 0)
1013 goto error;
1014
1015 ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur);
1016 if ((ret != 0) || (*cur != 0) || !VALID_DATETIME((&(dt->value.date))))
1017 goto error;
1018
Daniel Veillard455cc072003-03-31 10:13:23 +00001019
Daniel Veillard070803b2002-05-03 07:29:38 +00001020 dt->type = XML_SCHEMAS_DATETIME;
1021
Daniel Veillard455cc072003-03-31 10:13:23 +00001022done:
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001023#if 1
1024 if ((type != XML_SCHEMAS_UNKNOWN) && (type != dt->type))
1025 goto error;
1026#else
1027 /*
1028 * insure the parsed type is equal to or less significant (right
1029 * truncated) than the desired type.
1030 */
1031 if ((type != XML_SCHEMAS_UNKNOWN) && (type != dt->type)) {
1032
1033 /* time only matches time */
1034 if ((type == XML_SCHEMAS_TIME) && (dt->type == XML_SCHEMAS_TIME))
1035 goto error;
1036
1037 if ((type == XML_SCHEMAS_DATETIME) &&
1038 ((dt->type != XML_SCHEMAS_DATE) ||
1039 (dt->type != XML_SCHEMAS_GYEARMONTH) ||
1040 (dt->type != XML_SCHEMAS_GYEAR)))
1041 goto error;
1042
1043 if ((type == XML_SCHEMAS_DATE) &&
1044 ((dt->type != XML_SCHEMAS_GYEAR) ||
1045 (dt->type != XML_SCHEMAS_GYEARMONTH)))
1046 goto error;
1047
1048 if ((type == XML_SCHEMAS_GYEARMONTH) && (dt->type != XML_SCHEMAS_GYEAR))
1049 goto error;
1050
1051 if ((type == XML_SCHEMAS_GMONTHDAY) && (dt->type != XML_SCHEMAS_GMONTH))
1052 goto error;
1053 }
Daniel Veillard455cc072003-03-31 10:13:23 +00001054#endif
1055
Daniel Veillard070803b2002-05-03 07:29:38 +00001056 if (val != NULL)
1057 *val = dt;
Daniel Veillard80b19092003-03-28 13:29:53 +00001058 else
1059 xmlSchemaFreeValue(dt);
Daniel Veillard070803b2002-05-03 07:29:38 +00001060
1061 return 0;
1062
1063error:
1064 if (dt != NULL)
1065 xmlSchemaFreeValue(dt);
1066 return 1;
1067}
1068
1069/**
Daniel Veillard5a872412002-05-22 06:40:27 +00001070 * xmlSchemaValidateDuration:
Daniel Veillard070803b2002-05-03 07:29:38 +00001071 * @type: the predefined type
1072 * @duration: string to analyze
1073 * @val: the return computed value
1074 *
1075 * Check that @duration conforms to the lexical space of the duration type.
1076 * if true a value is computed and returned in @val.
1077 *
1078 * Returns 0 if this validates, a positive error code number otherwise
1079 * and -1 in case of internal or API error.
1080 */
1081static int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00001082xmlSchemaValidateDuration (xmlSchemaTypePtr type ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +00001083 const xmlChar *duration, xmlSchemaValPtr *val) {
Daniel Veillard070803b2002-05-03 07:29:38 +00001084 const xmlChar *cur = duration;
1085 xmlSchemaValPtr dur;
1086 int isneg = 0;
1087 unsigned int seq = 0;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001088 double num;
1089 int num_type = 0; /* -1 = invalid, 0 = int, 1 = floating */
1090 const xmlChar desig[] = {'Y', 'M', 'D', 'H', 'M', 'S'};
1091 const double multi[] = { 0.0, 0.0, 86400.0, 3600.0, 60.0, 1.0, 0.0};
Daniel Veillard070803b2002-05-03 07:29:38 +00001092
1093 if (duration == NULL)
1094 return -1;
1095
1096 if (*cur == '-') {
1097 isneg = 1;
1098 cur++;
1099 }
1100
1101 /* duration must start with 'P' (after sign) */
1102 if (*cur++ != 'P')
1103 return 1;
1104
Daniel Veillard80b19092003-03-28 13:29:53 +00001105 if (*cur == 0)
1106 return 1;
1107
Daniel Veillard070803b2002-05-03 07:29:38 +00001108 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
1109 if (dur == NULL)
1110 return -1;
1111
1112 while (*cur != 0) {
Daniel Veillard070803b2002-05-03 07:29:38 +00001113
1114 /* input string should be empty or invalid date/time item */
1115 if (seq >= sizeof(desig))
1116 goto error;
1117
1118 /* T designator must be present for time items */
1119 if (*cur == 'T') {
1120 if (seq <= 3) {
1121 seq = 3;
1122 cur++;
1123 } else
1124 return 1;
1125 } else if (seq == 3)
1126 goto error;
1127
1128 /* parse the number portion of the item */
1129 PARSE_NUM(num, cur, num_type);
1130
1131 if ((num_type == -1) || (*cur == 0))
1132 goto error;
1133
1134 /* update duration based on item type */
1135 while (seq < sizeof(desig)) {
1136 if (*cur == desig[seq]) {
1137
1138 /* verify numeric type; only seconds can be float */
1139 if ((num_type != 0) && (seq < (sizeof(desig)-1)))
1140 goto error;
1141
1142 switch (seq) {
1143 case 0:
1144 dur->value.dur.mon = (long)num * 12;
1145 break;
1146 case 1:
1147 dur->value.dur.mon += (long)num;
1148 break;
1149 default:
1150 /* convert to seconds using multiplier */
1151 dur->value.dur.sec += num * multi[seq];
1152 seq++;
1153 break;
1154 }
1155
1156 break; /* exit loop */
1157 }
1158 /* no date designators found? */
1159 if (++seq == 3)
1160 goto error;
1161 }
1162 cur++;
1163 }
1164
1165 if (isneg) {
1166 dur->value.dur.mon = -dur->value.dur.mon;
1167 dur->value.dur.day = -dur->value.dur.day;
1168 dur->value.dur.sec = -dur->value.dur.sec;
1169 }
1170
1171 if (val != NULL)
1172 *val = dur;
Daniel Veillard80b19092003-03-28 13:29:53 +00001173 else
1174 xmlSchemaFreeValue(dur);
Daniel Veillard070803b2002-05-03 07:29:38 +00001175
1176 return 0;
1177
1178error:
1179 if (dur != NULL)
1180 xmlSchemaFreeValue(dur);
1181 return 1;
1182}
1183
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001184/**
1185 * xmlSchemaStrip:
1186 * @value: a value
1187 *
1188 * Removes the leading and ending spaces of a string
1189 *
1190 * Returns the new string or NULL if no change was required.
1191 */
1192static xmlChar *
1193xmlSchemaStrip(const xmlChar *value) {
1194 const xmlChar *start = value, *end, *f;
1195
1196 if (value == NULL) return(NULL);
1197 while ((*start != 0) && (IS_BLANK(*start))) start++;
1198 end = start;
1199 while (*end != 0) end++;
1200 f = end;
1201 end--;
1202 while ((end > start) && (IS_BLANK(*end))) end--;
1203 end++;
1204 if ((start == value) && (f == end)) return(NULL);
1205 return(xmlStrndup(start, end - start));
1206}
Daniel Veillard96a4b252003-02-06 08:22:32 +00001207
1208/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001209 * xmlSchemaCollapseString:
1210 * @value: a value
1211 *
1212 * Removes and normalize white spaces in the string
1213 *
1214 * Returns the new string or NULL if no change was required.
1215 */
1216static xmlChar *
1217xmlSchemaCollapseString(const xmlChar *value) {
1218 const xmlChar *start = value, *end, *f;
1219 xmlChar *g;
1220 int col = 0;
1221
1222 if (value == NULL) return(NULL);
1223 while ((*start != 0) && (IS_BLANK(*start))) start++;
1224 end = start;
1225 while (*end != 0) {
1226 if ((*end == ' ') && (IS_BLANK(end[1]))) {
1227 col = end - start;
1228 break;
1229 } else if ((*end == 0xa) || (*end == 0x9) || (*end == 0xd)) {
1230 col = end - start;
1231 break;
1232 }
1233 end++;
1234 }
1235 if (col == 0) {
1236 f = end;
1237 end--;
1238 while ((end > start) && (IS_BLANK(*end))) end--;
1239 end++;
1240 if ((start == value) && (f == end)) return(NULL);
1241 return(xmlStrndup(start, end - start));
1242 }
1243 start = xmlStrdup(start);
1244 if (start == NULL) return(NULL);
1245 g = (xmlChar *) (start + col);
1246 end = g;
1247 while (*end != 0) {
1248 if (IS_BLANK(*end)) {
1249 end++;
1250 while (IS_BLANK(*end)) end++;
1251 if (*end != 0)
1252 *g++ = ' ';
1253 } else
1254 *g++ = *end++;
1255 }
1256 *g = 0;
1257 return((xmlChar *) start);
1258}
1259
1260/**
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001261 * xmlSchemaValAtomicListNode:
1262 * @type: the predefined atomic type for a token in the list
1263 * @value: the list value to check
1264 * @ret: the return computed value
1265 * @node: the node containing the value
1266 *
1267 * Check that a value conforms to the lexical space of the predefined
1268 * list type. if true a value is computed and returned in @ret.
1269 *
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001270 * Returns the number of items if this validates, a negative error code
1271 * number otherwise
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001272 */
1273static int
1274xmlSchemaValAtomicListNode(xmlSchemaTypePtr type, const xmlChar *value,
1275 xmlSchemaValPtr *ret, xmlNodePtr node) {
1276 xmlChar *val, *cur, *endval;
1277 int nb_values = 0;
Daniel Veillard580ced82003-03-21 21:22:48 +00001278 int tmp = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001279
1280 if (value == NULL) {
1281 return(-1);
1282 }
1283 val = xmlStrdup(value);
1284 if (val == NULL) {
1285 return(-1);
1286 }
1287 cur = val;
1288 /*
1289 * Split the list
1290 */
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001291 while (IS_BLANK(*cur)) *cur++ = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001292 while (*cur != 0) {
1293 if (IS_BLANK(*cur)) {
1294 *cur = 0;
1295 cur++;
1296 while (IS_BLANK(*cur)) *cur++ = 0;
1297 } else {
1298 nb_values++;
1299 cur++;
1300 while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
1301 }
1302 }
1303 if (nb_values == 0) {
1304 if (ret != NULL) {
1305 TODO
1306 }
1307 xmlFree(val);
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001308 return(nb_values);
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001309 }
1310 endval = cur;
1311 cur = val;
1312 while ((*cur == 0) && (cur != endval)) cur++;
1313 while (cur != endval) {
1314 tmp = xmlSchemaValPredefTypeNode(type, cur, NULL, node);
1315 if (tmp != 0)
1316 break;
1317 while (*cur != 0) cur++;
1318 while ((*cur == 0) && (cur != endval)) cur++;
1319 }
1320 xmlFree(val);
1321 if (ret != NULL) {
1322 TODO
1323 }
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001324 if (tmp == 0)
1325 return(nb_values);
1326 return(-1);
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001327}
1328
1329/**
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001330 * xmlSchemaParseUInt:
1331 * @str: pointer to the string R/W
1332 * @llo: pointer to the low result
1333 * @lmi: pointer to the mid result
1334 * @lhi: pointer to the high result
1335 *
1336 * Parse an unsigned long into 3 fields.
1337 *
1338 * Returns the number of chars parsed or -1 if overflow of the capacity
1339 */
1340static int
1341xmlSchemaParseUInt(const xmlChar **str, unsigned long *llo,
1342 unsigned long *lmi, unsigned long *lhi) {
1343 unsigned long lo = 0, mi = 0, hi = 0;
1344 const xmlChar *tmp, *cur = *str;
1345 int ret = 0, i = 0;
1346
1347 while (*cur == '0') {
1348 ret++;
1349 cur++;
1350 }
1351 tmp = cur;
1352 while ((*tmp != 0) && (*tmp >= '0') && (*tmp <= '9')) {
1353 i++;tmp++;ret++;
1354 }
1355 if (i > 24) {
1356 *str = tmp;
1357 return(-1);
1358 }
1359 while (i > 16) {
1360 hi = hi * 10 + (*cur++ - '0');
1361 i--;
1362 }
1363 while (i > 8) {
1364 mi = mi * 10 + (*cur++ - '0');
1365 i--;
1366 }
1367 while (i > 0) {
1368 lo = lo * 10 + (*cur++ - '0');
1369 i--;
1370 }
1371
1372 *str = cur;
1373 *llo = lo;
1374 *lmi = mi;
1375 *lhi = hi;
1376 return(ret);
1377}
1378
1379/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001380 * xmlSchemaValAtomicType:
1381 * @type: the predefined type
1382 * @value: the value to check
1383 * @val: the return computed value
1384 * @node: the node containing the value
1385 * flags: flags to control the vlidation
1386 *
1387 * Check that a value conforms to the lexical space of the atomic type.
1388 * if true a value is computed and returned in @val.
1389 *
1390 * Returns 0 if this validates, a positive error code number otherwise
1391 * and -1 in case of internal or API error.
1392 */
1393static int
1394xmlSchemaValAtomicType(xmlSchemaTypePtr type, const xmlChar *value,
1395 xmlSchemaValPtr *val, xmlNodePtr node, int flags) {
1396 xmlSchemaValPtr v;
1397 xmlChar *norm = NULL;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001398 int ret = 0;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001399
1400 if (xmlSchemaTypesInitialized == 0)
1401 return(-1);
1402 if (type == NULL)
1403 return(-1);
1404
1405 if (val != NULL)
1406 *val = NULL;
1407 if ((flags == 0) && (value != NULL)) {
1408 if ((type->flags != XML_SCHEMAS_STRING) &&
1409 (type->flags != XML_SCHEMAS_NORMSTRING)) {
1410 norm = xmlSchemaCollapseString(value);
1411 if (norm != NULL)
1412 value = norm;
1413 }
1414 }
1415
1416 switch (type->flags) {
1417 case XML_SCHEMAS_UNKNOWN:
1418 if (type == xmlSchemaTypeAnyTypeDef)
1419 goto return0;
1420 goto error;
1421 case XML_SCHEMAS_STRING:
1422 goto return0;
1423 case XML_SCHEMAS_NORMSTRING:
1424 TODO
1425 goto return0;
1426 case XML_SCHEMAS_DECIMAL: {
1427 const xmlChar *cur = value, *tmp;
William M. Brackc1939562003-08-05 15:52:22 +00001428 unsigned int frac = 0, len, neg = 0;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001429 unsigned long base = 0;
1430 if (cur == NULL)
1431 goto return1;
1432 if (*cur == '+')
1433 cur++;
1434 else if (*cur == '-') {
1435 neg = 1;
1436 cur++;
1437 }
1438 tmp = cur;
1439 while ((*cur >= '0') && (*cur <= '9')) {
1440 base = base * 10 + (*cur - '0');
1441 cur++;
1442 }
1443 len = cur - tmp;
1444 if (*cur == '.') {
1445 cur++;
1446 tmp = cur;
1447 while ((*cur >= '0') && (*cur <= '9')) {
1448 base = base * 10 + (*cur - '0');
1449 cur++;
1450 }
1451 frac = cur - tmp;
1452 }
1453 if (*cur != 0)
1454 goto return1;
1455 if (val != NULL) {
1456 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
1457 if (v != NULL) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001458 v->value.decimal.lo = base;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001459 v->value.decimal.sign = neg;
1460 v->value.decimal.frac = frac;
1461 v->value.decimal.total = frac + len;
1462 *val = v;
1463 }
1464 }
1465 goto return0;
1466 }
1467 case XML_SCHEMAS_TIME:
1468 case XML_SCHEMAS_GDAY:
1469 case XML_SCHEMAS_GMONTH:
1470 case XML_SCHEMAS_GMONTHDAY:
1471 case XML_SCHEMAS_GYEAR:
1472 case XML_SCHEMAS_GYEARMONTH:
1473 case XML_SCHEMAS_DATE:
1474 case XML_SCHEMAS_DATETIME:
Daniel Veillard455cc072003-03-31 10:13:23 +00001475 ret = xmlSchemaValidateDates(type->flags, value, val);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001476 break;
1477 case XML_SCHEMAS_DURATION:
1478 ret = xmlSchemaValidateDuration(type, value, val);
1479 break;
1480 case XML_SCHEMAS_FLOAT:
1481 case XML_SCHEMAS_DOUBLE: {
1482 const xmlChar *cur = value;
1483 int neg = 0;
1484 if (cur == NULL)
1485 goto return1;
1486 if ((cur[0] == 'N') && (cur[1] == 'a') && (cur[2] == 'N')) {
1487 cur += 3;
1488 if (*cur != 0)
1489 goto return1;
1490 if (val != NULL) {
1491 if (type == xmlSchemaTypeFloatDef) {
1492 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1493 if (v != NULL) {
1494 v->value.f = (float) xmlXPathNAN;
1495 } else {
1496 xmlSchemaFreeValue(v);
1497 goto error;
1498 }
1499 } else {
1500 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1501 if (v != NULL) {
1502 v->value.d = xmlXPathNAN;
1503 } else {
1504 xmlSchemaFreeValue(v);
1505 goto error;
1506 }
1507 }
1508 *val = v;
1509 }
1510 goto return0;
1511 }
1512 if (*cur == '-') {
1513 neg = 1;
1514 cur++;
1515 }
1516 if ((cur[0] == 'I') && (cur[1] == 'N') && (cur[2] == 'F')) {
1517 cur += 3;
1518 if (*cur != 0)
1519 goto return1;
1520 if (val != NULL) {
1521 if (type == xmlSchemaTypeFloatDef) {
1522 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1523 if (v != NULL) {
1524 if (neg)
1525 v->value.f = (float) xmlXPathNINF;
1526 else
1527 v->value.f = (float) xmlXPathPINF;
1528 } else {
1529 xmlSchemaFreeValue(v);
1530 goto error;
1531 }
1532 } else {
1533 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1534 if (v != NULL) {
1535 if (neg)
1536 v->value.d = xmlXPathNINF;
1537 else
1538 v->value.d = xmlXPathPINF;
1539 } else {
1540 xmlSchemaFreeValue(v);
1541 goto error;
1542 }
1543 }
1544 *val = v;
1545 }
1546 goto return0;
1547 }
1548 if ((neg == 0) && (*cur == '+'))
1549 cur++;
1550 if ((cur[0] == 0) || (cur[0] == '+') || (cur[0] == '-'))
1551 goto return1;
1552 while ((*cur >= '0') && (*cur <= '9')) {
1553 cur++;
1554 }
1555 if (*cur == '.') {
1556 cur++;
1557 while ((*cur >= '0') && (*cur <= '9'))
1558 cur++;
1559 }
1560 if ((*cur == 'e') || (*cur == 'E')) {
1561 cur++;
1562 if ((*cur == '-') || (*cur == '+'))
1563 cur++;
1564 while ((*cur >= '0') && (*cur <= '9'))
1565 cur++;
1566 }
1567 if (*cur != 0)
1568 goto return1;
1569 if (val != NULL) {
1570 if (type == xmlSchemaTypeFloatDef) {
1571 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1572 if (v != NULL) {
1573 if (sscanf((const char *)value, "%f", &(v->value.f))==1) {
1574 *val = v;
1575 } else {
1576 xmlGenericError(xmlGenericErrorContext,
1577 "failed to scanf float %s\n", value);
1578 xmlSchemaFreeValue(v);
1579 goto return1;
1580 }
1581 } else {
1582 goto error;
1583 }
1584 } else {
1585 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1586 if (v != NULL) {
1587 if (sscanf((const char *)value, "%lf", &(v->value.d))==1) {
1588 *val = v;
1589 } else {
1590 xmlGenericError(xmlGenericErrorContext,
1591 "failed to scanf double %s\n", value);
1592 xmlSchemaFreeValue(v);
1593 goto return1;
1594 }
1595 } else {
1596 goto error;
1597 }
1598 }
1599 }
1600 goto return0;
1601 }
1602 case XML_SCHEMAS_BOOLEAN: {
1603 const xmlChar *cur = value;
1604
1605 if ((cur[0] == '0') && (cur[1] == 0))
1606 ret = 0;
1607 else if ((cur[0] == '1') && (cur[1] == 0))
1608 ret = 1;
1609 else if ((cur[0] == 't') && (cur[1] == 'r') && (cur[2] == 'u') &&
1610 (cur[3] == 'e') && (cur[4] == 0))
1611 ret = 1;
1612 else if ((cur[0] == 'f') && (cur[1] == 'a') && (cur[2] == 'l') &&
1613 (cur[3] == 's') && (cur[4] == 'e') && (cur[5] == 0))
1614 ret = 0;
1615 else
1616 goto return1;
1617 if (val != NULL) {
1618 v = xmlSchemaNewValue(XML_SCHEMAS_BOOLEAN);
1619 if (v != NULL) {
1620 v->value.b = ret;
1621 *val = v;
1622 } else {
1623 goto error;
1624 }
1625 }
1626 goto return0;
1627 }
1628 case XML_SCHEMAS_TOKEN: {
1629 const xmlChar *cur = value;
1630
1631 if (IS_BLANK(*cur))
1632 goto return1;
1633
1634 while (*cur != 0) {
1635 if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) {
1636 goto return1;
1637 } else if (*cur == ' ') {
1638 cur++;
1639 if (*cur == 0)
1640 goto return1;
1641 if (*cur == ' ')
1642 goto return1;
1643 } else {
1644 cur++;
1645 }
1646 }
1647 if (val != NULL) {
1648 v = xmlSchemaNewValue(XML_SCHEMAS_TOKEN);
1649 if (v != NULL) {
1650 v->value.str = xmlStrdup(value);
1651 *val = v;
1652 } else {
1653 goto error;
1654 }
1655 }
1656 goto return0;
1657 }
1658 case XML_SCHEMAS_LANGUAGE:
1659 if (xmlCheckLanguageID(value) == 1) {
1660 if (val != NULL) {
1661 v = xmlSchemaNewValue(XML_SCHEMAS_LANGUAGE);
1662 if (v != NULL) {
1663 v->value.str = xmlStrdup(value);
1664 *val = v;
1665 } else {
1666 goto error;
1667 }
1668 }
1669 goto return0;
1670 }
1671 goto return1;
1672 case XML_SCHEMAS_NMTOKEN:
1673 if (xmlValidateNMToken(value, 1) == 0) {
1674 if (val != NULL) {
1675 v = xmlSchemaNewValue(XML_SCHEMAS_NMTOKEN);
1676 if (v != NULL) {
1677 v->value.str = xmlStrdup(value);
1678 *val = v;
1679 } else {
1680 goto error;
1681 }
1682 }
1683 goto return0;
1684 }
1685 goto return1;
1686 case XML_SCHEMAS_NMTOKENS:
1687 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeNmtokenDef,
1688 value, val, node);
1689 if (ret > 0)
1690 ret = 0;
1691 else
1692 ret = 1;
1693 goto done;
1694 case XML_SCHEMAS_NAME:
1695 ret = xmlValidateName(value, 1);
1696 if ((ret == 0) && (val != NULL)) {
1697 TODO;
1698 }
1699 goto done;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001700 case XML_SCHEMAS_QNAME: {
1701 xmlChar *uri = NULL;
1702 xmlChar *local = NULL;
1703
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001704 ret = xmlValidateQName(value, 1);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001705 if ((ret == 0) && (node != NULL)) {
1706 xmlChar *prefix;
1707 local = xmlSplitQName2(value, &prefix);
1708 if (prefix != NULL) {
1709 xmlNsPtr ns;
1710
1711 ns = xmlSearchNs(node->doc, node, prefix);
1712 if (ns == NULL)
1713 ret = 1;
1714 else if (val != NULL)
1715 uri = xmlStrdup(ns->href);
1716 }
1717 if ((local != NULL) && ((val == NULL) || (ret != 0)))
1718 xmlFree(local);
1719 if (prefix != NULL)
1720 xmlFree(prefix);
1721 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001722 if ((ret == 0) && (val != NULL)) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001723 v = xmlSchemaNewValue(XML_SCHEMAS_QNAME);
1724 if (v != NULL) {
1725 if (local != NULL)
1726 v->value.qname.name = local;
1727 else
1728 v->value.qname.name = xmlStrdup(value);
1729 if (uri != NULL)
1730 v->value.qname.uri = uri;
1731
1732 *val = v;
1733 } else {
1734 if (local != NULL)
1735 xmlFree(local);
1736 if (uri != NULL)
1737 xmlFree(uri);
1738 goto error;
1739 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001740 }
1741 goto done;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001742 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001743 case XML_SCHEMAS_NCNAME:
1744 ret = xmlValidateNCName(value, 1);
1745 if ((ret == 0) && (val != NULL)) {
1746 v = xmlSchemaNewValue(XML_SCHEMAS_NCNAME);
1747 if (v != NULL) {
1748 v->value.str = xmlStrdup(value);
1749 *val = v;
1750 } else {
1751 goto error;
1752 }
1753 }
1754 goto done;
1755 case XML_SCHEMAS_ID:
1756 ret = xmlValidateNCName(value, 1);
1757 if ((ret == 0) && (val != NULL)) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00001758 v = xmlSchemaNewValue(XML_SCHEMAS_ID);
1759 if (v != NULL) {
1760 v->value.str = xmlStrdup(value);
1761 *val = v;
1762 } else {
1763 goto error;
1764 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001765 }
1766 if ((ret == 0) && (node != NULL) &&
1767 (node->type == XML_ATTRIBUTE_NODE)) {
1768 xmlAttrPtr attr = (xmlAttrPtr) node;
1769 /*
1770 * NOTE: the IDness might have already be declared in the DTD
1771 */
1772 if (attr->atype != XML_ATTRIBUTE_ID) {
1773 xmlIDPtr res;
1774 xmlChar *strip;
1775
1776 strip = xmlSchemaStrip(value);
1777 if (strip != NULL) {
1778 res = xmlAddID(NULL, node->doc, strip, attr);
1779 xmlFree(strip);
1780 } else
1781 res = xmlAddID(NULL, node->doc, value, attr);
1782 if (res == NULL) {
1783 ret = 2;
1784 } else {
1785 attr->atype = XML_ATTRIBUTE_ID;
1786 }
1787 }
1788 }
1789 goto done;
1790 case XML_SCHEMAS_IDREF:
1791 ret = xmlValidateNCName(value, 1);
1792 if ((ret == 0) && (val != NULL)) {
1793 TODO;
1794 }
1795 if ((ret == 0) && (node != NULL) &&
1796 (node->type == XML_ATTRIBUTE_NODE)) {
1797 xmlAttrPtr attr = (xmlAttrPtr) node;
1798 xmlChar *strip;
1799
1800 strip = xmlSchemaStrip(value);
1801 if (strip != NULL) {
1802 xmlAddRef(NULL, node->doc, strip, attr);
1803 xmlFree(strip);
1804 } else
1805 xmlAddRef(NULL, node->doc, value, attr);
1806 attr->atype = XML_ATTRIBUTE_IDREF;
1807 }
1808 goto done;
1809 case XML_SCHEMAS_IDREFS:
1810 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeIdrefDef,
1811 value, val, node);
1812 if (ret < 0)
1813 ret = 2;
1814 else
1815 ret = 0;
1816 if ((ret == 0) && (node != NULL) &&
1817 (node->type == XML_ATTRIBUTE_NODE)) {
1818 xmlAttrPtr attr = (xmlAttrPtr) node;
1819
1820 attr->atype = XML_ATTRIBUTE_IDREFS;
1821 }
1822 goto done;
1823 case XML_SCHEMAS_ENTITY: {
1824 xmlChar *strip;
1825 ret = xmlValidateNCName(value, 1);
1826 if ((node == NULL) || (node->doc == NULL))
1827 ret = 3;
1828 if (ret == 0) {
1829 xmlEntityPtr ent;
1830
1831 strip = xmlSchemaStrip(value);
1832 if (strip != NULL) {
1833 ent = xmlGetDocEntity(node->doc, strip);
1834 xmlFree(strip);
1835 } else {
1836 ent = xmlGetDocEntity(node->doc, value);
1837 }
1838 if ((ent == NULL) ||
1839 (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY))
1840 ret = 4;
1841 }
1842 if ((ret == 0) && (val != NULL)) {
1843 TODO;
1844 }
1845 if ((ret == 0) && (node != NULL) &&
1846 (node->type == XML_ATTRIBUTE_NODE)) {
1847 xmlAttrPtr attr = (xmlAttrPtr) node;
1848
1849 attr->atype = XML_ATTRIBUTE_ENTITY;
1850 }
1851 goto done;
1852 }
1853 case XML_SCHEMAS_ENTITIES:
1854 if ((node == NULL) || (node->doc == NULL))
1855 goto return3;
1856 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeEntityDef,
1857 value, val, node);
1858 if (ret <= 0)
1859 ret = 1;
1860 else
1861 ret = 0;
1862 if ((ret == 0) && (node != NULL) &&
1863 (node->type == XML_ATTRIBUTE_NODE)) {
1864 xmlAttrPtr attr = (xmlAttrPtr) node;
1865
1866 attr->atype = XML_ATTRIBUTE_ENTITIES;
1867 }
1868 goto done;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001869 case XML_SCHEMAS_NOTATION: {
1870 xmlChar *uri = NULL;
1871 xmlChar *local = NULL;
1872
1873 ret = xmlValidateQName(value, 1);
1874 if ((ret == 0) && (node != NULL)) {
1875 xmlChar *prefix;
1876 local = xmlSplitQName2(value, &prefix);
1877 if (prefix != NULL) {
1878 xmlNsPtr ns;
1879
1880 ns = xmlSearchNs(node->doc, node, prefix);
1881 if (ns == NULL)
1882 ret = 1;
1883 else if (val != NULL)
1884 uri = xmlStrdup(ns->href);
1885 }
1886 if ((local != NULL) && ((val == NULL) || (ret != 0)))
1887 xmlFree(local);
1888 if (prefix != NULL)
1889 xmlFree(prefix);
1890 }
1891 if ((node == NULL) || (node->doc == NULL))
1892 ret = 3;
1893 if (ret == 0) {
1894 ret = xmlValidateNotationUse(NULL, node->doc, value);
1895 if (ret == 1)
1896 ret = 0;
1897 else
1898 ret = 1;
1899 }
1900 if ((ret == 0) && (val != NULL)) {
1901 v = xmlSchemaNewValue(XML_SCHEMAS_NOTATION);
1902 if (v != NULL) {
1903 if (local != NULL)
1904 v->value.qname.name = local;
1905 else
1906 v->value.qname.name = xmlStrdup(value);
1907 if (uri != NULL)
1908 v->value.qname.uri = uri;
1909
1910 *val = v;
1911 } else {
1912 if (local != NULL)
1913 xmlFree(local);
1914 if (uri != NULL)
1915 xmlFree(uri);
1916 goto error;
1917 }
1918 }
1919 goto done;
1920 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001921 case XML_SCHEMAS_ANYURI: {
1922 xmlURIPtr uri;
1923
1924 uri = xmlParseURI((const char *) value);
1925 if (uri == NULL)
1926 goto return1;
1927 if (val != NULL) {
1928 TODO;
1929 }
1930 xmlFreeURI(uri);
1931 goto return0;
1932 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00001933 case XML_SCHEMAS_HEXBINARY: {
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00001934 const xmlChar *cur = value;
1935 xmlChar *base;
Daniel Veillard560c2a42003-07-06 21:13:49 +00001936 int total, i = 0;
Daniel Veillard560c2a42003-07-06 21:13:49 +00001937
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00001938 if (cur == NULL)
1939 goto return1;
1940
1941 while (((*cur >= '0') && (*cur <= '9')) ||
1942 ((*cur >= 'A') && (*cur <= 'F')) ||
1943 ((*cur >= 'a') && (*cur <= 'f'))) {
1944 i++;cur++;
Daniel Veillard560c2a42003-07-06 21:13:49 +00001945 }
1946
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00001947 if (*cur != 0)
Daniel Veillard560c2a42003-07-06 21:13:49 +00001948 goto return1;
1949 if ((i % 2) != 0)
1950 goto return1;
1951
Daniel Veillard560c2a42003-07-06 21:13:49 +00001952 if (val != NULL) {
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00001953
1954 v = xmlSchemaNewValue(XML_SCHEMAS_HEXBINARY);
1955 if (v == NULL)
Daniel Veillard560c2a42003-07-06 21:13:49 +00001956 goto error;
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00001957
1958 cur = xmlStrdup(value);
1959 if (cur == NULL) {
1960 xmlFree(v);
1961 goto return1;
1962 }
1963
1964 total = i / 2; /* number of octets */
1965
1966 base = (xmlChar *)cur;
1967 while (i-- > 0) {
1968 if (*base >= 'a')
1969 *base = *base - ('a' - 'A');
1970 base++;
1971 }
1972
1973 v->value.hex.str = (xmlChar *)cur;
1974 v->value.hex.total = total;
1975 *val = v;
1976 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00001977 goto return0;
1978 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001979 case XML_SCHEMAS_INTEGER:
1980 case XML_SCHEMAS_PINTEGER:
1981 case XML_SCHEMAS_NPINTEGER:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001982 case XML_SCHEMAS_NINTEGER:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001983 case XML_SCHEMAS_NNINTEGER: {
1984 const xmlChar *cur = value;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001985 unsigned long lo, mi, hi;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001986 int sign = 0;
1987 if (cur == NULL)
1988 goto return1;
1989 if (*cur == '-') {
1990 sign = 1;
1991 cur++;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001992 } else if (*cur == '+')
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001993 cur++;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001994 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
1995 if (ret == 0)
1996 goto return1;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001997 if (*cur != 0)
1998 goto return1;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001999 if (type->flags == XML_SCHEMAS_NPINTEGER) {
2000 if ((sign == 0) &&
2001 ((hi != 0) || (mi != 0) || (lo != 0)))
2002 goto return1;
2003 } else if (type->flags == XML_SCHEMAS_PINTEGER) {
2004 if (sign == 1)
2005 goto return1;
2006 if ((hi == 0) && (mi == 0) && (lo == 0))
2007 goto return1;
2008 } else if (type->flags == XML_SCHEMAS_NINTEGER) {
2009 if (sign == 0)
2010 goto return1;
2011 if ((hi == 0) && (mi == 0) && (lo == 0))
2012 goto return1;
2013 } else if (type->flags == XML_SCHEMAS_NNINTEGER) {
2014 if ((sign == 1) &&
2015 ((hi != 0) || (mi != 0) || (lo != 0)))
2016 goto return1;
2017 }
2018 /*
2019 * We can store a value only if no overflow occured
2020 */
2021 if ((ret > 0) && (val != NULL)) {
2022 v = xmlSchemaNewValue(type->flags);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002023 if (v != NULL) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002024 v->value.decimal.lo = lo;
2025 v->value.decimal.mi = lo;
2026 v->value.decimal.hi = lo;
2027 v->value.decimal.sign = sign;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002028 v->value.decimal.frac = 0;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002029 v->value.decimal.total = cur - value;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002030 *val = v;
2031 }
2032 }
2033 goto return0;
2034 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002035 case XML_SCHEMAS_LONG:
2036 case XML_SCHEMAS_BYTE:
2037 case XML_SCHEMAS_SHORT:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002038 case XML_SCHEMAS_INT: {
2039 const xmlChar *cur = value;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002040 unsigned long lo, mi, hi;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002041 int total = 0;
2042 int sign = 0;
2043 if (cur == NULL)
2044 goto return1;
2045 if (*cur == '-') {
2046 sign = 1;
2047 cur++;
2048 } else if (*cur == '+')
2049 cur++;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002050 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2051 if (ret <= 0)
2052 goto return1;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002053 if (*cur != 0)
2054 goto return1;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002055 if (type->flags == XML_SCHEMAS_LONG) {
2056 if (hi >= 922) {
2057 if (hi > 922)
2058 goto return1;
2059 if (mi >= 33720368) {
2060 if (mi > 33720368)
2061 goto return1;
2062 if ((sign == 0) && (lo > 54775807))
2063 goto return1;
2064 if ((sign == 1) && (lo > 54775808))
2065 goto return1;
2066 }
2067 }
2068 } else if (type->flags == XML_SCHEMAS_INT) {
2069 if (hi != 0)
2070 goto return1;
2071 if (mi >= 21) {
2072 if (mi > 21)
2073 goto return1;
2074 if ((sign == 0) && (lo > 47483647))
2075 goto return1;
2076 if ((sign == 1) && (lo > 47483648))
2077 goto return1;
2078 }
2079 } else if (type->flags == XML_SCHEMAS_SHORT) {
2080 if ((mi != 0) || (hi != 0))
2081 goto return1;
2082 if ((sign == 1) && (lo > 32768))
2083 goto return1;
2084 if ((sign == 0) && (lo > 32767))
2085 goto return1;
2086 } else if (type->flags == XML_SCHEMAS_BYTE) {
2087 if ((mi != 0) || (hi != 0))
2088 goto return1;
2089 if ((sign == 1) && (lo > 128))
2090 goto return1;
2091 if ((sign == 0) && (lo > 127))
2092 goto return1;
2093 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002094 if (val != NULL) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002095 v = xmlSchemaNewValue(type->flags);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002096 if (v != NULL) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002097 v->value.decimal.lo = lo;
2098 v->value.decimal.mi = lo;
2099 v->value.decimal.hi = lo;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002100 v->value.decimal.sign = sign;
2101 v->value.decimal.frac = 0;
2102 v->value.decimal.total = total;
2103 *val = v;
2104 }
2105 }
2106 goto return0;
2107 }
2108 case XML_SCHEMAS_UINT:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002109 case XML_SCHEMAS_ULONG:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002110 case XML_SCHEMAS_USHORT:
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002111 case XML_SCHEMAS_UBYTE: {
2112 const xmlChar *cur = value;
2113 unsigned long lo, mi, hi;
2114 int total = 0;
2115 if (cur == NULL)
2116 goto return1;
2117 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2118 if (ret <= 0)
2119 goto return1;
2120 if (*cur != 0)
2121 goto return1;
2122 if (type->flags == XML_SCHEMAS_ULONG) {
2123 if (hi >= 1844) {
2124 if (hi > 1844)
2125 goto return1;
2126 if (mi >= 67440737) {
2127 if (mi > 67440737)
2128 goto return1;
2129 if (lo > 9551615)
2130 goto return1;
2131 }
2132 }
2133 } else if (type->flags == XML_SCHEMAS_UINT) {
2134 if (hi != 0)
2135 goto return1;
2136 if (mi >= 42) {
2137 if (mi > 42)
2138 goto return1;
2139 if (lo > 94967295)
2140 goto return1;
2141 }
2142 } else if (type->flags == XML_SCHEMAS_USHORT) {
2143 if ((mi != 0) || (hi != 0))
2144 goto return1;
2145 if (lo > 65535)
2146 goto return1;
2147 } else if (type->flags == XML_SCHEMAS_UBYTE) {
2148 if ((mi != 0) || (hi != 0))
2149 goto return1;
2150 if (lo > 255)
2151 goto return1;
2152 }
2153 if (val != NULL) {
2154 v = xmlSchemaNewValue(type->flags);
2155 if (v != NULL) {
2156 v->value.decimal.lo = lo;
2157 v->value.decimal.mi = mi;
2158 v->value.decimal.hi = hi;
2159 v->value.decimal.sign = 0;
2160 v->value.decimal.frac = 0;
2161 v->value.decimal.total = total;
2162 *val = v;
2163 }
2164 }
2165 goto return0;
2166 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002167 }
2168
2169done:
2170 if (norm != NULL) xmlFree(norm);
2171 return(ret);
2172return3:
2173 if (norm != NULL) xmlFree(norm);
2174 return(3);
2175return1:
2176 if (norm != NULL) xmlFree(norm);
2177 return(1);
2178return0:
2179 if (norm != NULL) xmlFree(norm);
2180 return(0);
2181error:
2182 if (norm != NULL) xmlFree(norm);
2183 return(-1);
2184}
2185
2186/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002187 * xmlSchemaValPredefTypeNode:
Daniel Veillard4255d502002-04-16 15:50:10 +00002188 * @type: the predefined type
2189 * @value: the value to check
2190 * @val: the return computed value
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002191 * @node: the node containing the value
Daniel Veillard4255d502002-04-16 15:50:10 +00002192 *
2193 * Check that a value conforms to the lexical space of the predefined type.
2194 * if true a value is computed and returned in @val.
2195 *
2196 * Returns 0 if this validates, a positive error code number otherwise
2197 * and -1 in case of internal or API error.
2198 */
2199int
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002200xmlSchemaValPredefTypeNode(xmlSchemaTypePtr type, const xmlChar *value,
2201 xmlSchemaValPtr *val, xmlNodePtr node) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002202 return(xmlSchemaValAtomicType(type, value, val, node, 0));
Daniel Veillard4255d502002-04-16 15:50:10 +00002203}
2204
2205/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002206 * xmlSchemaValidatePredefinedType:
2207 * @type: the predefined type
2208 * @value: the value to check
2209 * @val: the return computed value
2210 *
2211 * Check that a value conforms to the lexical space of the predefined type.
2212 * if true a value is computed and returned in @val.
2213 *
2214 * Returns 0 if this validates, a positive error code number otherwise
2215 * and -1 in case of internal or API error.
2216 */
2217int
2218xmlSchemaValidatePredefinedType(xmlSchemaTypePtr type, const xmlChar *value,
2219 xmlSchemaValPtr *val) {
2220 return(xmlSchemaValPredefTypeNode(type, value, val, NULL));
2221}
2222
2223/**
Daniel Veillard4255d502002-04-16 15:50:10 +00002224 * xmlSchemaCompareDecimals:
2225 * @x: a first decimal value
2226 * @y: a second decimal value
2227 *
2228 * Compare 2 decimals
2229 *
2230 * Returns -1 if x < y, 0 if x == y, 1 if x > y and -2 in case of error
2231 */
2232static int
2233xmlSchemaCompareDecimals(xmlSchemaValPtr x, xmlSchemaValPtr y)
2234{
2235 xmlSchemaValPtr swp;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002236 int order = 1, p;
Daniel Veillard4255d502002-04-16 15:50:10 +00002237 unsigned long tmp;
2238
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002239 if ((x->value.decimal.sign) &&
2240 ((x->value.decimal.lo != 0) ||
2241 (x->value.decimal.mi != 0) ||
2242 (x->value.decimal.hi != 0))) {
2243 if ((y->value.decimal.sign) &&
2244 ((y->value.decimal.lo != 0) ||
2245 (y->value.decimal.mi != 0) ||
2246 (y->value.decimal.hi != 0)))
Daniel Veillard80b19092003-03-28 13:29:53 +00002247 order = -1;
2248 else
2249 return (-1);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002250 } else if ((y->value.decimal.sign) &&
2251 ((y->value.decimal.lo != 0) ||
2252 (y->value.decimal.mi != 0) ||
2253 (y->value.decimal.hi != 0))) {
Daniel Veillard4255d502002-04-16 15:50:10 +00002254 return (1);
Daniel Veillard80b19092003-03-28 13:29:53 +00002255 }
Daniel Veillard4255d502002-04-16 15:50:10 +00002256 if (x->value.decimal.frac == y->value.decimal.frac) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002257 if (x->value.decimal.hi < y->value.decimal.hi)
2258 return (-order);
2259 if (x->value.decimal.hi < y->value.decimal.hi)
2260 return (order);
2261 if (x->value.decimal.mi < y->value.decimal.mi)
2262 return (-order);
2263 if (x->value.decimal.mi < y->value.decimal.mi)
2264 return (order);
2265 if (x->value.decimal.lo < y->value.decimal.lo)
Daniel Veillard80b19092003-03-28 13:29:53 +00002266 return (-order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002267 if (x->value.decimal.lo > y->value.decimal.lo)
Daniel Veillard80b19092003-03-28 13:29:53 +00002268 return(order);
2269 return(0);
Daniel Veillard4255d502002-04-16 15:50:10 +00002270 }
2271 if (y->value.decimal.frac > x->value.decimal.frac) {
2272 swp = y;
2273 y = x;
2274 x = swp;
2275 order = -order;
2276 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002277 p = powten[x->value.decimal.frac - y->value.decimal.frac];
2278 tmp = x->value.decimal.lo / p;
2279 if (tmp > y->value.decimal.lo)
Daniel Veillard4255d502002-04-16 15:50:10 +00002280 return (order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002281 if (tmp < y->value.decimal.lo)
Daniel Veillard4255d502002-04-16 15:50:10 +00002282 return (-order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002283 tmp = y->value.decimal.lo * p;
2284 if (x->value.decimal.lo < tmp)
Daniel Veillard4255d502002-04-16 15:50:10 +00002285 return (-order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002286 if (x->value.decimal.lo == tmp)
Daniel Veillard4255d502002-04-16 15:50:10 +00002287 return (0);
2288 return (order);
2289}
2290
2291/**
Daniel Veillard070803b2002-05-03 07:29:38 +00002292 * xmlSchemaCompareDurations:
2293 * @x: a first duration value
2294 * @y: a second duration value
2295 *
2296 * Compare 2 durations
2297 *
2298 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
2299 * case of error
2300 */
2301static int
2302xmlSchemaCompareDurations(xmlSchemaValPtr x, xmlSchemaValPtr y)
2303{
2304 long carry, mon, day;
2305 double sec;
Daniel Veillard80b19092003-03-28 13:29:53 +00002306 int invert = 1;
2307 long xmon, xday, myear, minday, maxday;
Daniel Veillard070803b2002-05-03 07:29:38 +00002308 static const long dayRange [2][12] = {
2309 { 0, 28, 59, 89, 120, 150, 181, 212, 242, 273, 303, 334, },
2310 { 0, 31, 62, 92, 123, 153, 184, 215, 245, 276, 306, 337} };
2311
2312 if ((x == NULL) || (y == NULL))
Daniel Veillard5a872412002-05-22 06:40:27 +00002313 return -2;
Daniel Veillard070803b2002-05-03 07:29:38 +00002314
2315 /* months */
2316 mon = x->value.dur.mon - y->value.dur.mon;
2317
2318 /* seconds */
2319 sec = x->value.dur.sec - y->value.dur.sec;
2320 carry = (long)sec / SECS_PER_DAY;
2321 sec -= (double)(carry * SECS_PER_DAY);
2322
2323 /* days */
2324 day = x->value.dur.day - y->value.dur.day + carry;
2325
2326 /* easy test */
2327 if (mon == 0) {
2328 if (day == 0)
2329 if (sec == 0.0)
2330 return 0;
2331 else if (sec < 0.0)
2332 return -1;
2333 else
2334 return 1;
2335 else if (day < 0)
2336 return -1;
2337 else
2338 return 1;
2339 }
2340
2341 if (mon > 0) {
2342 if ((day >= 0) && (sec >= 0.0))
2343 return 1;
2344 else {
2345 xmon = mon;
2346 xday = -day;
2347 }
2348 } else if ((day <= 0) && (sec <= 0.0)) {
2349 return -1;
2350 } else {
Daniel Veillard80b19092003-03-28 13:29:53 +00002351 invert = -1;
Daniel Veillard070803b2002-05-03 07:29:38 +00002352 xmon = -mon;
2353 xday = day;
2354 }
2355
2356 myear = xmon / 12;
Daniel Veillard80b19092003-03-28 13:29:53 +00002357 if (myear == 0) {
2358 minday = 0;
2359 maxday = 0;
2360 } else {
2361 maxday = 366 * ((myear + 3) / 4) +
2362 365 * ((myear - 1) % 4);
2363 minday = maxday - 1;
2364 }
2365
Daniel Veillard070803b2002-05-03 07:29:38 +00002366 xmon = xmon % 12;
2367 minday += dayRange[0][xmon];
2368 maxday += dayRange[1][xmon];
2369
Daniel Veillard80b19092003-03-28 13:29:53 +00002370 if ((maxday == minday) && (maxday == xday))
2371 return(0); /* can this really happen ? */
Daniel Veillard070803b2002-05-03 07:29:38 +00002372 if (maxday < xday)
Daniel Veillard80b19092003-03-28 13:29:53 +00002373 return(-invert);
2374 if (minday > xday)
2375 return(invert);
Daniel Veillard070803b2002-05-03 07:29:38 +00002376
2377 /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00002378 return 2;
2379}
2380
2381/*
2382 * macros for adding date/times and durations
2383 */
2384#define FQUOTIENT(a,b) (floor(((double)a/(double)b)))
2385#define MODULO(a,b) (a - FQUOTIENT(a,b) * b)
2386#define FQUOTIENT_RANGE(a,low,high) (FQUOTIENT((a-low),(high-low)))
2387#define MODULO_RANGE(a,low,high) ((MODULO((a-low),(high-low)))+low)
2388
2389/**
2390 * _xmlSchemaDateAdd:
2391 * @dt: an #xmlSchemaValPtr
2392 * @dur: an #xmlSchemaValPtr of type #XS_DURATION
2393 *
2394 * Compute a new date/time from @dt and @dur. This function assumes @dt
2395 * is either #XML_SCHEMAS_DATETIME, #XML_SCHEMAS_DATE, #XML_SCHEMAS_GYEARMONTH,
2396 * or #XML_SCHEMAS_GYEAR.
2397 *
2398 * Returns date/time pointer or NULL.
2399 */
2400static xmlSchemaValPtr
2401_xmlSchemaDateAdd (xmlSchemaValPtr dt, xmlSchemaValPtr dur)
2402{
2403 xmlSchemaValPtr ret;
2404 long carry, tempdays, temp;
2405 xmlSchemaValDatePtr r, d;
2406 xmlSchemaValDurationPtr u;
2407
2408 if ((dt == NULL) || (dur == NULL))
2409 return NULL;
2410
2411 ret = xmlSchemaNewValue(dt->type);
2412 if (ret == NULL)
2413 return NULL;
2414
2415 r = &(ret->value.date);
2416 d = &(dt->value.date);
2417 u = &(dur->value.dur);
2418
2419 /* normalization */
2420 if (d->mon == 0)
2421 d->mon = 1;
2422
2423 /* normalize for time zone offset */
2424 u->sec -= (d->tzo * 60);
2425 d->tzo = 0;
2426
2427 /* normalization */
2428 if (d->day == 0)
2429 d->day = 1;
2430
2431 /* month */
2432 carry = d->mon + u->mon;
2433 r->mon = MODULO_RANGE(carry, 1, 13);
2434 carry = FQUOTIENT_RANGE(carry, 1, 13);
2435
2436 /* year (may be modified later) */
2437 r->year = d->year + carry;
2438 if (r->year == 0) {
2439 if (d->year > 0)
2440 r->year--;
2441 else
2442 r->year++;
2443 }
2444
2445 /* time zone */
2446 r->tzo = d->tzo;
2447 r->tz_flag = d->tz_flag;
2448
2449 /* seconds */
2450 r->sec = d->sec + u->sec;
2451 carry = FQUOTIENT((long)r->sec, 60);
2452 if (r->sec != 0.0) {
2453 r->sec = MODULO(r->sec, 60.0);
2454 }
2455
2456 /* minute */
2457 carry += d->min;
2458 r->min = MODULO(carry, 60);
2459 carry = FQUOTIENT(carry, 60);
2460
2461 /* hours */
2462 carry += d->hour;
2463 r->hour = MODULO(carry, 24);
2464 carry = FQUOTIENT(carry, 24);
2465
2466 /*
2467 * days
2468 * Note we use tempdays because the temporary values may need more
2469 * than 5 bits
2470 */
2471 if ((VALID_YEAR(r->year)) && (VALID_MONTH(r->mon)) &&
2472 (d->day > MAX_DAYINMONTH(r->year, r->mon)))
2473 tempdays = MAX_DAYINMONTH(r->year, r->mon);
2474 else if (d->day < 1)
2475 tempdays = 1;
2476 else
2477 tempdays = d->day;
2478
2479 tempdays += u->day + carry;
2480
2481 while (1) {
2482 if (tempdays < 1) {
2483 long tmon = MODULO_RANGE(r->mon-1, 1, 13);
2484 long tyr = r->year + FQUOTIENT_RANGE(r->mon-1, 1, 13);
2485 if (tyr == 0)
2486 tyr--;
2487 tempdays += MAX_DAYINMONTH(tyr, tmon);
2488 carry = -1;
2489 } else if (tempdays > MAX_DAYINMONTH(r->year, r->mon)) {
2490 tempdays = tempdays - MAX_DAYINMONTH(r->year, r->mon);
2491 carry = 1;
2492 } else
2493 break;
2494
2495 temp = r->mon + carry;
2496 r->mon = MODULO_RANGE(temp, 1, 13);
2497 r->year = r->year + FQUOTIENT_RANGE(temp, 1, 13);
2498 if (r->year == 0) {
2499 if (temp < 1)
2500 r->year--;
2501 else
2502 r->year++;
2503 }
2504 }
2505
2506 r->day = tempdays;
2507
2508 /*
2509 * adjust the date/time type to the date values
2510 */
2511 if (ret->type != XML_SCHEMAS_DATETIME) {
2512 if ((r->hour) || (r->min) || (r->sec))
2513 ret->type = XML_SCHEMAS_DATETIME;
2514 else if (ret->type != XML_SCHEMAS_DATE) {
2515 if ((r->mon != 1) && (r->day != 1))
2516 ret->type = XML_SCHEMAS_DATE;
2517 else if ((ret->type != XML_SCHEMAS_GYEARMONTH) && (r->mon != 1))
2518 ret->type = XML_SCHEMAS_GYEARMONTH;
2519 }
2520 }
2521
2522 return ret;
2523}
2524
2525/**
2526 * xmlSchemaDupVal:
2527 * @v: value to duplicate
2528 *
2529 * returns a duplicated value.
2530 */
2531static xmlSchemaValPtr
2532xmlSchemaDupVal (xmlSchemaValPtr v)
2533{
2534 xmlSchemaValPtr ret = xmlSchemaNewValue(v->type);
2535 if (ret == NULL)
2536 return ret;
2537
2538 memcpy(ret, v, sizeof(xmlSchemaVal));
2539 return ret;
2540}
2541
2542/**
2543 * xmlSchemaDateNormalize:
2544 * @dt: an #xmlSchemaValPtr
2545 *
2546 * Normalize @dt to GMT time.
2547 *
2548 */
2549static xmlSchemaValPtr
2550xmlSchemaDateNormalize (xmlSchemaValPtr dt, double offset)
2551{
2552 xmlSchemaValPtr dur, ret;
2553
2554 if (dt == NULL)
2555 return NULL;
2556
2557 if (((dt->type != XML_SCHEMAS_TIME) &&
2558 (dt->type != XML_SCHEMAS_DATETIME)) || (dt->value.date.tzo == 0))
2559 return xmlSchemaDupVal(dt);
2560
2561 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
2562 if (dur == NULL)
2563 return NULL;
2564
2565 dur->value.date.sec -= offset;
2566
2567 ret = _xmlSchemaDateAdd(dt, dur);
2568 if (ret == NULL)
2569 return NULL;
2570
2571 xmlSchemaFreeValue(dur);
2572
2573 /* ret->value.date.tzo = 0; */
2574 return ret;
2575}
2576
2577/**
2578 * _xmlSchemaDateCastYMToDays:
2579 * @dt: an #xmlSchemaValPtr
2580 *
2581 * Convert mon and year of @dt to total number of days. Take the
2582 * number of years since (or before) 1 AD and add the number of leap
2583 * years. This is a function because negative
2584 * years must be handled a little differently and there is no zero year.
2585 *
2586 * Returns number of days.
2587 */
2588static long
2589_xmlSchemaDateCastYMToDays (const xmlSchemaValPtr dt)
2590{
2591 long ret;
2592
2593 if (dt->value.date.year < 0)
2594 ret = (dt->value.date.year * 365) +
2595 (((dt->value.date.year+1)/4)-((dt->value.date.year+1)/100)+
2596 ((dt->value.date.year+1)/400)) +
2597 DAY_IN_YEAR(0, dt->value.date.mon, dt->value.date.year);
2598 else
2599 ret = ((dt->value.date.year-1) * 365) +
2600 (((dt->value.date.year-1)/4)-((dt->value.date.year-1)/100)+
2601 ((dt->value.date.year-1)/400)) +
2602 DAY_IN_YEAR(0, dt->value.date.mon, dt->value.date.year);
2603
2604 return ret;
2605}
2606
2607/**
2608 * TIME_TO_NUMBER:
2609 * @dt: an #xmlSchemaValPtr
2610 *
2611 * Calculates the number of seconds in the time portion of @dt.
2612 *
2613 * Returns seconds.
2614 */
2615#define TIME_TO_NUMBER(dt) \
2616 ((double)((dt->value.date.hour * SECS_PER_HOUR) + \
Daniel Veillardb3721c22003-03-31 11:22:25 +00002617 (dt->value.date.min * SECS_PER_MIN) + \
2618 (dt->value.date.tzo * SECS_PER_MIN)) + \
2619 dt->value.date.sec)
Daniel Veillard5a872412002-05-22 06:40:27 +00002620
2621/**
2622 * xmlSchemaCompareDates:
2623 * @x: a first date/time value
2624 * @y: a second date/time value
2625 *
2626 * Compare 2 date/times
2627 *
2628 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
2629 * case of error
2630 */
2631static int
2632xmlSchemaCompareDates (xmlSchemaValPtr x, xmlSchemaValPtr y)
2633{
2634 unsigned char xmask, ymask, xor_mask, and_mask;
2635 xmlSchemaValPtr p1, p2, q1, q2;
2636 long p1d, p2d, q1d, q2d;
2637
2638 if ((x == NULL) || (y == NULL))
2639 return -2;
2640
2641 if (x->value.date.tz_flag) {
2642
2643 if (!y->value.date.tz_flag) {
2644 p1 = xmlSchemaDateNormalize(x, 0);
2645 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
2646 /* normalize y + 14:00 */
2647 q1 = xmlSchemaDateNormalize(y, (14 * SECS_PER_HOUR));
2648
2649 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002650 if (p1d < q1d) {
2651 xmlSchemaFreeValue(p1);
2652 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002653 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002654 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00002655 double sec;
2656
2657 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00002658 if (sec < 0.0) {
2659 xmlSchemaFreeValue(p1);
2660 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002661 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002662 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00002663 /* normalize y - 14:00 */
2664 q2 = xmlSchemaDateNormalize(y, -(14 * SECS_PER_HOUR));
2665 q2d = _xmlSchemaDateCastYMToDays(q2) + q2->value.date.day;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002666 xmlSchemaFreeValue(p1);
2667 xmlSchemaFreeValue(q1);
2668 xmlSchemaFreeValue(q2);
Daniel Veillard5a872412002-05-22 06:40:27 +00002669 if (p1d > q2d)
2670 return 1;
2671 else if (p1d == q2d) {
2672 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q2);
2673 if (sec > 0.0)
2674 return 1;
2675 else
2676 return 2; /* indeterminate */
2677 }
2678 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00002679 } else {
2680 xmlSchemaFreeValue(p1);
2681 xmlSchemaFreeValue(q1);
2682 }
Daniel Veillard5a872412002-05-22 06:40:27 +00002683 }
2684 } else if (y->value.date.tz_flag) {
2685 q1 = xmlSchemaDateNormalize(y, 0);
2686 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
2687
2688 /* normalize x - 14:00 */
2689 p1 = xmlSchemaDateNormalize(x, -(14 * SECS_PER_HOUR));
2690 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
2691
Daniel Veillardfdc91562002-07-01 21:52:03 +00002692 if (p1d < q1d) {
2693 xmlSchemaFreeValue(p1);
2694 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002695 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002696 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00002697 double sec;
2698
2699 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00002700 if (sec < 0.0) {
2701 xmlSchemaFreeValue(p1);
2702 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002703 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002704 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00002705 /* normalize x + 14:00 */
2706 p2 = xmlSchemaDateNormalize(x, (14 * SECS_PER_HOUR));
2707 p2d = _xmlSchemaDateCastYMToDays(p2) + p2->value.date.day;
2708
Daniel Veillard6560a422003-03-27 21:25:38 +00002709 if (p2d > q1d) {
2710 xmlSchemaFreeValue(p1);
2711 xmlSchemaFreeValue(q1);
2712 xmlSchemaFreeValue(p2);
Daniel Veillard5a872412002-05-22 06:40:27 +00002713 return 1;
Daniel Veillard6560a422003-03-27 21:25:38 +00002714 } else if (p2d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00002715 sec = TIME_TO_NUMBER(p2) - TIME_TO_NUMBER(q1);
Daniel Veillard6560a422003-03-27 21:25:38 +00002716 xmlSchemaFreeValue(p1);
2717 xmlSchemaFreeValue(q1);
2718 xmlSchemaFreeValue(p2);
Daniel Veillard5a872412002-05-22 06:40:27 +00002719 if (sec > 0.0)
2720 return 1;
2721 else
2722 return 2; /* indeterminate */
2723 }
Daniel Veillard6560a422003-03-27 21:25:38 +00002724 xmlSchemaFreeValue(p1);
2725 xmlSchemaFreeValue(q1);
2726 xmlSchemaFreeValue(p2);
Daniel Veillard5a872412002-05-22 06:40:27 +00002727 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00002728 } else {
2729 xmlSchemaFreeValue(p1);
2730 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002731 }
2732 }
2733
2734 /*
2735 * if the same type then calculate the difference
2736 */
2737 if (x->type == y->type) {
2738 q1 = xmlSchemaDateNormalize(y, 0);
2739 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
2740
2741 p1 = xmlSchemaDateNormalize(x, 0);
2742 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
2743
Daniel Veillardfdc91562002-07-01 21:52:03 +00002744 if (p1d < q1d) {
2745 xmlSchemaFreeValue(p1);
2746 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002747 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002748 } else if (p1d > q1d) {
2749 xmlSchemaFreeValue(p1);
2750 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002751 return 1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002752 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00002753 double sec;
2754
2755 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00002756 xmlSchemaFreeValue(p1);
2757 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002758 if (sec < 0.0)
2759 return -1;
2760 else if (sec > 0.0)
2761 return 1;
2762
2763 }
2764 return 0;
2765 }
2766
2767 switch (x->type) {
2768 case XML_SCHEMAS_DATETIME:
2769 xmask = 0xf;
2770 break;
2771 case XML_SCHEMAS_DATE:
2772 xmask = 0x7;
2773 break;
2774 case XML_SCHEMAS_GYEAR:
2775 xmask = 0x1;
2776 break;
2777 case XML_SCHEMAS_GMONTH:
2778 xmask = 0x2;
2779 break;
2780 case XML_SCHEMAS_GDAY:
2781 xmask = 0x3;
2782 break;
2783 case XML_SCHEMAS_GYEARMONTH:
2784 xmask = 0x3;
2785 break;
2786 case XML_SCHEMAS_GMONTHDAY:
2787 xmask = 0x6;
2788 break;
2789 case XML_SCHEMAS_TIME:
2790 xmask = 0x8;
2791 break;
2792 default:
2793 xmask = 0;
2794 break;
2795 }
2796
2797 switch (y->type) {
2798 case XML_SCHEMAS_DATETIME:
2799 ymask = 0xf;
2800 break;
2801 case XML_SCHEMAS_DATE:
2802 ymask = 0x7;
2803 break;
2804 case XML_SCHEMAS_GYEAR:
2805 ymask = 0x1;
2806 break;
2807 case XML_SCHEMAS_GMONTH:
2808 ymask = 0x2;
2809 break;
2810 case XML_SCHEMAS_GDAY:
2811 ymask = 0x3;
2812 break;
2813 case XML_SCHEMAS_GYEARMONTH:
2814 ymask = 0x3;
2815 break;
2816 case XML_SCHEMAS_GMONTHDAY:
2817 ymask = 0x6;
2818 break;
2819 case XML_SCHEMAS_TIME:
2820 ymask = 0x8;
2821 break;
2822 default:
2823 ymask = 0;
2824 break;
2825 }
2826
2827 xor_mask = xmask ^ ymask; /* mark type differences */
2828 and_mask = xmask & ymask; /* mark field specification */
2829
2830 /* year */
2831 if (xor_mask & 1)
2832 return 2; /* indeterminate */
2833 else if (and_mask & 1) {
2834 if (x->value.date.year < y->value.date.year)
2835 return -1;
2836 else if (x->value.date.year > y->value.date.year)
2837 return 1;
2838 }
2839
2840 /* month */
2841 if (xor_mask & 2)
2842 return 2; /* indeterminate */
2843 else if (and_mask & 2) {
2844 if (x->value.date.mon < y->value.date.mon)
2845 return -1;
2846 else if (x->value.date.mon > y->value.date.mon)
2847 return 1;
2848 }
2849
2850 /* day */
2851 if (xor_mask & 4)
2852 return 2; /* indeterminate */
2853 else if (and_mask & 4) {
2854 if (x->value.date.day < y->value.date.day)
2855 return -1;
2856 else if (x->value.date.day > y->value.date.day)
2857 return 1;
2858 }
2859
2860 /* time */
2861 if (xor_mask & 8)
2862 return 2; /* indeterminate */
2863 else if (and_mask & 8) {
2864 if (x->value.date.hour < y->value.date.hour)
2865 return -1;
2866 else if (x->value.date.hour > y->value.date.hour)
2867 return 1;
2868 else if (x->value.date.min < y->value.date.min)
2869 return -1;
2870 else if (x->value.date.min > y->value.date.min)
2871 return 1;
2872 else if (x->value.date.sec < y->value.date.sec)
2873 return -1;
2874 else if (x->value.date.sec > y->value.date.sec)
2875 return 1;
2876 }
2877
Daniel Veillard070803b2002-05-03 07:29:38 +00002878 return 0;
2879}
2880
2881/**
Daniel Veillardc4c21552003-03-29 10:53:38 +00002882 * xmlSchemaCompareNormStrings:
2883 * @x: a first string value
2884 * @y: a second string value
2885 *
2886 * Compare 2 string for their normalized values.
2887 *
2888 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
2889 * case of error
2890 */
2891static int
2892xmlSchemaCompareNormStrings(xmlSchemaValPtr x, xmlSchemaValPtr y) {
2893 const xmlChar *utf1;
2894 const xmlChar *utf2;
2895 int tmp;
2896
2897 if ((x == NULL) || (y == NULL))
2898 return(-2);
2899 utf1 = x->value.str;
2900 utf2 = y->value.str;
2901
2902 while (IS_BLANK(*utf1)) utf1++;
2903 while (IS_BLANK(*utf2)) utf2++;
2904 while ((*utf1 != 0) && (*utf2 != 0)) {
2905 if (IS_BLANK(*utf1)) {
2906 if (!IS_BLANK(*utf2)) {
2907 tmp = *utf1 - *utf2;
2908 return(tmp);
2909 }
2910 while (IS_BLANK(*utf1)) utf1++;
2911 while (IS_BLANK(*utf2)) utf2++;
2912 } else {
2913 tmp = *utf1++ - *utf2++;
2914 if (tmp < 0)
2915 return(-1);
2916 if (tmp > 0)
2917 return(1);
2918 }
2919 }
2920 if (*utf1 != 0) {
2921 while (IS_BLANK(*utf1)) utf1++;
2922 if (*utf1 != 0)
2923 return(1);
2924 }
2925 if (*utf2 != 0) {
2926 while (IS_BLANK(*utf2)) utf2++;
2927 if (*utf2 != 0)
2928 return(-1);
2929 }
2930 return(0);
2931}
2932
2933/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002934 * xmlSchemaCompareFloats:
2935 * @x: a first float or double value
2936 * @y: a second float or double value
2937 *
2938 * Compare 2 values
2939 *
2940 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
2941 * case of error
2942 */
2943static int
2944xmlSchemaCompareFloats(xmlSchemaValPtr x, xmlSchemaValPtr y) {
2945 double d1, d2;
2946
2947 if ((x == NULL) || (y == NULL))
2948 return(-2);
2949
2950 /*
2951 * Cast everything to doubles.
2952 */
2953 if (x->type == XML_SCHEMAS_DOUBLE)
2954 d1 = x->value.d;
2955 else if (x->type == XML_SCHEMAS_FLOAT)
2956 d1 = x->value.f;
2957 else
2958 return(-2);
2959
2960 if (y->type == XML_SCHEMAS_DOUBLE)
2961 d2 = y->value.d;
2962 else if (y->type == XML_SCHEMAS_FLOAT)
2963 d2 = y->value.f;
2964 else
2965 return(-2);
2966
2967 /*
2968 * Check for special cases.
2969 */
2970 if (xmlXPathIsNaN(d1)) {
2971 if (xmlXPathIsNaN(d2))
2972 return(0);
2973 return(1);
2974 }
2975 if (xmlXPathIsNaN(d2))
2976 return(-1);
2977 if (d1 == xmlXPathPINF) {
2978 if (d2 == xmlXPathPINF)
2979 return(0);
2980 return(1);
2981 }
2982 if (d2 == xmlXPathPINF)
2983 return(-1);
2984 if (d1 == xmlXPathNINF) {
2985 if (d2 == xmlXPathNINF)
2986 return(0);
2987 return(-1);
2988 }
2989 if (d2 == xmlXPathNINF)
2990 return(1);
2991
2992 /*
2993 * basic tests, the last one we should have equality, but
2994 * portability is more important than speed and handling
2995 * NaN or Inf in a portable way is always a challenge, so ...
2996 */
2997 if (d1 < d2)
2998 return(-1);
2999 if (d1 > d2)
3000 return(1);
3001 if (d1 == d2)
3002 return(0);
3003 return(2);
3004}
3005
3006/**
Daniel Veillard4255d502002-04-16 15:50:10 +00003007 * xmlSchemaCompareValues:
3008 * @x: a first value
3009 * @y: a second value
3010 *
3011 * Compare 2 values
3012 *
Daniel Veillard5a872412002-05-22 06:40:27 +00003013 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3014 * case of error
Daniel Veillard4255d502002-04-16 15:50:10 +00003015 */
Daniel Veillard80b19092003-03-28 13:29:53 +00003016int
Daniel Veillard4255d502002-04-16 15:50:10 +00003017xmlSchemaCompareValues(xmlSchemaValPtr x, xmlSchemaValPtr y) {
3018 if ((x == NULL) || (y == NULL))
3019 return(-2);
3020
3021 switch (x->type) {
Daniel Veillard80b19092003-03-28 13:29:53 +00003022 case XML_SCHEMAS_UNKNOWN:
3023 return(-2);
3024 case XML_SCHEMAS_INTEGER:
3025 case XML_SCHEMAS_NPINTEGER:
3026 case XML_SCHEMAS_NINTEGER:
3027 case XML_SCHEMAS_NNINTEGER:
3028 case XML_SCHEMAS_PINTEGER:
3029 case XML_SCHEMAS_INT:
3030 case XML_SCHEMAS_UINT:
3031 case XML_SCHEMAS_LONG:
3032 case XML_SCHEMAS_ULONG:
3033 case XML_SCHEMAS_SHORT:
3034 case XML_SCHEMAS_USHORT:
3035 case XML_SCHEMAS_BYTE:
3036 case XML_SCHEMAS_UBYTE:
Daniel Veillard4255d502002-04-16 15:50:10 +00003037 case XML_SCHEMAS_DECIMAL:
Daniel Veillard80b19092003-03-28 13:29:53 +00003038 if (y->type == x->type)
3039 return(xmlSchemaCompareDecimals(x, y));
3040 if ((y->type == XML_SCHEMAS_DECIMAL) ||
3041 (y->type == XML_SCHEMAS_INTEGER) ||
3042 (y->type == XML_SCHEMAS_NPINTEGER) ||
3043 (y->type == XML_SCHEMAS_NINTEGER) ||
3044 (y->type == XML_SCHEMAS_NNINTEGER) ||
3045 (y->type == XML_SCHEMAS_PINTEGER) ||
3046 (y->type == XML_SCHEMAS_INT) ||
3047 (y->type == XML_SCHEMAS_UINT) ||
3048 (y->type == XML_SCHEMAS_LONG) ||
3049 (y->type == XML_SCHEMAS_ULONG) ||
3050 (y->type == XML_SCHEMAS_SHORT) ||
3051 (y->type == XML_SCHEMAS_USHORT) ||
3052 (y->type == XML_SCHEMAS_BYTE) ||
3053 (y->type == XML_SCHEMAS_UBYTE))
Daniel Veillard4255d502002-04-16 15:50:10 +00003054 return(xmlSchemaCompareDecimals(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00003055 return(-2);
Daniel Veillard070803b2002-05-03 07:29:38 +00003056 case XML_SCHEMAS_DURATION:
3057 if (y->type == XML_SCHEMAS_DURATION)
3058 return(xmlSchemaCompareDurations(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00003059 return(-2);
3060 case XML_SCHEMAS_TIME:
3061 case XML_SCHEMAS_GDAY:
3062 case XML_SCHEMAS_GMONTH:
3063 case XML_SCHEMAS_GMONTHDAY:
3064 case XML_SCHEMAS_GYEAR:
3065 case XML_SCHEMAS_GYEARMONTH:
3066 case XML_SCHEMAS_DATE:
3067 case XML_SCHEMAS_DATETIME:
3068 if ((y->type == XML_SCHEMAS_DATETIME) ||
3069 (y->type == XML_SCHEMAS_TIME) ||
3070 (y->type == XML_SCHEMAS_GDAY) ||
3071 (y->type == XML_SCHEMAS_GMONTH) ||
3072 (y->type == XML_SCHEMAS_GMONTHDAY) ||
3073 (y->type == XML_SCHEMAS_GYEAR) ||
3074 (y->type == XML_SCHEMAS_DATE) ||
3075 (y->type == XML_SCHEMAS_GYEARMONTH))
3076 return (xmlSchemaCompareDates(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00003077 return (-2);
Daniel Veillard80b19092003-03-28 13:29:53 +00003078 case XML_SCHEMAS_NORMSTRING:
Daniel Veillard80b19092003-03-28 13:29:53 +00003079 case XML_SCHEMAS_TOKEN:
3080 case XML_SCHEMAS_LANGUAGE:
3081 case XML_SCHEMAS_NMTOKEN:
Daniel Veillard80b19092003-03-28 13:29:53 +00003082 case XML_SCHEMAS_NAME:
Daniel Veillard80b19092003-03-28 13:29:53 +00003083 case XML_SCHEMAS_NCNAME:
3084 case XML_SCHEMAS_ID:
3085 case XML_SCHEMAS_IDREF:
Daniel Veillard80b19092003-03-28 13:29:53 +00003086 case XML_SCHEMAS_ENTITY:
Daniel Veillard80b19092003-03-28 13:29:53 +00003087 case XML_SCHEMAS_NOTATION:
3088 case XML_SCHEMAS_ANYURI:
Daniel Veillardc4c21552003-03-29 10:53:38 +00003089 if ((y->type == XML_SCHEMAS_NORMSTRING) ||
3090 (y->type == XML_SCHEMAS_TOKEN) ||
3091 (y->type == XML_SCHEMAS_LANGUAGE) ||
3092 (y->type == XML_SCHEMAS_NMTOKEN) ||
3093 (y->type == XML_SCHEMAS_NAME) ||
3094 (y->type == XML_SCHEMAS_QNAME) ||
3095 (y->type == XML_SCHEMAS_NCNAME) ||
3096 (y->type == XML_SCHEMAS_ID) ||
3097 (y->type == XML_SCHEMAS_IDREF) ||
3098 (y->type == XML_SCHEMAS_ENTITY) ||
3099 (y->type == XML_SCHEMAS_NOTATION) ||
3100 (y->type == XML_SCHEMAS_ANYURI))
3101 return (xmlSchemaCompareNormStrings(x, y));
3102 return (-2);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003103 case XML_SCHEMAS_QNAME:
3104 if (y->type == XML_SCHEMAS_QNAME) {
3105 if ((xmlStrEqual(x->value.qname.name, y->value.qname.name)) &&
3106 (xmlStrEqual(x->value.qname.uri, y->value.qname.uri)))
3107 return(0);
3108 return(2);
3109 }
3110 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00003111 case XML_SCHEMAS_FLOAT:
3112 case XML_SCHEMAS_DOUBLE:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003113 if ((y->type == XML_SCHEMAS_FLOAT) ||
3114 (y->type == XML_SCHEMAS_DOUBLE))
3115 return (xmlSchemaCompareFloats(x, y));
3116 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00003117 case XML_SCHEMAS_BOOLEAN:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003118 if (y->type == XML_SCHEMAS_BOOLEAN) {
3119 if (x->value.b == y->value.b)
3120 return(0);
3121 if (x->value.b == 0)
3122 return(-1);
3123 return(1);
3124 }
3125 return (-2);
Daniel Veillard560c2a42003-07-06 21:13:49 +00003126 case XML_SCHEMAS_HEXBINARY:
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00003127 if (y->type == XML_SCHEMAS_HEXBINARY) {
3128 if (x->value.hex.total == y->value.hex.total) {
3129 int ret = xmlStrcmp(x->value.hex.str, y->value.hex.str);
3130 if (ret > 0)
3131 return(1);
3132 else if (ret == 0)
3133 return(0);
3134 }
3135 else if (x->value.hex.total > y->value.hex.total)
3136 return(1);
3137
3138 return(-1);
3139 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00003140 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00003141 case XML_SCHEMAS_STRING:
3142 case XML_SCHEMAS_IDREFS:
3143 case XML_SCHEMAS_ENTITIES:
3144 case XML_SCHEMAS_NMTOKENS:
3145 TODO
3146 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00003147 }
Daniel Veillard5a872412002-05-22 06:40:27 +00003148 return -2;
Daniel Veillard4255d502002-04-16 15:50:10 +00003149}
3150
3151/**
Daniel Veillardc4c21552003-03-29 10:53:38 +00003152 * xmlSchemaNormLen:
3153 * @value: a string
3154 *
3155 * Computes the UTF8 length of the normalized value of the string
3156 *
3157 * Returns the length or -1 in case of error.
3158 */
3159static int
3160xmlSchemaNormLen(const xmlChar *value) {
3161 const xmlChar *utf;
3162 int ret = 0;
3163
3164 if (value == NULL)
3165 return(-1);
3166 utf = value;
3167 while (IS_BLANK(*utf)) utf++;
3168 while (*utf != 0) {
3169 if (utf[0] & 0x80) {
3170 if ((utf[1] & 0xc0) != 0x80)
3171 return(-1);
3172 if ((utf[0] & 0xe0) == 0xe0) {
3173 if ((utf[2] & 0xc0) != 0x80)
3174 return(-1);
3175 if ((utf[0] & 0xf0) == 0xf0) {
3176 if ((utf[0] & 0xf8) != 0xf0 || (utf[3] & 0xc0) != 0x80)
3177 return(-1);
3178 utf += 4;
3179 } else {
3180 utf += 3;
3181 }
3182 } else {
3183 utf += 2;
3184 }
3185 } else if (IS_BLANK(*utf)) {
3186 while (IS_BLANK(*utf)) utf++;
3187 if (*utf == 0)
3188 break;
3189 } else {
3190 utf++;
3191 }
3192 ret++;
3193 }
3194 return(ret);
3195}
3196
3197/**
Daniel Veillard4255d502002-04-16 15:50:10 +00003198 * xmlSchemaValidateFacet:
Daniel Veillard01c13b52002-12-10 15:19:08 +00003199 * @base: the base type
Daniel Veillard4255d502002-04-16 15:50:10 +00003200 * @facet: the facet to check
3201 * @value: the lexical repr of the value to validate
3202 * @val: the precomputed value
3203 *
3204 * Check a value against a facet condition
3205 *
3206 * Returns 0 if the element is schemas valid, a positive error code
3207 * number otherwise and -1 in case of internal or API error.
3208 */
3209int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00003210xmlSchemaValidateFacet(xmlSchemaTypePtr base ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +00003211 xmlSchemaFacetPtr facet,
Daniel Veillard4255d502002-04-16 15:50:10 +00003212 const xmlChar *value, xmlSchemaValPtr val)
3213{
3214 int ret;
3215
3216 switch (facet->type) {
3217 case XML_SCHEMA_FACET_PATTERN:
3218 ret = xmlRegexpExec(facet->regexp, value);
3219 if (ret == 1)
3220 return(0);
3221 if (ret == 0) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003222 /* TODO error code */
Daniel Veillard4255d502002-04-16 15:50:10 +00003223 return(1);
3224 }
3225 return(ret);
3226 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
3227 ret = xmlSchemaCompareValues(val, facet->val);
3228 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003229 /* TODO error code */
Daniel Veillard4255d502002-04-16 15:50:10 +00003230 return(-1);
3231 }
3232 if (ret == -1)
3233 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00003234 /* error code */
Daniel Veillard4255d502002-04-16 15:50:10 +00003235 return(1);
Daniel Veillard070803b2002-05-03 07:29:38 +00003236 case XML_SCHEMA_FACET_MAXINCLUSIVE:
3237 ret = xmlSchemaCompareValues(val, facet->val);
3238 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003239 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00003240 return(-1);
3241 }
3242 if ((ret == -1) || (ret == 0))
3243 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00003244 /* error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00003245 return(1);
3246 case XML_SCHEMA_FACET_MINEXCLUSIVE:
3247 ret = xmlSchemaCompareValues(val, facet->val);
3248 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003249 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00003250 return(-1);
3251 }
3252 if (ret == 1)
3253 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00003254 /* error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00003255 return(1);
3256 case XML_SCHEMA_FACET_MININCLUSIVE:
3257 ret = xmlSchemaCompareValues(val, facet->val);
3258 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003259 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00003260 return(-1);
3261 }
3262 if ((ret == 1) || (ret == 0))
3263 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00003264 /* error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00003265 return(1);
Daniel Veillard8651f532002-04-17 09:06:27 +00003266 case XML_SCHEMA_FACET_WHITESPACE:
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003267 /* TODO whitespaces */
Daniel Veillard8651f532002-04-17 09:06:27 +00003268 return(0);
Daniel Veillard88c58912002-04-23 07:12:20 +00003269 case XML_SCHEMA_FACET_ENUMERATION:
3270 if ((facet->value != NULL) &&
3271 (xmlStrEqual(facet->value, value)))
3272 return(0);
3273 return(1);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003274 case XML_SCHEMA_FACET_LENGTH:
3275 case XML_SCHEMA_FACET_MAXLENGTH:
3276 case XML_SCHEMA_FACET_MINLENGTH: {
3277 unsigned int len = 0;
3278
3279 if ((facet->val == NULL) ||
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003280 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
3281 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003282 (facet->val->value.decimal.frac != 0)) {
3283 return(-1);
3284 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00003285 if ((val != NULL) && (val->type == XML_SCHEMAS_HEXBINARY))
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00003286 len = val->value.hex.total;
Daniel Veillard560c2a42003-07-06 21:13:49 +00003287 else {
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00003288 switch (base->flags) {
Daniel Veillard560c2a42003-07-06 21:13:49 +00003289 case XML_SCHEMAS_IDREF:
3290 case XML_SCHEMAS_NORMSTRING:
3291 case XML_SCHEMAS_TOKEN:
3292 case XML_SCHEMAS_LANGUAGE:
3293 case XML_SCHEMAS_NMTOKEN:
3294 case XML_SCHEMAS_NAME:
3295 case XML_SCHEMAS_NCNAME:
3296 case XML_SCHEMAS_ID:
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00003297 len = xmlSchemaNormLen(value);
3298 break;
Daniel Veillard560c2a42003-07-06 21:13:49 +00003299 case XML_SCHEMAS_STRING:
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00003300 len = xmlUTF8Strlen(value);
3301 break;
Daniel Veillard560c2a42003-07-06 21:13:49 +00003302 default:
3303 TODO
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00003304 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003305 }
3306 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003307 if (len != facet->val->value.decimal.lo)
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003308 return(1);
3309 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003310 if (len < facet->val->value.decimal.lo)
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003311 return(1);
3312 } else {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003313 if (len > facet->val->value.decimal.lo)
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003314 return(1);
3315 }
3316 break;
3317 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00003318 case XML_SCHEMA_FACET_TOTALDIGITS:
3319 case XML_SCHEMA_FACET_FRACTIONDIGITS:
3320
3321 if ((facet->val == NULL) ||
3322 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
3323 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
3324 (facet->val->value.decimal.frac != 0)) {
3325 return(-1);
3326 }
3327 if ((val == NULL) ||
3328 ((val->type != XML_SCHEMAS_DECIMAL) &&
3329 (val->type != XML_SCHEMAS_INTEGER) &&
3330 (val->type != XML_SCHEMAS_NPINTEGER) &&
3331 (val->type != XML_SCHEMAS_NINTEGER) &&
3332 (val->type != XML_SCHEMAS_NNINTEGER) &&
3333 (val->type != XML_SCHEMAS_PINTEGER) &&
3334 (val->type != XML_SCHEMAS_INT) &&
3335 (val->type != XML_SCHEMAS_UINT) &&
3336 (val->type != XML_SCHEMAS_LONG) &&
3337 (val->type != XML_SCHEMAS_ULONG) &&
3338 (val->type != XML_SCHEMAS_SHORT) &&
3339 (val->type != XML_SCHEMAS_USHORT) &&
3340 (val->type != XML_SCHEMAS_BYTE) &&
3341 (val->type != XML_SCHEMAS_UBYTE))) {
3342 return(-1);
3343 }
3344 if (facet->type == XML_SCHEMA_FACET_TOTALDIGITS) {
3345 if (val->value.decimal.total > facet->val->value.decimal.lo)
3346 return(1);
3347
3348 } else if (facet->type == XML_SCHEMA_FACET_FRACTIONDIGITS) {
3349 if (val->value.decimal.frac > facet->val->value.decimal.lo)
3350 return(1);
3351 }
3352 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00003353 default:
3354 TODO
3355 }
3356 return(0);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003357
Daniel Veillard4255d502002-04-16 15:50:10 +00003358}
3359
3360#endif /* LIBXML_SCHEMAS_ENABLED */