blob: 5f55a99bf6b979eb220647f7079ac7d3122abc3e [file] [log] [blame]
Daniel Veillard4255d502002-04-16 15:50:10 +00001/*
2 * schemastypes.c : implementation of the XML Schema Datatypes
3 * definition and validity checking
4 *
5 * See Copyright for the status of this software.
6 *
7 * Daniel Veillard <veillard@redhat.com>
8 */
9
10#define IN_LIBXML
11#include "libxml.h"
12
13#ifdef LIBXML_SCHEMAS_ENABLED
14
15#include <string.h>
16#include <libxml/xmlmemory.h>
17#include <libxml/parser.h>
18#include <libxml/parserInternals.h>
19#include <libxml/hash.h>
20#include <libxml/valid.h>
Daniel Veillard96a4b252003-02-06 08:22:32 +000021#include <libxml/xpath.h>
22#include <libxml/uri.h>
Daniel Veillard4255d502002-04-16 15:50:10 +000023
24#include <libxml/xmlschemas.h>
25#include <libxml/schemasInternals.h>
26#include <libxml/xmlschemastypes.h>
27
Daniel Veillard070803b2002-05-03 07:29:38 +000028#ifdef HAVE_MATH_H
29#include <math.h>
30#endif
31
Daniel Veillard4255d502002-04-16 15:50:10 +000032#define DEBUG
33
34#define TODO \
35 xmlGenericError(xmlGenericErrorContext, \
36 "Unimplemented block at %s:%d\n", \
37 __FILE__, __LINE__);
38
39#define XML_SCHEMAS_NAMESPACE_NAME \
40 (const xmlChar *)"http://www.w3.org/2001/XMLSchema"
41
42typedef enum {
43 XML_SCHEMAS_UNKNOWN = 0,
44 XML_SCHEMAS_STRING,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +000045 XML_SCHEMAS_NORMSTRING,
Daniel Veillard4255d502002-04-16 15:50:10 +000046 XML_SCHEMAS_DECIMAL,
Daniel Veillard070803b2002-05-03 07:29:38 +000047 XML_SCHEMAS_TIME,
48 XML_SCHEMAS_GDAY,
49 XML_SCHEMAS_GMONTH,
50 XML_SCHEMAS_GMONTHDAY,
51 XML_SCHEMAS_GYEAR,
52 XML_SCHEMAS_GYEARMONTH,
53 XML_SCHEMAS_DATE,
54 XML_SCHEMAS_DATETIME,
55 XML_SCHEMAS_DURATION,
Daniel Veillard84d70a42002-09-16 10:51:38 +000056 XML_SCHEMAS_FLOAT,
57 XML_SCHEMAS_DOUBLE,
Daniel Veillardc5a70f22003-02-06 23:41:59 +000058 XML_SCHEMAS_BOOLEAN,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +000059 XML_SCHEMAS_TOKEN,
60 XML_SCHEMAS_LANGUAGE,
61 XML_SCHEMAS_NMTOKEN,
62 XML_SCHEMAS_NMTOKENS,
63 XML_SCHEMAS_NAME,
64 XML_SCHEMAS_QNAME,
65 XML_SCHEMAS_NCNAME,
66 XML_SCHEMAS_ID,
67 XML_SCHEMAS_IDREF,
68 XML_SCHEMAS_IDREFS,
69 XML_SCHEMAS_ENTITY,
70 XML_SCHEMAS_ENTITIES,
71 XML_SCHEMAS_NOTATION,
72 XML_SCHEMAS_ANYURI,
73 XML_SCHEMAS_INTEGER,
74 XML_SCHEMAS_NPINTEGER,
75 XML_SCHEMAS_NINTEGER,
76 XML_SCHEMAS_NNINTEGER,
77 XML_SCHEMAS_PINTEGER,
Daniel Veillard96a4b252003-02-06 08:22:32 +000078 XML_SCHEMAS_INT,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +000079 XML_SCHEMAS_UINT,
80 XML_SCHEMAS_LONG,
81 XML_SCHEMAS_ULONG,
82 XML_SCHEMAS_SHORT,
83 XML_SCHEMAS_USHORT,
84 XML_SCHEMAS_BYTE,
Daniel Veillard560c2a42003-07-06 21:13:49 +000085 XML_SCHEMAS_UBYTE,
Daniel Veillard1ac24d32003-08-27 14:15:15 +000086 XML_SCHEMAS_HEXBINARY,
87 XML_SCHEMAS_BASE64BINARY
Daniel Veillard4255d502002-04-16 15:50:10 +000088} xmlSchemaValType;
89
Daniel Veillard5f704af2003-03-05 10:01:43 +000090static unsigned long powten[10] = {
Daniel Veillard4255d502002-04-16 15:50:10 +000091 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000L,
92 100000000L, 1000000000L
93};
94
Daniel Veillard070803b2002-05-03 07:29:38 +000095/* Date value */
96typedef struct _xmlSchemaValDate xmlSchemaValDate;
97typedef xmlSchemaValDate *xmlSchemaValDatePtr;
98struct _xmlSchemaValDate {
99 long year;
100 unsigned int mon :4; /* 1 <= mon <= 12 */
101 unsigned int day :5; /* 1 <= day <= 31 */
102 unsigned int hour :5; /* 0 <= hour <= 23 */
103 unsigned int min :6; /* 0 <= min <= 59 */
104 double sec;
Daniel Veillarda77cf712003-05-09 23:09:55 +0000105 unsigned int tz_flag :1; /* is tzo explicitely set? */
Daniel Veillard070803b2002-05-03 07:29:38 +0000106 int tzo :11; /* -1440 <= tzo <= 1440 */
107};
108
109/* Duration value */
110typedef struct _xmlSchemaValDuration xmlSchemaValDuration;
111typedef xmlSchemaValDuration *xmlSchemaValDurationPtr;
112struct _xmlSchemaValDuration {
113 long mon; /* mon stores years also */
114 long day;
115 double sec; /* sec stores min and hour also */
116};
117
Daniel Veillard4255d502002-04-16 15:50:10 +0000118typedef struct _xmlSchemaValDecimal xmlSchemaValDecimal;
119typedef xmlSchemaValDecimal *xmlSchemaValDecimalPtr;
120struct _xmlSchemaValDecimal {
121 /* would use long long but not portable */
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000122 unsigned long lo;
123 unsigned long mi;
124 unsigned long hi;
Daniel Veillard4255d502002-04-16 15:50:10 +0000125 unsigned int extra;
Daniel Veillard5a872412002-05-22 06:40:27 +0000126 unsigned int sign:1;
William M. Brackc1939562003-08-05 15:52:22 +0000127 unsigned int frac:7;
128 unsigned int total:8;
Daniel Veillard4255d502002-04-16 15:50:10 +0000129};
130
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000131typedef struct _xmlSchemaValQName xmlSchemaValQName;
132typedef xmlSchemaValQName *xmlSchemaValQNamePtr;
133struct _xmlSchemaValQName {
134 xmlChar *name;
135 xmlChar *uri;
136};
137
Daniel Veillard70bcb0e2003-08-08 14:00:28 +0000138typedef struct _xmlSchemaValHex xmlSchemaValHex;
139typedef xmlSchemaValHex *xmlSchemaValHexPtr;
140struct _xmlSchemaValHex {
141 xmlChar *str;
142 unsigned int total;
143};
144
Daniel Veillard1ac24d32003-08-27 14:15:15 +0000145typedef struct _xmlSchemaValBase64 xmlSchemaValBase64;
146typedef xmlSchemaValBase64 *xmlSchemaValBase64Ptr;
147struct _xmlSchemaValBase64 {
148 xmlChar *str;
149 unsigned int total;
150};
151
Daniel Veillard4255d502002-04-16 15:50:10 +0000152struct _xmlSchemaVal {
153 xmlSchemaValType type;
154 union {
Daniel Veillard5a872412002-05-22 06:40:27 +0000155 xmlSchemaValDecimal decimal;
Daniel Veillard070803b2002-05-03 07:29:38 +0000156 xmlSchemaValDate date;
157 xmlSchemaValDuration dur;
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000158 xmlSchemaValQName qname;
Daniel Veillard70bcb0e2003-08-08 14:00:28 +0000159 xmlSchemaValHex hex;
Daniel Veillard1ac24d32003-08-27 14:15:15 +0000160 xmlSchemaValBase64 base64;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000161 float f;
162 double d;
Daniel Veillardc5a70f22003-02-06 23:41:59 +0000163 int b;
Daniel Veillardc4c21552003-03-29 10:53:38 +0000164 xmlChar *str;
Daniel Veillard4255d502002-04-16 15:50:10 +0000165 } value;
166};
167
168static int xmlSchemaTypesInitialized = 0;
169static xmlHashTablePtr xmlSchemaTypesBank = NULL;
170
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000171/*
172 * Basic types
173 */
Daniel Veillard4255d502002-04-16 15:50:10 +0000174static xmlSchemaTypePtr xmlSchemaTypeStringDef = NULL;
175static xmlSchemaTypePtr xmlSchemaTypeAnyTypeDef = NULL;
176static xmlSchemaTypePtr xmlSchemaTypeAnySimpleTypeDef = NULL;
177static xmlSchemaTypePtr xmlSchemaTypeDecimalDef = NULL;
Daniel Veillard070803b2002-05-03 07:29:38 +0000178static xmlSchemaTypePtr xmlSchemaTypeDatetimeDef = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +0000179static xmlSchemaTypePtr xmlSchemaTypeDateDef = NULL;
Daniel Veillard070803b2002-05-03 07:29:38 +0000180static xmlSchemaTypePtr xmlSchemaTypeTimeDef = NULL;
181static xmlSchemaTypePtr xmlSchemaTypeGYearDef = NULL;
182static xmlSchemaTypePtr xmlSchemaTypeGYearMonthDef = NULL;
183static xmlSchemaTypePtr xmlSchemaTypeGDayDef = NULL;
184static xmlSchemaTypePtr xmlSchemaTypeGMonthDayDef = NULL;
185static xmlSchemaTypePtr xmlSchemaTypeGMonthDef = NULL;
186static xmlSchemaTypePtr xmlSchemaTypeDurationDef = NULL;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000187static xmlSchemaTypePtr xmlSchemaTypeFloatDef = NULL;
Daniel Veillardc5a70f22003-02-06 23:41:59 +0000188static xmlSchemaTypePtr xmlSchemaTypeBooleanDef = NULL;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000189static xmlSchemaTypePtr xmlSchemaTypeDoubleDef = NULL;
Daniel Veillard560c2a42003-07-06 21:13:49 +0000190static xmlSchemaTypePtr xmlSchemaTypeHexBinaryDef = NULL;
Daniel Veillard1ac24d32003-08-27 14:15:15 +0000191static xmlSchemaTypePtr xmlSchemaTypeBase64BinaryDef = NULL;
Daniel Veillarde5b110b2003-02-04 14:43:39 +0000192static xmlSchemaTypePtr xmlSchemaTypeAnyURIDef = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +0000193
194/*
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000195 * Derived types
196 */
197static xmlSchemaTypePtr xmlSchemaTypePositiveIntegerDef = NULL;
198static xmlSchemaTypePtr xmlSchemaTypeNonPositiveIntegerDef = NULL;
199static xmlSchemaTypePtr xmlSchemaTypeNegativeIntegerDef = NULL;
200static xmlSchemaTypePtr xmlSchemaTypeNonNegativeIntegerDef = NULL;
201static xmlSchemaTypePtr xmlSchemaTypeIntegerDef = NULL;
202static xmlSchemaTypePtr xmlSchemaTypeLongDef = NULL;
203static xmlSchemaTypePtr xmlSchemaTypeIntDef = NULL;
204static xmlSchemaTypePtr xmlSchemaTypeShortDef = NULL;
205static xmlSchemaTypePtr xmlSchemaTypeByteDef = NULL;
206static xmlSchemaTypePtr xmlSchemaTypeUnsignedLongDef = NULL;
207static xmlSchemaTypePtr xmlSchemaTypeUnsignedIntDef = NULL;
208static xmlSchemaTypePtr xmlSchemaTypeUnsignedShortDef = NULL;
209static xmlSchemaTypePtr xmlSchemaTypeUnsignedByteDef = NULL;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000210static xmlSchemaTypePtr xmlSchemaTypeNormStringDef = NULL;
211static xmlSchemaTypePtr xmlSchemaTypeTokenDef = NULL;
212static xmlSchemaTypePtr xmlSchemaTypeLanguageDef = NULL;
213static xmlSchemaTypePtr xmlSchemaTypeNameDef = NULL;
214static xmlSchemaTypePtr xmlSchemaTypeQNameDef = NULL;
Daniel Veillarde5b110b2003-02-04 14:43:39 +0000215static xmlSchemaTypePtr xmlSchemaTypeNCNameDef = NULL;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000216static xmlSchemaTypePtr xmlSchemaTypeIdDef = NULL;
217static xmlSchemaTypePtr xmlSchemaTypeIdrefDef = NULL;
218static xmlSchemaTypePtr xmlSchemaTypeIdrefsDef = NULL;
Daniel Veillarda1a9d042003-03-18 16:53:17 +0000219static xmlSchemaTypePtr xmlSchemaTypeEntityDef = NULL;
220static xmlSchemaTypePtr xmlSchemaTypeEntitiesDef = NULL;
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000221static xmlSchemaTypePtr xmlSchemaTypeNotationDef = NULL;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000222static xmlSchemaTypePtr xmlSchemaTypeNmtokenDef = NULL;
223static xmlSchemaTypePtr xmlSchemaTypeNmtokensDef = NULL;
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000224
225/*
Daniel Veillard4255d502002-04-16 15:50:10 +0000226 * xmlSchemaInitBasicType:
227 * @name: the type name
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000228 * @type: the value type associated
Daniel Veillard4255d502002-04-16 15:50:10 +0000229 *
230 * Initialize one default type
231 */
232static xmlSchemaTypePtr
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000233xmlSchemaInitBasicType(const char *name, xmlSchemaValType type) {
Daniel Veillard4255d502002-04-16 15:50:10 +0000234 xmlSchemaTypePtr ret;
235
236 ret = (xmlSchemaTypePtr) xmlMalloc(sizeof(xmlSchemaType));
237 if (ret == NULL) {
238 xmlGenericError(xmlGenericErrorContext,
239 "Could not initilize type %s: out of memory\n", name);
240 return(NULL);
241 }
242 memset(ret, 0, sizeof(xmlSchemaType));
243 ret->name = xmlStrdup((const xmlChar *)name);
244 ret->type = XML_SCHEMA_TYPE_BASIC;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000245 ret->flags = type;
Daniel Veillard4255d502002-04-16 15:50:10 +0000246 ret->contentType = XML_SCHEMA_CONTENT_BASIC;
247 xmlHashAddEntry2(xmlSchemaTypesBank, ret->name,
248 XML_SCHEMAS_NAMESPACE_NAME, ret);
249 return(ret);
250}
251
252/*
253 * xmlSchemaInitTypes:
254 *
255 * Initialize the default XML Schemas type library
256 */
257void
Daniel Veillard6560a422003-03-27 21:25:38 +0000258xmlSchemaInitTypes(void)
259{
Daniel Veillard4255d502002-04-16 15:50:10 +0000260 if (xmlSchemaTypesInitialized != 0)
Daniel Veillard6560a422003-03-27 21:25:38 +0000261 return;
Daniel Veillard4255d502002-04-16 15:50:10 +0000262 xmlSchemaTypesBank = xmlHashCreate(40);
Daniel Veillard6560a422003-03-27 21:25:38 +0000263
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000264 /*
265 * primitive datatypes
266 */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000267 xmlSchemaTypeStringDef = xmlSchemaInitBasicType("string",
Daniel Veillard6560a422003-03-27 21:25:38 +0000268 XML_SCHEMAS_STRING);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000269 xmlSchemaTypeAnyTypeDef = xmlSchemaInitBasicType("anyType",
Daniel Veillard6560a422003-03-27 21:25:38 +0000270 XML_SCHEMAS_UNKNOWN);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000271 xmlSchemaTypeAnySimpleTypeDef = xmlSchemaInitBasicType("anySimpleType",
Daniel Veillard6560a422003-03-27 21:25:38 +0000272 XML_SCHEMAS_UNKNOWN);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000273 xmlSchemaTypeDecimalDef = xmlSchemaInitBasicType("decimal",
Daniel Veillard6560a422003-03-27 21:25:38 +0000274 XML_SCHEMAS_DECIMAL);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000275 xmlSchemaTypeDateDef = xmlSchemaInitBasicType("date",
Daniel Veillard6560a422003-03-27 21:25:38 +0000276 XML_SCHEMAS_DATE);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000277 xmlSchemaTypeDatetimeDef = xmlSchemaInitBasicType("dateTime",
Daniel Veillard6560a422003-03-27 21:25:38 +0000278 XML_SCHEMAS_DATETIME);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000279 xmlSchemaTypeTimeDef = xmlSchemaInitBasicType("time",
Daniel Veillard6560a422003-03-27 21:25:38 +0000280 XML_SCHEMAS_TIME);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000281 xmlSchemaTypeGYearDef = xmlSchemaInitBasicType("gYear",
Daniel Veillard6560a422003-03-27 21:25:38 +0000282 XML_SCHEMAS_GYEAR);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000283 xmlSchemaTypeGYearMonthDef = xmlSchemaInitBasicType("gYearMonth",
Daniel Veillard6560a422003-03-27 21:25:38 +0000284 XML_SCHEMAS_GYEARMONTH);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000285 xmlSchemaTypeGMonthDef = xmlSchemaInitBasicType("gMonth",
Daniel Veillard6560a422003-03-27 21:25:38 +0000286 XML_SCHEMAS_GMONTH);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000287 xmlSchemaTypeGMonthDayDef = xmlSchemaInitBasicType("gMonthDay",
Daniel Veillard6560a422003-03-27 21:25:38 +0000288 XML_SCHEMAS_GMONTHDAY);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000289 xmlSchemaTypeGDayDef = xmlSchemaInitBasicType("gDay",
Daniel Veillard6560a422003-03-27 21:25:38 +0000290 XML_SCHEMAS_GDAY);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000291 xmlSchemaTypeDurationDef = xmlSchemaInitBasicType("duration",
Daniel Veillard6560a422003-03-27 21:25:38 +0000292 XML_SCHEMAS_DURATION);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000293 xmlSchemaTypeFloatDef = xmlSchemaInitBasicType("float",
Daniel Veillard6560a422003-03-27 21:25:38 +0000294 XML_SCHEMAS_FLOAT);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000295 xmlSchemaTypeDoubleDef = xmlSchemaInitBasicType("double",
Daniel Veillard6560a422003-03-27 21:25:38 +0000296 XML_SCHEMAS_DOUBLE);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000297 xmlSchemaTypeBooleanDef = xmlSchemaInitBasicType("boolean",
Daniel Veillard6560a422003-03-27 21:25:38 +0000298 XML_SCHEMAS_BOOLEAN);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000299 xmlSchemaTypeAnyURIDef = xmlSchemaInitBasicType("anyURI",
Daniel Veillard6560a422003-03-27 21:25:38 +0000300 XML_SCHEMAS_ANYURI);
Daniel Veillard560c2a42003-07-06 21:13:49 +0000301 xmlSchemaTypeHexBinaryDef = xmlSchemaInitBasicType("hexBinary",
302 XML_SCHEMAS_HEXBINARY);
Daniel Veillard1ac24d32003-08-27 14:15:15 +0000303 xmlSchemaTypeBase64BinaryDef
304 = xmlSchemaInitBasicType("base64Binary", XML_SCHEMAS_BASE64BINARY);
Daniel Veillard4255d502002-04-16 15:50:10 +0000305
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000306 /*
307 * derived datatypes
308 */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000309 xmlSchemaTypeIntegerDef = xmlSchemaInitBasicType("integer",
Daniel Veillard6560a422003-03-27 21:25:38 +0000310 XML_SCHEMAS_INTEGER);;
311 xmlSchemaTypeNonPositiveIntegerDef =
312 xmlSchemaInitBasicType("nonPositiveInteger",
313 XML_SCHEMAS_NPINTEGER);;
314 xmlSchemaTypeNegativeIntegerDef =
315 xmlSchemaInitBasicType("negativeInteger", XML_SCHEMAS_NINTEGER);;
316 xmlSchemaTypeLongDef =
317 xmlSchemaInitBasicType("long", XML_SCHEMAS_LONG);;
318 xmlSchemaTypeIntDef = xmlSchemaInitBasicType("int", XML_SCHEMAS_INT);;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000319 xmlSchemaTypeShortDef = xmlSchemaInitBasicType("short",
Daniel Veillard6560a422003-03-27 21:25:38 +0000320 XML_SCHEMAS_SHORT);;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000321 xmlSchemaTypeByteDef = xmlSchemaInitBasicType("byte",
Daniel Veillard6560a422003-03-27 21:25:38 +0000322 XML_SCHEMAS_BYTE);;
323 xmlSchemaTypeNonNegativeIntegerDef =
324 xmlSchemaInitBasicType("nonNegativeInteger",
325 XML_SCHEMAS_NNINTEGER);
326 xmlSchemaTypeUnsignedLongDef =
327 xmlSchemaInitBasicType("unsignedLong", XML_SCHEMAS_ULONG);;
328 xmlSchemaTypeUnsignedIntDef =
329 xmlSchemaInitBasicType("unsignedInt", XML_SCHEMAS_UINT);;
330 xmlSchemaTypeUnsignedShortDef =
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000331 xmlSchemaInitBasicType("unsignedShort", XML_SCHEMAS_USHORT);;
Daniel Veillard6560a422003-03-27 21:25:38 +0000332 xmlSchemaTypeUnsignedByteDef =
333 xmlSchemaInitBasicType("unsignedByte", XML_SCHEMAS_UBYTE);;
334 xmlSchemaTypePositiveIntegerDef =
335 xmlSchemaInitBasicType("positiveInteger", XML_SCHEMAS_PINTEGER);
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000336
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000337 xmlSchemaTypeNormStringDef = xmlSchemaInitBasicType("normalizedString",
Daniel Veillard6560a422003-03-27 21:25:38 +0000338 XML_SCHEMAS_NORMSTRING);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000339 xmlSchemaTypeTokenDef = xmlSchemaInitBasicType("token",
Daniel Veillard6560a422003-03-27 21:25:38 +0000340 XML_SCHEMAS_TOKEN);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000341 xmlSchemaTypeLanguageDef = xmlSchemaInitBasicType("language",
Daniel Veillard6560a422003-03-27 21:25:38 +0000342 XML_SCHEMAS_LANGUAGE);
343 xmlSchemaTypeIdDef = xmlSchemaInitBasicType("ID", XML_SCHEMAS_ID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000344 xmlSchemaTypeIdrefDef = xmlSchemaInitBasicType("IDREF",
Daniel Veillard6560a422003-03-27 21:25:38 +0000345 XML_SCHEMAS_IDREF);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000346 xmlSchemaTypeIdrefsDef = xmlSchemaInitBasicType("IDREFS",
Daniel Veillard6560a422003-03-27 21:25:38 +0000347 XML_SCHEMAS_IDREFS);
Daniel Veillarda1a9d042003-03-18 16:53:17 +0000348 xmlSchemaTypeEntityDef = xmlSchemaInitBasicType("ENTITY",
Daniel Veillard6560a422003-03-27 21:25:38 +0000349 XML_SCHEMAS_ENTITY);
Daniel Veillarda1a9d042003-03-18 16:53:17 +0000350 xmlSchemaTypeEntitiesDef = xmlSchemaInitBasicType("ENTITIES",
Daniel Veillard6560a422003-03-27 21:25:38 +0000351 XML_SCHEMAS_ENTITIES);
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000352 xmlSchemaTypeNotationDef = xmlSchemaInitBasicType("NOTATION",
353 XML_SCHEMAS_NOTATION);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000354 xmlSchemaTypeNameDef = xmlSchemaInitBasicType("Name",
Daniel Veillard6560a422003-03-27 21:25:38 +0000355 XML_SCHEMAS_NAME);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000356 xmlSchemaTypeQNameDef = xmlSchemaInitBasicType("QName",
Daniel Veillard6560a422003-03-27 21:25:38 +0000357 XML_SCHEMAS_QNAME);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000358 xmlSchemaTypeNCNameDef = xmlSchemaInitBasicType("NCName",
Daniel Veillard6560a422003-03-27 21:25:38 +0000359 XML_SCHEMAS_NCNAME);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000360 xmlSchemaTypeNmtokenDef = xmlSchemaInitBasicType("NMTOKEN",
Daniel Veillard6560a422003-03-27 21:25:38 +0000361 XML_SCHEMAS_NMTOKEN);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000362 xmlSchemaTypeNmtokensDef = xmlSchemaInitBasicType("NMTOKENS",
Daniel Veillard6560a422003-03-27 21:25:38 +0000363 XML_SCHEMAS_NMTOKENS);
Daniel Veillard4255d502002-04-16 15:50:10 +0000364 xmlSchemaTypesInitialized = 1;
365}
366
367/**
368 * xmlSchemaCleanupTypes:
369 *
370 * Cleanup the default XML Schemas type library
371 */
372void
373xmlSchemaCleanupTypes(void) {
374 if (xmlSchemaTypesInitialized == 0)
375 return;
376 xmlHashFree(xmlSchemaTypesBank, (xmlHashDeallocator) xmlSchemaFreeType);
377 xmlSchemaTypesInitialized = 0;
378}
379
380/**
381 * xmlSchemaNewValue:
382 * @type: the value type
383 *
384 * Allocate a new simple type value
385 *
386 * Returns a pointer to the new value or NULL in case of error
387 */
388static xmlSchemaValPtr
389xmlSchemaNewValue(xmlSchemaValType type) {
390 xmlSchemaValPtr value;
391
392 value = (xmlSchemaValPtr) xmlMalloc(sizeof(xmlSchemaVal));
393 if (value == NULL) {
394 return(NULL);
395 }
396 memset(value, 0, sizeof(xmlSchemaVal));
397 value->type = type;
398 return(value);
399}
400
401/**
402 * xmlSchemaFreeValue:
403 * @value: the value to free
404 *
405 * Cleanup the default XML Schemas type library
406 */
407void
408xmlSchemaFreeValue(xmlSchemaValPtr value) {
409 if (value == NULL)
410 return;
Daniel Veillardc4c21552003-03-29 10:53:38 +0000411 switch (value->type) {
412 case XML_SCHEMAS_STRING:
413 case XML_SCHEMAS_NORMSTRING:
414 case XML_SCHEMAS_TOKEN:
415 case XML_SCHEMAS_LANGUAGE:
416 case XML_SCHEMAS_NMTOKEN:
417 case XML_SCHEMAS_NMTOKENS:
418 case XML_SCHEMAS_NAME:
Daniel Veillardc4c21552003-03-29 10:53:38 +0000419 case XML_SCHEMAS_NCNAME:
420 case XML_SCHEMAS_ID:
421 case XML_SCHEMAS_IDREF:
422 case XML_SCHEMAS_IDREFS:
423 case XML_SCHEMAS_ENTITY:
424 case XML_SCHEMAS_ENTITIES:
425 case XML_SCHEMAS_NOTATION:
426 case XML_SCHEMAS_ANYURI:
427 if (value->value.str != NULL)
428 xmlFree(value->value.str);
429 break;
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000430 case XML_SCHEMAS_QNAME:
431 if (value->value.qname.uri != NULL)
432 xmlFree(value->value.qname.uri);
433 if (value->value.qname.name != NULL)
434 xmlFree(value->value.qname.name);
435 break;
Daniel Veillard70bcb0e2003-08-08 14:00:28 +0000436 case XML_SCHEMAS_HEXBINARY:
437 if (value->value.hex.str != NULL)
438 xmlFree(value->value.hex.str);
439 break;
Daniel Veillard1ac24d32003-08-27 14:15:15 +0000440 case XML_SCHEMAS_BASE64BINARY:
441 if (value->value.base64.str != NULL)
442 xmlFree(value->value.base64.str);
443 break;
Daniel Veillardc4c21552003-03-29 10:53:38 +0000444 default:
445 break;
446 }
Daniel Veillard4255d502002-04-16 15:50:10 +0000447 xmlFree(value);
448}
449
450/**
451 * xmlSchemaGetPredefinedType:
452 * @name: the type name
453 * @ns: the URI of the namespace usually "http://www.w3.org/2001/XMLSchema"
454 *
455 * Lookup a type in the default XML Schemas type library
456 *
457 * Returns the type if found, NULL otherwise
458 */
459xmlSchemaTypePtr
460xmlSchemaGetPredefinedType(const xmlChar *name, const xmlChar *ns) {
461 if (xmlSchemaTypesInitialized == 0)
462 xmlSchemaInitTypes();
463 if (name == NULL)
464 return(NULL);
465 return((xmlSchemaTypePtr) xmlHashLookup2(xmlSchemaTypesBank, name, ns));
466}
Daniel Veillard070803b2002-05-03 07:29:38 +0000467
468/****************************************************************
469 * *
470 * Convenience macros and functions *
471 * *
472 ****************************************************************/
473
474#define IS_TZO_CHAR(c) \
475 ((c == 0) || (c == 'Z') || (c == '+') || (c == '-'))
476
477#define VALID_YEAR(yr) (yr != 0)
478#define VALID_MONTH(mon) ((mon >= 1) && (mon <= 12))
479/* VALID_DAY should only be used when month is unknown */
480#define VALID_DAY(day) ((day >= 1) && (day <= 31))
481#define VALID_HOUR(hr) ((hr >= 0) && (hr <= 23))
482#define VALID_MIN(min) ((min >= 0) && (min <= 59))
483#define VALID_SEC(sec) ((sec >= 0) && (sec < 60))
484#define VALID_TZO(tzo) ((tzo > -1440) && (tzo < 1440))
485#define IS_LEAP(y) \
486 (((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0))
487
488static const long daysInMonth[12] =
489 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
490static const long daysInMonthLeap[12] =
491 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
492
Daniel Veillard5a872412002-05-22 06:40:27 +0000493#define MAX_DAYINMONTH(yr,mon) \
494 (IS_LEAP(yr) ? daysInMonthLeap[mon - 1] : daysInMonth[mon - 1])
495
Daniel Veillard070803b2002-05-03 07:29:38 +0000496#define VALID_MDAY(dt) \
497 (IS_LEAP(dt->year) ? \
498 (dt->day <= daysInMonthLeap[dt->mon - 1]) : \
499 (dt->day <= daysInMonth[dt->mon - 1]))
500
501#define VALID_DATE(dt) \
502 (VALID_YEAR(dt->year) && VALID_MONTH(dt->mon) && VALID_MDAY(dt))
503
504#define VALID_TIME(dt) \
505 (VALID_HOUR(dt->hour) && VALID_MIN(dt->min) && \
506 VALID_SEC(dt->sec) && VALID_TZO(dt->tzo))
507
508#define VALID_DATETIME(dt) \
509 (VALID_DATE(dt) && VALID_TIME(dt))
510
511#define SECS_PER_MIN (60)
512#define SECS_PER_HOUR (60 * SECS_PER_MIN)
513#define SECS_PER_DAY (24 * SECS_PER_HOUR)
514
Daniel Veillard5a872412002-05-22 06:40:27 +0000515static const long dayInYearByMonth[12] =
516 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
517static const long dayInLeapYearByMonth[12] =
518 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 };
519
520#define DAY_IN_YEAR(day, month, year) \
521 ((IS_LEAP(year) ? \
522 dayInLeapYearByMonth[month - 1] : \
523 dayInYearByMonth[month - 1]) + day)
524
525#ifdef DEBUG
526#define DEBUG_DATE(dt) \
527 xmlGenericError(xmlGenericErrorContext, \
528 "type=%o %04ld-%02u-%02uT%02u:%02u:%03f", \
529 dt->type,dt->value.date.year,dt->value.date.mon, \
530 dt->value.date.day,dt->value.date.hour,dt->value.date.min, \
531 dt->value.date.sec); \
532 if (dt->value.date.tz_flag) \
533 if (dt->value.date.tzo != 0) \
534 xmlGenericError(xmlGenericErrorContext, \
535 "%+05d\n",dt->value.date.tzo); \
536 else \
537 xmlGenericError(xmlGenericErrorContext, "Z\n"); \
538 else \
539 xmlGenericError(xmlGenericErrorContext,"\n")
540#else
541#define DEBUG_DATE(dt)
542#endif
543
Daniel Veillard070803b2002-05-03 07:29:38 +0000544/**
545 * _xmlSchemaParseGYear:
546 * @dt: pointer to a date structure
547 * @str: pointer to the string to analyze
548 *
549 * Parses a xs:gYear without time zone and fills in the appropriate
550 * field of the @dt structure. @str is updated to point just after the
551 * xs:gYear. It is supposed that @dt->year is big enough to contain
552 * the year.
553 *
554 * Returns 0 or the error code
555 */
556static int
557_xmlSchemaParseGYear (xmlSchemaValDatePtr dt, const xmlChar **str) {
558 const xmlChar *cur = *str, *firstChar;
559 int isneg = 0, digcnt = 0;
560
561 if (((*cur < '0') || (*cur > '9')) &&
562 (*cur != '-') && (*cur != '+'))
563 return -1;
564
565 if (*cur == '-') {
566 isneg = 1;
567 cur++;
568 }
569
570 firstChar = cur;
571
572 while ((*cur >= '0') && (*cur <= '9')) {
573 dt->year = dt->year * 10 + (*cur - '0');
574 cur++;
575 digcnt++;
576 }
577
578 /* year must be at least 4 digits (CCYY); over 4
579 * digits cannot have a leading zero. */
580 if ((digcnt < 4) || ((digcnt > 4) && (*firstChar == '0')))
581 return 1;
582
583 if (isneg)
584 dt->year = - dt->year;
585
586 if (!VALID_YEAR(dt->year))
587 return 2;
588
589 *str = cur;
590 return 0;
591}
592
593/**
594 * PARSE_2_DIGITS:
595 * @num: the integer to fill in
596 * @cur: an #xmlChar *
597 * @invalid: an integer
598 *
599 * Parses a 2-digits integer and updates @num with the value. @cur is
600 * updated to point just after the integer.
601 * In case of error, @invalid is set to %TRUE, values of @num and
602 * @cur are undefined.
603 */
604#define PARSE_2_DIGITS(num, cur, invalid) \
605 if ((cur[0] < '0') || (cur[0] > '9') || \
606 (cur[1] < '0') || (cur[1] > '9')) \
607 invalid = 1; \
608 else \
609 num = (cur[0] - '0') * 10 + (cur[1] - '0'); \
610 cur += 2;
611
612/**
613 * PARSE_FLOAT:
614 * @num: the double to fill in
615 * @cur: an #xmlChar *
616 * @invalid: an integer
617 *
618 * Parses a float and updates @num with the value. @cur is
619 * updated to point just after the float. The float must have a
620 * 2-digits integer part and may or may not have a decimal part.
621 * In case of error, @invalid is set to %TRUE, values of @num and
622 * @cur are undefined.
623 */
624#define PARSE_FLOAT(num, cur, invalid) \
625 PARSE_2_DIGITS(num, cur, invalid); \
626 if (!invalid && (*cur == '.')) { \
627 double mult = 1; \
628 cur++; \
629 if ((*cur < '0') || (*cur > '9')) \
630 invalid = 1; \
631 while ((*cur >= '0') && (*cur <= '9')) { \
632 mult /= 10; \
633 num += (*cur - '0') * mult; \
634 cur++; \
635 } \
636 }
637
638/**
639 * _xmlSchemaParseGMonth:
640 * @dt: pointer to a date structure
641 * @str: pointer to the string to analyze
642 *
643 * Parses a xs:gMonth without time zone and fills in the appropriate
644 * field of the @dt structure. @str is updated to point just after the
645 * xs:gMonth.
646 *
647 * Returns 0 or the error code
648 */
649static int
650_xmlSchemaParseGMonth (xmlSchemaValDatePtr dt, const xmlChar **str) {
651 const xmlChar *cur = *str;
652 int ret = 0;
653
654 PARSE_2_DIGITS(dt->mon, cur, ret);
655 if (ret != 0)
656 return ret;
657
658 if (!VALID_MONTH(dt->mon))
659 return 2;
660
661 *str = cur;
662 return 0;
663}
664
665/**
666 * _xmlSchemaParseGDay:
667 * @dt: pointer to a date structure
668 * @str: pointer to the string to analyze
669 *
670 * Parses a xs:gDay without time zone and fills in the appropriate
671 * field of the @dt structure. @str is updated to point just after the
672 * xs:gDay.
673 *
674 * Returns 0 or the error code
675 */
676static int
677_xmlSchemaParseGDay (xmlSchemaValDatePtr dt, const xmlChar **str) {
678 const xmlChar *cur = *str;
679 int ret = 0;
680
681 PARSE_2_DIGITS(dt->day, cur, ret);
682 if (ret != 0)
683 return ret;
684
685 if (!VALID_DAY(dt->day))
686 return 2;
687
688 *str = cur;
689 return 0;
690}
691
692/**
693 * _xmlSchemaParseTime:
694 * @dt: pointer to a date structure
695 * @str: pointer to the string to analyze
696 *
697 * Parses a xs:time without time zone and fills in the appropriate
698 * fields of the @dt structure. @str is updated to point just after the
699 * xs:time.
700 * In case of error, values of @dt fields are undefined.
701 *
702 * Returns 0 or the error code
703 */
704static int
705_xmlSchemaParseTime (xmlSchemaValDatePtr dt, const xmlChar **str) {
706 const xmlChar *cur = *str;
707 unsigned int hour = 0; /* use temp var in case str is not xs:time */
708 int ret = 0;
709
710 PARSE_2_DIGITS(hour, cur, ret);
711 if (ret != 0)
712 return ret;
713
714 if (*cur != ':')
715 return 1;
716 cur++;
717
718 /* the ':' insures this string is xs:time */
719 dt->hour = hour;
720
721 PARSE_2_DIGITS(dt->min, cur, ret);
722 if (ret != 0)
723 return ret;
724
725 if (*cur != ':')
726 return 1;
727 cur++;
728
729 PARSE_FLOAT(dt->sec, cur, ret);
730 if (ret != 0)
731 return ret;
732
733 if (!VALID_TIME(dt))
734 return 2;
735
736 *str = cur;
737 return 0;
738}
739
740/**
741 * _xmlSchemaParseTimeZone:
742 * @dt: pointer to a date structure
743 * @str: pointer to the string to analyze
744 *
745 * Parses a time zone without time zone and fills in the appropriate
746 * field of the @dt structure. @str is updated to point just after the
747 * time zone.
748 *
749 * Returns 0 or the error code
750 */
751static int
752_xmlSchemaParseTimeZone (xmlSchemaValDatePtr dt, const xmlChar **str) {
753 const xmlChar *cur = *str;
754 int ret = 0;
755
756 if (str == NULL)
757 return -1;
758
759 switch (*cur) {
760 case 0:
761 dt->tz_flag = 0;
762 dt->tzo = 0;
763 break;
764
765 case 'Z':
766 dt->tz_flag = 1;
767 dt->tzo = 0;
768 cur++;
769 break;
770
771 case '+':
772 case '-': {
773 int isneg = 0, tmp = 0;
774 isneg = (*cur == '-');
775
776 cur++;
777
778 PARSE_2_DIGITS(tmp, cur, ret);
779 if (ret != 0)
780 return ret;
781 if (!VALID_HOUR(tmp))
782 return 2;
783
784 if (*cur != ':')
785 return 1;
786 cur++;
787
788 dt->tzo = tmp * 60;
789
790 PARSE_2_DIGITS(tmp, cur, ret);
791 if (ret != 0)
792 return ret;
793 if (!VALID_MIN(tmp))
794 return 2;
795
796 dt->tzo += tmp;
797 if (isneg)
798 dt->tzo = - dt->tzo;
799
800 if (!VALID_TZO(dt->tzo))
801 return 2;
802
Daniel Veillard5a872412002-05-22 06:40:27 +0000803 dt->tz_flag = 1;
Daniel Veillard070803b2002-05-03 07:29:38 +0000804 break;
805 }
806 default:
807 return 1;
808 }
809
810 *str = cur;
811 return 0;
812}
813
Daniel Veillard1ac24d32003-08-27 14:15:15 +0000814/**
815 * _xmlSchemaBase64Decode:
816 * @ch: a character
817 *
818 * Converts a base64 encoded character to its base 64 value.
819 *
820 * Returns 0-63 (value), 64 (pad), or -1 (not recognized)
821 */
822static int
823_xmlSchemaBase64Decode (const xmlChar ch) {
824 if (('A' <= ch) && (ch <= 'Z')) return ch - 'A';
825 if (('a' <= ch) && (ch <= 'z')) return ch - 'a' + 26;
826 if (('0' <= ch) && (ch <= '9')) return ch - '0' + 52;
827 if ('+' == ch) return 62;
828 if ('/' == ch) return 63;
829 if ('=' == ch) return 64;
830 return -1;
831}
832
Daniel Veillard070803b2002-05-03 07:29:38 +0000833/****************************************************************
834 * *
835 * XML Schema Dates/Times Datatypes Handling *
836 * *
837 ****************************************************************/
838
839/**
840 * PARSE_DIGITS:
841 * @num: the integer to fill in
842 * @cur: an #xmlChar *
843 * @num_type: an integer flag
844 *
845 * Parses a digits integer and updates @num with the value. @cur is
846 * updated to point just after the integer.
847 * In case of error, @num_type is set to -1, values of @num and
848 * @cur are undefined.
849 */
850#define PARSE_DIGITS(num, cur, num_type) \
851 if ((*cur < '0') || (*cur > '9')) \
852 num_type = -1; \
853 else \
854 while ((*cur >= '0') && (*cur <= '9')) { \
855 num = num * 10 + (*cur - '0'); \
856 cur++; \
857 }
858
859/**
860 * PARSE_NUM:
861 * @num: the double to fill in
862 * @cur: an #xmlChar *
863 * @num_type: an integer flag
864 *
865 * Parses a float or integer and updates @num with the value. @cur is
866 * updated to point just after the number. If the number is a float,
867 * then it must have an integer part and a decimal part; @num_type will
868 * be set to 1. If there is no decimal part, @num_type is set to zero.
869 * In case of error, @num_type is set to -1, values of @num and
870 * @cur are undefined.
871 */
872#define PARSE_NUM(num, cur, num_type) \
873 num = 0; \
874 PARSE_DIGITS(num, cur, num_type); \
875 if (!num_type && (*cur == '.')) { \
876 double mult = 1; \
877 cur++; \
878 if ((*cur < '0') || (*cur > '9')) \
879 num_type = -1; \
880 else \
881 num_type = 1; \
882 while ((*cur >= '0') && (*cur <= '9')) { \
883 mult /= 10; \
884 num += (*cur - '0') * mult; \
885 cur++; \
886 } \
887 }
888
889/**
Daniel Veillard5a872412002-05-22 06:40:27 +0000890 * xmlSchemaValidateDates:
Daniel Veillard455cc072003-03-31 10:13:23 +0000891 * @type: the expected type or XML_SCHEMAS_UNKNOWN
Daniel Veillard070803b2002-05-03 07:29:38 +0000892 * @dateTime: string to analyze
893 * @val: the return computed value
894 *
895 * Check that @dateTime conforms to the lexical space of one of the date types.
896 * if true a value is computed and returned in @val.
897 *
898 * Returns 0 if this validates, a positive error code number otherwise
899 * and -1 in case of internal or API error.
900 */
901static int
Daniel Veillard455cc072003-03-31 10:13:23 +0000902xmlSchemaValidateDates (xmlSchemaValType type,
Daniel Veillard118aed72002-09-24 14:13:13 +0000903 const xmlChar *dateTime, xmlSchemaValPtr *val) {
Daniel Veillard070803b2002-05-03 07:29:38 +0000904 xmlSchemaValPtr dt;
905 int ret;
906 const xmlChar *cur = dateTime;
907
908#define RETURN_TYPE_IF_VALID(t) \
909 if (IS_TZO_CHAR(*cur)) { \
910 ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur); \
911 if (ret == 0) { \
912 if (*cur != 0) \
913 goto error; \
914 dt->type = t; \
Daniel Veillard455cc072003-03-31 10:13:23 +0000915 goto done; \
Daniel Veillard070803b2002-05-03 07:29:38 +0000916 } \
917 }
918
919 if (dateTime == NULL)
920 return -1;
921
922 if ((*cur != '-') && (*cur < '0') && (*cur > '9'))
923 return 1;
924
925 dt = xmlSchemaNewValue(XML_SCHEMAS_UNKNOWN);
926 if (dt == NULL)
927 return -1;
928
929 if ((cur[0] == '-') && (cur[1] == '-')) {
930 /*
931 * It's an incomplete date (xs:gMonthDay, xs:gMonth or
932 * xs:gDay)
933 */
934 cur += 2;
935
936 /* is it an xs:gDay? */
937 if (*cur == '-') {
Daniel Veillard455cc072003-03-31 10:13:23 +0000938 if (type == XML_SCHEMAS_GMONTH)
939 goto error;
Daniel Veillard070803b2002-05-03 07:29:38 +0000940 ++cur;
941 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
942 if (ret != 0)
943 goto error;
944
945 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GDAY);
946
947 goto error;
948 }
949
950 /*
951 * it should be an xs:gMonthDay or xs:gMonth
952 */
953 ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
954 if (ret != 0)
955 goto error;
956
Daniel Veillardd3b9cd82003-04-09 11:24:17 +0000957 /*
958 * a '-' char could indicate this type is xs:gMonthDay or
959 * a negative time zone offset. Check for xs:gMonthDay first.
960 * Also the first three char's of a negative tzo (-MM:SS) can
961 * appear to be a valid day; so even if the day portion
962 * of the xs:gMonthDay verifies, we must insure it was not
963 * a tzo.
964 */
965 if (*cur == '-') {
966 const xmlChar *rewnd = cur;
967 cur++;
Daniel Veillard070803b2002-05-03 07:29:38 +0000968
Daniel Veillardd3b9cd82003-04-09 11:24:17 +0000969 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
970 if ((ret == 0) && ((*cur == 0) || (*cur != ':'))) {
971
972 /*
973 * we can use the VALID_MDAY macro to validate the month
974 * and day because the leap year test will flag year zero
975 * as a leap year (even though zero is an invalid year).
976 */
977 if (VALID_MDAY((&(dt->value.date)))) {
978
979 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTHDAY);
980
981 goto error;
982 }
983 }
984
985 /*
986 * not xs:gMonthDay so rewind and check if just xs:gMonth
987 * with an optional time zone.
988 */
989 cur = rewnd;
990 }
991
992 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTH);
Daniel Veillard070803b2002-05-03 07:29:38 +0000993
994 goto error;
995 }
996
997 /*
998 * It's a right-truncated date or an xs:time.
999 * Try to parse an xs:time then fallback on right-truncated dates.
1000 */
1001 if ((*cur >= '0') && (*cur <= '9')) {
1002 ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
1003 if (ret == 0) {
1004 /* it's an xs:time */
1005 RETURN_TYPE_IF_VALID(XML_SCHEMAS_TIME);
1006 }
1007 }
1008
1009 /* fallback on date parsing */
1010 cur = dateTime;
1011
1012 ret = _xmlSchemaParseGYear(&(dt->value.date), &cur);
1013 if (ret != 0)
1014 goto error;
1015
1016 /* is it an xs:gYear? */
1017 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEAR);
1018
1019 if (*cur != '-')
1020 goto error;
1021 cur++;
1022
1023 ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
1024 if (ret != 0)
1025 goto error;
1026
1027 /* is it an xs:gYearMonth? */
1028 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEARMONTH);
1029
1030 if (*cur != '-')
1031 goto error;
1032 cur++;
1033
1034 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
1035 if ((ret != 0) || !VALID_DATE((&(dt->value.date))))
1036 goto error;
1037
1038 /* is it an xs:date? */
1039 RETURN_TYPE_IF_VALID(XML_SCHEMAS_DATE);
1040
1041 if (*cur != 'T')
1042 goto error;
1043 cur++;
1044
1045 /* it should be an xs:dateTime */
1046 ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
1047 if (ret != 0)
1048 goto error;
1049
1050 ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur);
1051 if ((ret != 0) || (*cur != 0) || !VALID_DATETIME((&(dt->value.date))))
1052 goto error;
1053
Daniel Veillard455cc072003-03-31 10:13:23 +00001054
Daniel Veillard070803b2002-05-03 07:29:38 +00001055 dt->type = XML_SCHEMAS_DATETIME;
1056
Daniel Veillard455cc072003-03-31 10:13:23 +00001057done:
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001058#if 1
1059 if ((type != XML_SCHEMAS_UNKNOWN) && (type != dt->type))
1060 goto error;
1061#else
1062 /*
1063 * insure the parsed type is equal to or less significant (right
1064 * truncated) than the desired type.
1065 */
1066 if ((type != XML_SCHEMAS_UNKNOWN) && (type != dt->type)) {
1067
1068 /* time only matches time */
1069 if ((type == XML_SCHEMAS_TIME) && (dt->type == XML_SCHEMAS_TIME))
1070 goto error;
1071
1072 if ((type == XML_SCHEMAS_DATETIME) &&
1073 ((dt->type != XML_SCHEMAS_DATE) ||
1074 (dt->type != XML_SCHEMAS_GYEARMONTH) ||
1075 (dt->type != XML_SCHEMAS_GYEAR)))
1076 goto error;
1077
1078 if ((type == XML_SCHEMAS_DATE) &&
1079 ((dt->type != XML_SCHEMAS_GYEAR) ||
1080 (dt->type != XML_SCHEMAS_GYEARMONTH)))
1081 goto error;
1082
1083 if ((type == XML_SCHEMAS_GYEARMONTH) && (dt->type != XML_SCHEMAS_GYEAR))
1084 goto error;
1085
1086 if ((type == XML_SCHEMAS_GMONTHDAY) && (dt->type != XML_SCHEMAS_GMONTH))
1087 goto error;
1088 }
Daniel Veillard455cc072003-03-31 10:13:23 +00001089#endif
1090
Daniel Veillard070803b2002-05-03 07:29:38 +00001091 if (val != NULL)
1092 *val = dt;
Daniel Veillard80b19092003-03-28 13:29:53 +00001093 else
1094 xmlSchemaFreeValue(dt);
Daniel Veillard070803b2002-05-03 07:29:38 +00001095
1096 return 0;
1097
1098error:
1099 if (dt != NULL)
1100 xmlSchemaFreeValue(dt);
1101 return 1;
1102}
1103
1104/**
Daniel Veillard5a872412002-05-22 06:40:27 +00001105 * xmlSchemaValidateDuration:
Daniel Veillard070803b2002-05-03 07:29:38 +00001106 * @type: the predefined type
1107 * @duration: string to analyze
1108 * @val: the return computed value
1109 *
1110 * Check that @duration conforms to the lexical space of the duration type.
1111 * if true a value is computed and returned in @val.
1112 *
1113 * Returns 0 if this validates, a positive error code number otherwise
1114 * and -1 in case of internal or API error.
1115 */
1116static int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00001117xmlSchemaValidateDuration (xmlSchemaTypePtr type ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +00001118 const xmlChar *duration, xmlSchemaValPtr *val) {
Daniel Veillard070803b2002-05-03 07:29:38 +00001119 const xmlChar *cur = duration;
1120 xmlSchemaValPtr dur;
1121 int isneg = 0;
1122 unsigned int seq = 0;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001123 double num;
1124 int num_type = 0; /* -1 = invalid, 0 = int, 1 = floating */
1125 const xmlChar desig[] = {'Y', 'M', 'D', 'H', 'M', 'S'};
1126 const double multi[] = { 0.0, 0.0, 86400.0, 3600.0, 60.0, 1.0, 0.0};
Daniel Veillard070803b2002-05-03 07:29:38 +00001127
1128 if (duration == NULL)
1129 return -1;
1130
1131 if (*cur == '-') {
1132 isneg = 1;
1133 cur++;
1134 }
1135
1136 /* duration must start with 'P' (after sign) */
1137 if (*cur++ != 'P')
1138 return 1;
1139
Daniel Veillard80b19092003-03-28 13:29:53 +00001140 if (*cur == 0)
1141 return 1;
1142
Daniel Veillard070803b2002-05-03 07:29:38 +00001143 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
1144 if (dur == NULL)
1145 return -1;
1146
1147 while (*cur != 0) {
Daniel Veillard070803b2002-05-03 07:29:38 +00001148
1149 /* input string should be empty or invalid date/time item */
1150 if (seq >= sizeof(desig))
1151 goto error;
1152
1153 /* T designator must be present for time items */
1154 if (*cur == 'T') {
1155 if (seq <= 3) {
1156 seq = 3;
1157 cur++;
1158 } else
1159 return 1;
1160 } else if (seq == 3)
1161 goto error;
1162
1163 /* parse the number portion of the item */
1164 PARSE_NUM(num, cur, num_type);
1165
1166 if ((num_type == -1) || (*cur == 0))
1167 goto error;
1168
1169 /* update duration based on item type */
1170 while (seq < sizeof(desig)) {
1171 if (*cur == desig[seq]) {
1172
1173 /* verify numeric type; only seconds can be float */
1174 if ((num_type != 0) && (seq < (sizeof(desig)-1)))
1175 goto error;
1176
1177 switch (seq) {
1178 case 0:
1179 dur->value.dur.mon = (long)num * 12;
1180 break;
1181 case 1:
1182 dur->value.dur.mon += (long)num;
1183 break;
1184 default:
1185 /* convert to seconds using multiplier */
1186 dur->value.dur.sec += num * multi[seq];
1187 seq++;
1188 break;
1189 }
1190
1191 break; /* exit loop */
1192 }
1193 /* no date designators found? */
1194 if (++seq == 3)
1195 goto error;
1196 }
1197 cur++;
1198 }
1199
1200 if (isneg) {
1201 dur->value.dur.mon = -dur->value.dur.mon;
1202 dur->value.dur.day = -dur->value.dur.day;
1203 dur->value.dur.sec = -dur->value.dur.sec;
1204 }
1205
1206 if (val != NULL)
1207 *val = dur;
Daniel Veillard80b19092003-03-28 13:29:53 +00001208 else
1209 xmlSchemaFreeValue(dur);
Daniel Veillard070803b2002-05-03 07:29:38 +00001210
1211 return 0;
1212
1213error:
1214 if (dur != NULL)
1215 xmlSchemaFreeValue(dur);
1216 return 1;
1217}
1218
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001219/**
1220 * xmlSchemaStrip:
1221 * @value: a value
1222 *
1223 * Removes the leading and ending spaces of a string
1224 *
1225 * Returns the new string or NULL if no change was required.
1226 */
1227static xmlChar *
1228xmlSchemaStrip(const xmlChar *value) {
1229 const xmlChar *start = value, *end, *f;
1230
1231 if (value == NULL) return(NULL);
1232 while ((*start != 0) && (IS_BLANK(*start))) start++;
1233 end = start;
1234 while (*end != 0) end++;
1235 f = end;
1236 end--;
1237 while ((end > start) && (IS_BLANK(*end))) end--;
1238 end++;
1239 if ((start == value) && (f == end)) return(NULL);
1240 return(xmlStrndup(start, end - start));
1241}
Daniel Veillard96a4b252003-02-06 08:22:32 +00001242
1243/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001244 * xmlSchemaCollapseString:
1245 * @value: a value
1246 *
1247 * Removes and normalize white spaces in the string
1248 *
1249 * Returns the new string or NULL if no change was required.
1250 */
1251static xmlChar *
1252xmlSchemaCollapseString(const xmlChar *value) {
1253 const xmlChar *start = value, *end, *f;
1254 xmlChar *g;
1255 int col = 0;
1256
1257 if (value == NULL) return(NULL);
1258 while ((*start != 0) && (IS_BLANK(*start))) start++;
1259 end = start;
1260 while (*end != 0) {
1261 if ((*end == ' ') && (IS_BLANK(end[1]))) {
1262 col = end - start;
1263 break;
1264 } else if ((*end == 0xa) || (*end == 0x9) || (*end == 0xd)) {
1265 col = end - start;
1266 break;
1267 }
1268 end++;
1269 }
1270 if (col == 0) {
1271 f = end;
1272 end--;
1273 while ((end > start) && (IS_BLANK(*end))) end--;
1274 end++;
1275 if ((start == value) && (f == end)) return(NULL);
1276 return(xmlStrndup(start, end - start));
1277 }
1278 start = xmlStrdup(start);
1279 if (start == NULL) return(NULL);
1280 g = (xmlChar *) (start + col);
1281 end = g;
1282 while (*end != 0) {
1283 if (IS_BLANK(*end)) {
1284 end++;
1285 while (IS_BLANK(*end)) end++;
1286 if (*end != 0)
1287 *g++ = ' ';
1288 } else
1289 *g++ = *end++;
1290 }
1291 *g = 0;
1292 return((xmlChar *) start);
1293}
1294
1295/**
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001296 * xmlSchemaValAtomicListNode:
1297 * @type: the predefined atomic type for a token in the list
1298 * @value: the list value to check
1299 * @ret: the return computed value
1300 * @node: the node containing the value
1301 *
1302 * Check that a value conforms to the lexical space of the predefined
1303 * list type. if true a value is computed and returned in @ret.
1304 *
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001305 * Returns the number of items if this validates, a negative error code
1306 * number otherwise
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001307 */
1308static int
1309xmlSchemaValAtomicListNode(xmlSchemaTypePtr type, const xmlChar *value,
1310 xmlSchemaValPtr *ret, xmlNodePtr node) {
1311 xmlChar *val, *cur, *endval;
1312 int nb_values = 0;
Daniel Veillard580ced82003-03-21 21:22:48 +00001313 int tmp = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001314
1315 if (value == NULL) {
1316 return(-1);
1317 }
1318 val = xmlStrdup(value);
1319 if (val == NULL) {
1320 return(-1);
1321 }
1322 cur = val;
1323 /*
1324 * Split the list
1325 */
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001326 while (IS_BLANK(*cur)) *cur++ = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001327 while (*cur != 0) {
1328 if (IS_BLANK(*cur)) {
1329 *cur = 0;
1330 cur++;
1331 while (IS_BLANK(*cur)) *cur++ = 0;
1332 } else {
1333 nb_values++;
1334 cur++;
1335 while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
1336 }
1337 }
1338 if (nb_values == 0) {
1339 if (ret != NULL) {
1340 TODO
1341 }
1342 xmlFree(val);
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001343 return(nb_values);
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001344 }
1345 endval = cur;
1346 cur = val;
1347 while ((*cur == 0) && (cur != endval)) cur++;
1348 while (cur != endval) {
1349 tmp = xmlSchemaValPredefTypeNode(type, cur, NULL, node);
1350 if (tmp != 0)
1351 break;
1352 while (*cur != 0) cur++;
1353 while ((*cur == 0) && (cur != endval)) cur++;
1354 }
1355 xmlFree(val);
1356 if (ret != NULL) {
1357 TODO
1358 }
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001359 if (tmp == 0)
1360 return(nb_values);
1361 return(-1);
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001362}
1363
1364/**
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001365 * xmlSchemaParseUInt:
1366 * @str: pointer to the string R/W
1367 * @llo: pointer to the low result
1368 * @lmi: pointer to the mid result
1369 * @lhi: pointer to the high result
1370 *
1371 * Parse an unsigned long into 3 fields.
1372 *
1373 * Returns the number of chars parsed or -1 if overflow of the capacity
1374 */
1375static int
1376xmlSchemaParseUInt(const xmlChar **str, unsigned long *llo,
1377 unsigned long *lmi, unsigned long *lhi) {
1378 unsigned long lo = 0, mi = 0, hi = 0;
1379 const xmlChar *tmp, *cur = *str;
1380 int ret = 0, i = 0;
1381
1382 while (*cur == '0') {
1383 ret++;
1384 cur++;
1385 }
1386 tmp = cur;
1387 while ((*tmp != 0) && (*tmp >= '0') && (*tmp <= '9')) {
1388 i++;tmp++;ret++;
1389 }
1390 if (i > 24) {
1391 *str = tmp;
1392 return(-1);
1393 }
1394 while (i > 16) {
1395 hi = hi * 10 + (*cur++ - '0');
1396 i--;
1397 }
1398 while (i > 8) {
1399 mi = mi * 10 + (*cur++ - '0');
1400 i--;
1401 }
1402 while (i > 0) {
1403 lo = lo * 10 + (*cur++ - '0');
1404 i--;
1405 }
1406
1407 *str = cur;
1408 *llo = lo;
1409 *lmi = mi;
1410 *lhi = hi;
1411 return(ret);
1412}
1413
1414/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001415 * xmlSchemaValAtomicType:
1416 * @type: the predefined type
1417 * @value: the value to check
1418 * @val: the return computed value
1419 * @node: the node containing the value
1420 * flags: flags to control the vlidation
1421 *
1422 * Check that a value conforms to the lexical space of the atomic type.
1423 * if true a value is computed and returned in @val.
1424 *
1425 * Returns 0 if this validates, a positive error code number otherwise
1426 * and -1 in case of internal or API error.
1427 */
1428static int
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001429xmlSchemaValAtomicType(xmlSchemaTypePtr type, const xmlChar * value,
1430 xmlSchemaValPtr * val, xmlNodePtr node, int flags)
1431{
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001432 xmlSchemaValPtr v;
1433 xmlChar *norm = NULL;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00001434 int ret = 0;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001435
1436 if (xmlSchemaTypesInitialized == 0)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001437 return (-1);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001438 if (type == NULL)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001439 return (-1);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001440
1441 if (val != NULL)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001442 *val = NULL;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001443 if ((flags == 0) && (value != NULL)) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001444 if ((type->flags != XML_SCHEMAS_STRING) &&
1445 (type->flags != XML_SCHEMAS_NORMSTRING)) {
1446 norm = xmlSchemaCollapseString(value);
1447 if (norm != NULL)
1448 value = norm;
1449 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001450 }
1451
1452 switch (type->flags) {
1453 case XML_SCHEMAS_UNKNOWN:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001454 if (type == xmlSchemaTypeAnyTypeDef)
1455 goto return0;
1456 goto error;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001457 case XML_SCHEMAS_STRING:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001458 goto return0;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001459 case XML_SCHEMAS_NORMSTRING:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001460 TODO goto return0;
1461 case XML_SCHEMAS_DECIMAL:{
1462 const xmlChar *cur = value, *tmp;
1463 unsigned int frac = 0, len, neg = 0;
1464 unsigned long base = 0;
1465
1466 if (cur == NULL)
1467 goto return1;
1468 if (*cur == '+')
1469 cur++;
1470 else if (*cur == '-') {
1471 neg = 1;
1472 cur++;
1473 }
1474 tmp = cur;
1475 while ((*cur >= '0') && (*cur <= '9')) {
1476 base = base * 10 + (*cur - '0');
1477 cur++;
1478 }
1479 len = cur - tmp;
1480 if (*cur == '.') {
1481 cur++;
1482 tmp = cur;
1483 while ((*cur >= '0') && (*cur <= '9')) {
1484 base = base * 10 + (*cur - '0');
1485 cur++;
1486 }
1487 frac = cur - tmp;
1488 }
1489 if (*cur != 0)
1490 goto return1;
1491 if (val != NULL) {
1492 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
1493 if (v != NULL) {
1494 v->value.decimal.lo = base;
1495 v->value.decimal.sign = neg;
1496 v->value.decimal.frac = frac;
1497 v->value.decimal.total = frac + len;
1498 *val = v;
1499 }
1500 }
1501 goto return0;
1502 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001503 case XML_SCHEMAS_TIME:
1504 case XML_SCHEMAS_GDAY:
1505 case XML_SCHEMAS_GMONTH:
1506 case XML_SCHEMAS_GMONTHDAY:
1507 case XML_SCHEMAS_GYEAR:
1508 case XML_SCHEMAS_GYEARMONTH:
1509 case XML_SCHEMAS_DATE:
1510 case XML_SCHEMAS_DATETIME:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001511 ret = xmlSchemaValidateDates(type->flags, value, val);
1512 break;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001513 case XML_SCHEMAS_DURATION:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001514 ret = xmlSchemaValidateDuration(type, value, val);
1515 break;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001516 case XML_SCHEMAS_FLOAT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001517 case XML_SCHEMAS_DOUBLE:{
1518 const xmlChar *cur = value;
1519 int neg = 0;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001520
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001521 if (cur == NULL)
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00001522 goto return1;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001523 if ((cur[0] == 'N') && (cur[1] == 'a') && (cur[2] == 'N')) {
1524 cur += 3;
1525 if (*cur != 0)
1526 goto return1;
1527 if (val != NULL) {
1528 if (type == xmlSchemaTypeFloatDef) {
1529 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1530 if (v != NULL) {
1531 v->value.f = (float) xmlXPathNAN;
1532 } else {
1533 xmlSchemaFreeValue(v);
1534 goto error;
1535 }
1536 } else {
1537 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1538 if (v != NULL) {
1539 v->value.d = xmlXPathNAN;
1540 } else {
1541 xmlSchemaFreeValue(v);
1542 goto error;
1543 }
1544 }
1545 *val = v;
1546 }
1547 goto return0;
1548 }
1549 if (*cur == '-') {
1550 neg = 1;
1551 cur++;
1552 }
1553 if ((cur[0] == 'I') && (cur[1] == 'N') && (cur[2] == 'F')) {
1554 cur += 3;
1555 if (*cur != 0)
1556 goto return1;
1557 if (val != NULL) {
1558 if (type == xmlSchemaTypeFloatDef) {
1559 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1560 if (v != NULL) {
1561 if (neg)
1562 v->value.f = (float) xmlXPathNINF;
1563 else
1564 v->value.f = (float) xmlXPathPINF;
1565 } else {
1566 xmlSchemaFreeValue(v);
1567 goto error;
1568 }
1569 } else {
1570 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1571 if (v != NULL) {
1572 if (neg)
1573 v->value.d = xmlXPathNINF;
1574 else
1575 v->value.d = xmlXPathPINF;
1576 } else {
1577 xmlSchemaFreeValue(v);
1578 goto error;
1579 }
1580 }
1581 *val = v;
1582 }
1583 goto return0;
1584 }
1585 if ((neg == 0) && (*cur == '+'))
1586 cur++;
1587 if ((cur[0] == 0) || (cur[0] == '+') || (cur[0] == '-'))
1588 goto return1;
1589 while ((*cur >= '0') && (*cur <= '9')) {
1590 cur++;
1591 }
1592 if (*cur == '.') {
1593 cur++;
1594 while ((*cur >= '0') && (*cur <= '9'))
1595 cur++;
1596 }
1597 if ((*cur == 'e') || (*cur == 'E')) {
1598 cur++;
1599 if ((*cur == '-') || (*cur == '+'))
1600 cur++;
1601 while ((*cur >= '0') && (*cur <= '9'))
1602 cur++;
1603 }
1604 if (*cur != 0)
1605 goto return1;
1606 if (val != NULL) {
1607 if (type == xmlSchemaTypeFloatDef) {
1608 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1609 if (v != NULL) {
1610 if (sscanf
1611 ((const char *) value, "%f",
1612 &(v->value.f)) == 1) {
1613 *val = v;
1614 } else {
1615 xmlGenericError(xmlGenericErrorContext,
1616 "failed to scanf float %s\n",
1617 value);
1618 xmlSchemaFreeValue(v);
1619 goto return1;
1620 }
1621 } else {
1622 goto error;
1623 }
1624 } else {
1625 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1626 if (v != NULL) {
1627 if (sscanf
1628 ((const char *) value, "%lf",
1629 &(v->value.d)) == 1) {
1630 *val = v;
1631 } else {
1632 xmlGenericError(xmlGenericErrorContext,
1633 "failed to scanf double %s\n",
1634 value);
1635 xmlSchemaFreeValue(v);
1636 goto return1;
1637 }
1638 } else {
1639 goto error;
1640 }
1641 }
1642 }
1643 goto return0;
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00001644 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00001645 case XML_SCHEMAS_BOOLEAN:{
1646 const xmlChar *cur = value;
1647
1648 if ((cur[0] == '0') && (cur[1] == 0))
1649 ret = 0;
1650 else if ((cur[0] == '1') && (cur[1] == 0))
1651 ret = 1;
1652 else if ((cur[0] == 't') && (cur[1] == 'r')
1653 && (cur[2] == 'u') && (cur[3] == 'e')
1654 && (cur[4] == 0))
1655 ret = 1;
1656 else if ((cur[0] == 'f') && (cur[1] == 'a')
1657 && (cur[2] == 'l') && (cur[3] == 's')
1658 && (cur[4] == 'e') && (cur[5] == 0))
1659 ret = 0;
1660 else
1661 goto return1;
1662 if (val != NULL) {
1663 v = xmlSchemaNewValue(XML_SCHEMAS_BOOLEAN);
1664 if (v != NULL) {
1665 v->value.b = ret;
1666 *val = v;
1667 } else {
1668 goto error;
1669 }
1670 }
1671 goto return0;
1672 }
1673 case XML_SCHEMAS_TOKEN:{
1674 const xmlChar *cur = value;
1675
1676 if (IS_BLANK(*cur))
1677 goto return1;
1678
1679 while (*cur != 0) {
1680 if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) {
1681 goto return1;
1682 } else if (*cur == ' ') {
1683 cur++;
1684 if (*cur == 0)
1685 goto return1;
1686 if (*cur == ' ')
1687 goto return1;
1688 } else {
1689 cur++;
1690 }
1691 }
1692 if (val != NULL) {
1693 v = xmlSchemaNewValue(XML_SCHEMAS_TOKEN);
1694 if (v != NULL) {
1695 v->value.str = xmlStrdup(value);
1696 *val = v;
1697 } else {
1698 goto error;
1699 }
1700 }
1701 goto return0;
1702 }
1703 case XML_SCHEMAS_LANGUAGE:
1704 if (xmlCheckLanguageID(value) == 1) {
1705 if (val != NULL) {
1706 v = xmlSchemaNewValue(XML_SCHEMAS_LANGUAGE);
1707 if (v != NULL) {
1708 v->value.str = xmlStrdup(value);
1709 *val = v;
1710 } else {
1711 goto error;
1712 }
1713 }
1714 goto return0;
1715 }
1716 goto return1;
1717 case XML_SCHEMAS_NMTOKEN:
1718 if (xmlValidateNMToken(value, 1) == 0) {
1719 if (val != NULL) {
1720 v = xmlSchemaNewValue(XML_SCHEMAS_NMTOKEN);
1721 if (v != NULL) {
1722 v->value.str = xmlStrdup(value);
1723 *val = v;
1724 } else {
1725 goto error;
1726 }
1727 }
1728 goto return0;
1729 }
1730 goto return1;
1731 case XML_SCHEMAS_NMTOKENS:
1732 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeNmtokenDef,
1733 value, val, node);
1734 if (ret > 0)
1735 ret = 0;
1736 else
1737 ret = 1;
1738 goto done;
1739 case XML_SCHEMAS_NAME:
1740 ret = xmlValidateName(value, 1);
1741 if ((ret == 0) && (val != NULL)) {
1742 TODO;
1743 }
1744 goto done;
1745 case XML_SCHEMAS_QNAME:{
1746 xmlChar *uri = NULL;
1747 xmlChar *local = NULL;
1748
1749 ret = xmlValidateQName(value, 1);
1750 if ((ret == 0) && (node != NULL)) {
1751 xmlChar *prefix;
1752
1753 local = xmlSplitQName2(value, &prefix);
1754 if (prefix != NULL) {
1755 xmlNsPtr ns;
1756
1757 ns = xmlSearchNs(node->doc, node, prefix);
1758 if (ns == NULL)
1759 ret = 1;
1760 else if (val != NULL)
1761 uri = xmlStrdup(ns->href);
1762 }
1763 if ((local != NULL) && ((val == NULL) || (ret != 0)))
1764 xmlFree(local);
1765 if (prefix != NULL)
1766 xmlFree(prefix);
1767 }
1768 if ((ret == 0) && (val != NULL)) {
1769 v = xmlSchemaNewValue(XML_SCHEMAS_QNAME);
1770 if (v != NULL) {
1771 if (local != NULL)
1772 v->value.qname.name = local;
1773 else
1774 v->value.qname.name = xmlStrdup(value);
1775 if (uri != NULL)
1776 v->value.qname.uri = uri;
1777
1778 *val = v;
1779 } else {
1780 if (local != NULL)
1781 xmlFree(local);
1782 if (uri != NULL)
1783 xmlFree(uri);
1784 goto error;
1785 }
1786 }
1787 goto done;
1788 }
1789 case XML_SCHEMAS_NCNAME:
1790 ret = xmlValidateNCName(value, 1);
1791 if ((ret == 0) && (val != NULL)) {
1792 v = xmlSchemaNewValue(XML_SCHEMAS_NCNAME);
1793 if (v != NULL) {
1794 v->value.str = xmlStrdup(value);
1795 *val = v;
1796 } else {
1797 goto error;
1798 }
1799 }
1800 goto done;
1801 case XML_SCHEMAS_ID:
1802 ret = xmlValidateNCName(value, 1);
1803 if ((ret == 0) && (val != NULL)) {
1804 v = xmlSchemaNewValue(XML_SCHEMAS_ID);
1805 if (v != NULL) {
1806 v->value.str = xmlStrdup(value);
1807 *val = v;
1808 } else {
1809 goto error;
1810 }
1811 }
1812 if ((ret == 0) && (node != NULL) &&
1813 (node->type == XML_ATTRIBUTE_NODE)) {
1814 xmlAttrPtr attr = (xmlAttrPtr) node;
1815
1816 /*
1817 * NOTE: the IDness might have already be declared in the DTD
1818 */
1819 if (attr->atype != XML_ATTRIBUTE_ID) {
1820 xmlIDPtr res;
1821 xmlChar *strip;
1822
1823 strip = xmlSchemaStrip(value);
1824 if (strip != NULL) {
1825 res = xmlAddID(NULL, node->doc, strip, attr);
1826 xmlFree(strip);
1827 } else
1828 res = xmlAddID(NULL, node->doc, value, attr);
1829 if (res == NULL) {
1830 ret = 2;
1831 } else {
1832 attr->atype = XML_ATTRIBUTE_ID;
1833 }
1834 }
1835 }
1836 goto done;
1837 case XML_SCHEMAS_IDREF:
1838 ret = xmlValidateNCName(value, 1);
1839 if ((ret == 0) && (val != NULL)) {
1840 TODO;
1841 }
1842 if ((ret == 0) && (node != NULL) &&
1843 (node->type == XML_ATTRIBUTE_NODE)) {
1844 xmlAttrPtr attr = (xmlAttrPtr) node;
1845 xmlChar *strip;
1846
1847 strip = xmlSchemaStrip(value);
1848 if (strip != NULL) {
1849 xmlAddRef(NULL, node->doc, strip, attr);
1850 xmlFree(strip);
1851 } else
1852 xmlAddRef(NULL, node->doc, value, attr);
1853 attr->atype = XML_ATTRIBUTE_IDREF;
1854 }
1855 goto done;
1856 case XML_SCHEMAS_IDREFS:
1857 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeIdrefDef,
1858 value, val, node);
1859 if (ret < 0)
1860 ret = 2;
1861 else
1862 ret = 0;
1863 if ((ret == 0) && (node != NULL) &&
1864 (node->type == XML_ATTRIBUTE_NODE)) {
1865 xmlAttrPtr attr = (xmlAttrPtr) node;
1866
1867 attr->atype = XML_ATTRIBUTE_IDREFS;
1868 }
1869 goto done;
1870 case XML_SCHEMAS_ENTITY:{
1871 xmlChar *strip;
1872
1873 ret = xmlValidateNCName(value, 1);
1874 if ((node == NULL) || (node->doc == NULL))
1875 ret = 3;
1876 if (ret == 0) {
1877 xmlEntityPtr ent;
1878
1879 strip = xmlSchemaStrip(value);
1880 if (strip != NULL) {
1881 ent = xmlGetDocEntity(node->doc, strip);
1882 xmlFree(strip);
1883 } else {
1884 ent = xmlGetDocEntity(node->doc, value);
1885 }
1886 if ((ent == NULL) ||
1887 (ent->etype !=
1888 XML_EXTERNAL_GENERAL_UNPARSED_ENTITY))
1889 ret = 4;
1890 }
1891 if ((ret == 0) && (val != NULL)) {
1892 TODO;
1893 }
1894 if ((ret == 0) && (node != NULL) &&
1895 (node->type == XML_ATTRIBUTE_NODE)) {
1896 xmlAttrPtr attr = (xmlAttrPtr) node;
1897
1898 attr->atype = XML_ATTRIBUTE_ENTITY;
1899 }
1900 goto done;
1901 }
1902 case XML_SCHEMAS_ENTITIES:
1903 if ((node == NULL) || (node->doc == NULL))
1904 goto return3;
1905 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeEntityDef,
1906 value, val, node);
1907 if (ret <= 0)
1908 ret = 1;
1909 else
1910 ret = 0;
1911 if ((ret == 0) && (node != NULL) &&
1912 (node->type == XML_ATTRIBUTE_NODE)) {
1913 xmlAttrPtr attr = (xmlAttrPtr) node;
1914
1915 attr->atype = XML_ATTRIBUTE_ENTITIES;
1916 }
1917 goto done;
1918 case XML_SCHEMAS_NOTATION:{
1919 xmlChar *uri = NULL;
1920 xmlChar *local = NULL;
1921
1922 ret = xmlValidateQName(value, 1);
1923 if ((ret == 0) && (node != NULL)) {
1924 xmlChar *prefix;
1925
1926 local = xmlSplitQName2(value, &prefix);
1927 if (prefix != NULL) {
1928 xmlNsPtr ns;
1929
1930 ns = xmlSearchNs(node->doc, node, prefix);
1931 if (ns == NULL)
1932 ret = 1;
1933 else if (val != NULL)
1934 uri = xmlStrdup(ns->href);
1935 }
1936 if ((local != NULL) && ((val == NULL) || (ret != 0)))
1937 xmlFree(local);
1938 if (prefix != NULL)
1939 xmlFree(prefix);
1940 }
1941 if ((node == NULL) || (node->doc == NULL))
1942 ret = 3;
1943 if (ret == 0) {
1944 ret = xmlValidateNotationUse(NULL, node->doc, value);
1945 if (ret == 1)
1946 ret = 0;
1947 else
1948 ret = 1;
1949 }
1950 if ((ret == 0) && (val != NULL)) {
1951 v = xmlSchemaNewValue(XML_SCHEMAS_NOTATION);
1952 if (v != NULL) {
1953 if (local != NULL)
1954 v->value.qname.name = local;
1955 else
1956 v->value.qname.name = xmlStrdup(value);
1957 if (uri != NULL)
1958 v->value.qname.uri = uri;
1959
1960 *val = v;
1961 } else {
1962 if (local != NULL)
1963 xmlFree(local);
1964 if (uri != NULL)
1965 xmlFree(uri);
1966 goto error;
1967 }
1968 }
1969 goto done;
1970 }
1971 case XML_SCHEMAS_ANYURI:{
1972 xmlURIPtr uri;
1973
1974 uri = xmlParseURI((const char *) value);
1975 if (uri == NULL)
1976 goto return1;
1977 if (val != NULL) {
1978 TODO;
1979 }
1980 xmlFreeURI(uri);
1981 goto return0;
1982 }
1983 case XML_SCHEMAS_HEXBINARY:{
1984 const xmlChar *cur = value;
1985 xmlChar *base;
1986 int total, i = 0;
1987
1988 if (cur == NULL)
1989 goto return1;
1990
1991 while (((*cur >= '0') && (*cur <= '9')) ||
1992 ((*cur >= 'A') && (*cur <= 'F')) ||
1993 ((*cur >= 'a') && (*cur <= 'f'))) {
1994 i++;
1995 cur++;
1996 }
1997
1998 if (*cur != 0)
1999 goto return1;
2000 if ((i % 2) != 0)
2001 goto return1;
2002
2003 if (val != NULL) {
2004
2005 v = xmlSchemaNewValue(XML_SCHEMAS_HEXBINARY);
2006 if (v == NULL)
2007 goto error;
2008
2009 cur = xmlStrdup(value);
2010 if (cur == NULL) {
2011 xmlFree(v);
2012 goto return1;
2013 }
2014
2015 total = i / 2; /* number of octets */
2016
2017 base = (xmlChar *) cur;
2018 while (i-- > 0) {
2019 if (*base >= 'a')
2020 *base = *base - ('a' - 'A');
2021 base++;
2022 }
2023
2024 v->value.hex.str = (xmlChar *) cur;
2025 v->value.hex.total = total;
2026 *val = v;
2027 }
2028 goto return0;
2029 }
2030 case XML_SCHEMAS_BASE64BINARY:{
2031 /* ISSUE:
2032 *
2033 * Ignore all stray characters? (yes, currently)
2034 * Worry about long lines? (no, currently)
2035 *
2036 * rfc2045.txt:
2037 *
2038 * "The encoded output stream must be represented in lines of
2039 * no more than 76 characters each. All line breaks or other
2040 * characters not found in Table 1 must be ignored by decoding
2041 * software. In base64 data, characters other than those in
2042 * Table 1, line breaks, and other white space probably
2043 * indicate a transmission error, about which a warning
2044 * message or even a message rejection might be appropriate
2045 * under some circumstances." */
2046 const xmlChar *cur = value;
2047 xmlChar *base;
2048 int total, i = 0, pad = 0;
2049
2050 if (cur == NULL)
2051 goto return1;
2052
2053 for (; *cur; ++cur) {
2054 int decc;
2055
2056 decc = _xmlSchemaBase64Decode(*cur);
2057 if (decc < 0) ;
2058 else if (decc < 64)
2059 i++;
2060 else
2061 break;
2062 }
2063 for (; *cur; ++cur) {
2064 int decc;
2065
2066 decc = _xmlSchemaBase64Decode(*cur);
2067 if (decc < 0) ;
2068 else if (decc < 64)
2069 goto return1;
2070 if (decc == 64)
2071 pad++;
2072 }
2073
2074 /* rfc2045.txt: "Special processing is performed if fewer than
2075 * 24 bits are available at the end of the data being encoded.
2076 * A full encoding quantum is always completed at the end of a
2077 * body. When fewer than 24 input bits are available in an
2078 * input group, zero bits are added (on the right) to form an
2079 * integral number of 6-bit groups. Padding at the end of the
2080 * data is performed using the "=" character. Since all
2081 * base64 input is an integral number of octets, only the
2082 * following cases can arise: (1) the final quantum of
2083 * encoding input is an integral multiple of 24 bits; here,
2084 * the final unit of encoded output will be an integral
2085 * multiple ofindent: Standard input:701: Warning:old style
2086 * assignment ambiguity in "=*". Assuming "= *" 4 characters
2087 * with no "=" padding, (2) the final
2088 * quantum of encoding input is exactly 8 bits; here, the
2089 * final unit of encoded output will be two characters
2090 * followed by two "=" padding characters, or (3) the final
2091 * quantum of encoding input is exactly 16 bits; here, the
2092 * final unit of encoded output will be three characters
2093 * followed by one "=" padding character." */
2094
2095 total = 3 * (i / 4);
2096 if (pad == 0) {
2097 if (i % 4 != 0)
2098 goto return1;
2099 } else if (pad == 1) {
2100 int decc;
2101
2102 if (i % 4 != 3)
2103 goto return1;
2104 for (decc = _xmlSchemaBase64Decode(*cur);
2105 (decc < 0) || (decc > 63);
2106 decc = _xmlSchemaBase64Decode(*cur))
2107 --cur;
2108 /* 16bits in 24bits means 2 pad bits: nnnnnn nnmmmm mmmm00*/
2109 /* 00111100 -> 0x3c */
2110 if (decc & ~0x3c)
2111 goto return1;
2112 total += 2;
2113 } else if (pad == 2) {
2114 int decc;
2115
2116 if (i % 4 != 2)
2117 goto return1;
2118 for (decc = _xmlSchemaBase64Decode(*cur);
2119 (decc < 0) || (decc > 63);
2120 decc = _xmlSchemaBase64Decode(*cur))
2121 --cur;
2122 /* 8bits in 12bits means 4 pad bits: nnnnnn nn0000 */
2123 /* 00110000 -> 0x30 */
2124 if (decc & ~0x30)
2125 goto return1;
2126 total += 1;
2127 } else
2128 goto return1;
2129
2130 if (val != NULL) {
2131 v = xmlSchemaNewValue(XML_SCHEMAS_BASE64BINARY);
2132 if (v == NULL)
2133 goto error;
2134 base =
2135 (xmlChar *) xmlMallocAtomic((i + pad + 1) *
2136 sizeof(xmlChar));
2137 if (base == NULL) {
2138 xmlGenericError(xmlGenericErrorContext,
2139 "malloc of %ld byte failed\n",
2140 (i + pad +
2141 1) * (long) sizeof(xmlChar));
2142 xmlFree(v);
2143 goto return1;
2144 }
2145 v->value.base64.str = base;
2146 for (cur = value; *cur; ++cur)
2147 if (_xmlSchemaBase64Decode(*cur) >= 0) {
2148 *base = *cur;
2149 ++base;
2150 }
2151 *base = 0;
2152 v->value.base64.total = total;
2153 *val = v;
2154 }
2155 goto return0;
2156 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002157 case XML_SCHEMAS_INTEGER:
2158 case XML_SCHEMAS_PINTEGER:
2159 case XML_SCHEMAS_NPINTEGER:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002160 case XML_SCHEMAS_NINTEGER:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002161 case XML_SCHEMAS_NNINTEGER:{
2162 const xmlChar *cur = value;
2163 unsigned long lo, mi, hi;
2164 int sign = 0;
2165
2166 if (cur == NULL)
2167 goto return1;
2168 if (*cur == '-') {
2169 sign = 1;
2170 cur++;
2171 } else if (*cur == '+')
2172 cur++;
2173 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2174 if (ret == 0)
2175 goto return1;
2176 if (*cur != 0)
2177 goto return1;
2178 if (type->flags == XML_SCHEMAS_NPINTEGER) {
2179 if ((sign == 0) &&
2180 ((hi != 0) || (mi != 0) || (lo != 0)))
2181 goto return1;
2182 } else if (type->flags == XML_SCHEMAS_PINTEGER) {
2183 if (sign == 1)
2184 goto return1;
2185 if ((hi == 0) && (mi == 0) && (lo == 0))
2186 goto return1;
2187 } else if (type->flags == XML_SCHEMAS_NINTEGER) {
2188 if (sign == 0)
2189 goto return1;
2190 if ((hi == 0) && (mi == 0) && (lo == 0))
2191 goto return1;
2192 } else if (type->flags == XML_SCHEMAS_NNINTEGER) {
2193 if ((sign == 1) &&
2194 ((hi != 0) || (mi != 0) || (lo != 0)))
2195 goto return1;
2196 }
2197 /*
2198 * We can store a value only if no overflow occured
2199 */
2200 if ((ret > 0) && (val != NULL)) {
2201 v = xmlSchemaNewValue(type->flags);
2202 if (v != NULL) {
2203 v->value.decimal.lo = lo;
2204 v->value.decimal.mi = lo;
2205 v->value.decimal.hi = lo;
2206 v->value.decimal.sign = sign;
2207 v->value.decimal.frac = 0;
2208 v->value.decimal.total = cur - value;
2209 *val = v;
2210 }
2211 }
2212 goto return0;
2213 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002214 case XML_SCHEMAS_LONG:
2215 case XML_SCHEMAS_BYTE:
2216 case XML_SCHEMAS_SHORT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002217 case XML_SCHEMAS_INT:{
2218 const xmlChar *cur = value;
2219 unsigned long lo, mi, hi;
2220 int total = 0;
2221 int sign = 0;
2222
2223 if (cur == NULL)
2224 goto return1;
2225 if (*cur == '-') {
2226 sign = 1;
2227 cur++;
2228 } else if (*cur == '+')
2229 cur++;
2230 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2231 if (ret <= 0)
2232 goto return1;
2233 if (*cur != 0)
2234 goto return1;
2235 if (type->flags == XML_SCHEMAS_LONG) {
2236 if (hi >= 922) {
2237 if (hi > 922)
2238 goto return1;
2239 if (mi >= 33720368) {
2240 if (mi > 33720368)
2241 goto return1;
2242 if ((sign == 0) && (lo > 54775807))
2243 goto return1;
2244 if ((sign == 1) && (lo > 54775808))
2245 goto return1;
2246 }
2247 }
2248 } else if (type->flags == XML_SCHEMAS_INT) {
2249 if (hi != 0)
2250 goto return1;
2251 if (mi >= 21) {
2252 if (mi > 21)
2253 goto return1;
2254 if ((sign == 0) && (lo > 47483647))
2255 goto return1;
2256 if ((sign == 1) && (lo > 47483648))
2257 goto return1;
2258 }
2259 } else if (type->flags == XML_SCHEMAS_SHORT) {
2260 if ((mi != 0) || (hi != 0))
2261 goto return1;
2262 if ((sign == 1) && (lo > 32768))
2263 goto return1;
2264 if ((sign == 0) && (lo > 32767))
2265 goto return1;
2266 } else if (type->flags == XML_SCHEMAS_BYTE) {
2267 if ((mi != 0) || (hi != 0))
2268 goto return1;
2269 if ((sign == 1) && (lo > 128))
2270 goto return1;
2271 if ((sign == 0) && (lo > 127))
2272 goto return1;
2273 }
2274 if (val != NULL) {
2275 v = xmlSchemaNewValue(type->flags);
2276 if (v != NULL) {
2277 v->value.decimal.lo = lo;
2278 v->value.decimal.mi = lo;
2279 v->value.decimal.hi = lo;
2280 v->value.decimal.sign = sign;
2281 v->value.decimal.frac = 0;
2282 v->value.decimal.total = total;
2283 *val = v;
2284 }
2285 }
2286 goto return0;
2287 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002288 case XML_SCHEMAS_UINT:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002289 case XML_SCHEMAS_ULONG:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002290 case XML_SCHEMAS_USHORT:
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002291 case XML_SCHEMAS_UBYTE:{
2292 const xmlChar *cur = value;
2293 unsigned long lo, mi, hi;
2294 int total = 0;
2295
2296 if (cur == NULL)
2297 goto return1;
2298 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2299 if (ret <= 0)
2300 goto return1;
2301 if (*cur != 0)
2302 goto return1;
2303 if (type->flags == XML_SCHEMAS_ULONG) {
2304 if (hi >= 1844) {
2305 if (hi > 1844)
2306 goto return1;
2307 if (mi >= 67440737) {
2308 if (mi > 67440737)
2309 goto return1;
2310 if (lo > 9551615)
2311 goto return1;
2312 }
2313 }
2314 } else if (type->flags == XML_SCHEMAS_UINT) {
2315 if (hi != 0)
2316 goto return1;
2317 if (mi >= 42) {
2318 if (mi > 42)
2319 goto return1;
2320 if (lo > 94967295)
2321 goto return1;
2322 }
2323 } else if (type->flags == XML_SCHEMAS_USHORT) {
2324 if ((mi != 0) || (hi != 0))
2325 goto return1;
2326 if (lo > 65535)
2327 goto return1;
2328 } else if (type->flags == XML_SCHEMAS_UBYTE) {
2329 if ((mi != 0) || (hi != 0))
2330 goto return1;
2331 if (lo > 255)
2332 goto return1;
2333 }
2334 if (val != NULL) {
2335 v = xmlSchemaNewValue(type->flags);
2336 if (v != NULL) {
2337 v->value.decimal.lo = lo;
2338 v->value.decimal.mi = mi;
2339 v->value.decimal.hi = hi;
2340 v->value.decimal.sign = 0;
2341 v->value.decimal.frac = 0;
2342 v->value.decimal.total = total;
2343 *val = v;
2344 }
2345 }
2346 goto return0;
2347 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002348 }
2349
Daniel Veillard1ac24d32003-08-27 14:15:15 +00002350 done:
2351 if (norm != NULL)
2352 xmlFree(norm);
2353 return (ret);
2354 return3:
2355 if (norm != NULL)
2356 xmlFree(norm);
2357 return (3);
2358 return1:
2359 if (norm != NULL)
2360 xmlFree(norm);
2361 return (1);
2362 return0:
2363 if (norm != NULL)
2364 xmlFree(norm);
2365 return (0);
2366 error:
2367 if (norm != NULL)
2368 xmlFree(norm);
2369 return (-1);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002370}
2371
2372/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002373 * xmlSchemaValPredefTypeNode:
Daniel Veillard4255d502002-04-16 15:50:10 +00002374 * @type: the predefined type
2375 * @value: the value to check
2376 * @val: the return computed value
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002377 * @node: the node containing the value
Daniel Veillard4255d502002-04-16 15:50:10 +00002378 *
2379 * Check that a value conforms to the lexical space of the predefined type.
2380 * if true a value is computed and returned in @val.
2381 *
2382 * Returns 0 if this validates, a positive error code number otherwise
2383 * and -1 in case of internal or API error.
2384 */
2385int
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002386xmlSchemaValPredefTypeNode(xmlSchemaTypePtr type, const xmlChar *value,
2387 xmlSchemaValPtr *val, xmlNodePtr node) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002388 return(xmlSchemaValAtomicType(type, value, val, node, 0));
Daniel Veillard4255d502002-04-16 15:50:10 +00002389}
2390
2391/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002392 * xmlSchemaValidatePredefinedType:
2393 * @type: the predefined type
2394 * @value: the value to check
2395 * @val: the return computed value
2396 *
2397 * Check that a value conforms to the lexical space of the predefined type.
2398 * if true a value is computed and returned in @val.
2399 *
2400 * Returns 0 if this validates, a positive error code number otherwise
2401 * and -1 in case of internal or API error.
2402 */
2403int
2404xmlSchemaValidatePredefinedType(xmlSchemaTypePtr type, const xmlChar *value,
2405 xmlSchemaValPtr *val) {
2406 return(xmlSchemaValPredefTypeNode(type, value, val, NULL));
2407}
2408
2409/**
Daniel Veillard4255d502002-04-16 15:50:10 +00002410 * xmlSchemaCompareDecimals:
2411 * @x: a first decimal value
2412 * @y: a second decimal value
2413 *
2414 * Compare 2 decimals
2415 *
2416 * Returns -1 if x < y, 0 if x == y, 1 if x > y and -2 in case of error
2417 */
2418static int
2419xmlSchemaCompareDecimals(xmlSchemaValPtr x, xmlSchemaValPtr y)
2420{
2421 xmlSchemaValPtr swp;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002422 int order = 1, p;
Daniel Veillard4255d502002-04-16 15:50:10 +00002423 unsigned long tmp;
2424
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002425 if ((x->value.decimal.sign) &&
2426 ((x->value.decimal.lo != 0) ||
2427 (x->value.decimal.mi != 0) ||
2428 (x->value.decimal.hi != 0))) {
2429 if ((y->value.decimal.sign) &&
2430 ((y->value.decimal.lo != 0) ||
2431 (y->value.decimal.mi != 0) ||
2432 (y->value.decimal.hi != 0)))
Daniel Veillard80b19092003-03-28 13:29:53 +00002433 order = -1;
2434 else
2435 return (-1);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002436 } else if ((y->value.decimal.sign) &&
2437 ((y->value.decimal.lo != 0) ||
2438 (y->value.decimal.mi != 0) ||
2439 (y->value.decimal.hi != 0))) {
Daniel Veillard4255d502002-04-16 15:50:10 +00002440 return (1);
Daniel Veillard80b19092003-03-28 13:29:53 +00002441 }
Daniel Veillard4255d502002-04-16 15:50:10 +00002442 if (x->value.decimal.frac == y->value.decimal.frac) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002443 if (x->value.decimal.hi < y->value.decimal.hi)
2444 return (-order);
2445 if (x->value.decimal.hi < y->value.decimal.hi)
2446 return (order);
2447 if (x->value.decimal.mi < y->value.decimal.mi)
2448 return (-order);
2449 if (x->value.decimal.mi < y->value.decimal.mi)
2450 return (order);
2451 if (x->value.decimal.lo < y->value.decimal.lo)
Daniel Veillard80b19092003-03-28 13:29:53 +00002452 return (-order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002453 if (x->value.decimal.lo > y->value.decimal.lo)
Daniel Veillard80b19092003-03-28 13:29:53 +00002454 return(order);
2455 return(0);
Daniel Veillard4255d502002-04-16 15:50:10 +00002456 }
2457 if (y->value.decimal.frac > x->value.decimal.frac) {
2458 swp = y;
2459 y = x;
2460 x = swp;
2461 order = -order;
2462 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002463 p = powten[x->value.decimal.frac - y->value.decimal.frac];
2464 tmp = x->value.decimal.lo / p;
2465 if (tmp > y->value.decimal.lo)
Daniel Veillard4255d502002-04-16 15:50:10 +00002466 return (order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002467 if (tmp < y->value.decimal.lo)
Daniel Veillard4255d502002-04-16 15:50:10 +00002468 return (-order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002469 tmp = y->value.decimal.lo * p;
2470 if (x->value.decimal.lo < tmp)
Daniel Veillard4255d502002-04-16 15:50:10 +00002471 return (-order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002472 if (x->value.decimal.lo == tmp)
Daniel Veillard4255d502002-04-16 15:50:10 +00002473 return (0);
2474 return (order);
2475}
2476
2477/**
Daniel Veillard070803b2002-05-03 07:29:38 +00002478 * xmlSchemaCompareDurations:
2479 * @x: a first duration value
2480 * @y: a second duration value
2481 *
2482 * Compare 2 durations
2483 *
2484 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
2485 * case of error
2486 */
2487static int
2488xmlSchemaCompareDurations(xmlSchemaValPtr x, xmlSchemaValPtr y)
2489{
2490 long carry, mon, day;
2491 double sec;
Daniel Veillard80b19092003-03-28 13:29:53 +00002492 int invert = 1;
2493 long xmon, xday, myear, minday, maxday;
Daniel Veillard070803b2002-05-03 07:29:38 +00002494 static const long dayRange [2][12] = {
2495 { 0, 28, 59, 89, 120, 150, 181, 212, 242, 273, 303, 334, },
2496 { 0, 31, 62, 92, 123, 153, 184, 215, 245, 276, 306, 337} };
2497
2498 if ((x == NULL) || (y == NULL))
Daniel Veillard5a872412002-05-22 06:40:27 +00002499 return -2;
Daniel Veillard070803b2002-05-03 07:29:38 +00002500
2501 /* months */
2502 mon = x->value.dur.mon - y->value.dur.mon;
2503
2504 /* seconds */
2505 sec = x->value.dur.sec - y->value.dur.sec;
2506 carry = (long)sec / SECS_PER_DAY;
2507 sec -= (double)(carry * SECS_PER_DAY);
2508
2509 /* days */
2510 day = x->value.dur.day - y->value.dur.day + carry;
2511
2512 /* easy test */
2513 if (mon == 0) {
2514 if (day == 0)
2515 if (sec == 0.0)
2516 return 0;
2517 else if (sec < 0.0)
2518 return -1;
2519 else
2520 return 1;
2521 else if (day < 0)
2522 return -1;
2523 else
2524 return 1;
2525 }
2526
2527 if (mon > 0) {
2528 if ((day >= 0) && (sec >= 0.0))
2529 return 1;
2530 else {
2531 xmon = mon;
2532 xday = -day;
2533 }
2534 } else if ((day <= 0) && (sec <= 0.0)) {
2535 return -1;
2536 } else {
Daniel Veillard80b19092003-03-28 13:29:53 +00002537 invert = -1;
Daniel Veillard070803b2002-05-03 07:29:38 +00002538 xmon = -mon;
2539 xday = day;
2540 }
2541
2542 myear = xmon / 12;
Daniel Veillard80b19092003-03-28 13:29:53 +00002543 if (myear == 0) {
2544 minday = 0;
2545 maxday = 0;
2546 } else {
2547 maxday = 366 * ((myear + 3) / 4) +
2548 365 * ((myear - 1) % 4);
2549 minday = maxday - 1;
2550 }
2551
Daniel Veillard070803b2002-05-03 07:29:38 +00002552 xmon = xmon % 12;
2553 minday += dayRange[0][xmon];
2554 maxday += dayRange[1][xmon];
2555
Daniel Veillard80b19092003-03-28 13:29:53 +00002556 if ((maxday == minday) && (maxday == xday))
2557 return(0); /* can this really happen ? */
Daniel Veillard070803b2002-05-03 07:29:38 +00002558 if (maxday < xday)
Daniel Veillard80b19092003-03-28 13:29:53 +00002559 return(-invert);
2560 if (minday > xday)
2561 return(invert);
Daniel Veillard070803b2002-05-03 07:29:38 +00002562
2563 /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00002564 return 2;
2565}
2566
2567/*
2568 * macros for adding date/times and durations
2569 */
2570#define FQUOTIENT(a,b) (floor(((double)a/(double)b)))
2571#define MODULO(a,b) (a - FQUOTIENT(a,b) * b)
2572#define FQUOTIENT_RANGE(a,low,high) (FQUOTIENT((a-low),(high-low)))
2573#define MODULO_RANGE(a,low,high) ((MODULO((a-low),(high-low)))+low)
2574
2575/**
2576 * _xmlSchemaDateAdd:
2577 * @dt: an #xmlSchemaValPtr
2578 * @dur: an #xmlSchemaValPtr of type #XS_DURATION
2579 *
2580 * Compute a new date/time from @dt and @dur. This function assumes @dt
2581 * is either #XML_SCHEMAS_DATETIME, #XML_SCHEMAS_DATE, #XML_SCHEMAS_GYEARMONTH,
2582 * or #XML_SCHEMAS_GYEAR.
2583 *
2584 * Returns date/time pointer or NULL.
2585 */
2586static xmlSchemaValPtr
2587_xmlSchemaDateAdd (xmlSchemaValPtr dt, xmlSchemaValPtr dur)
2588{
2589 xmlSchemaValPtr ret;
2590 long carry, tempdays, temp;
2591 xmlSchemaValDatePtr r, d;
2592 xmlSchemaValDurationPtr u;
2593
2594 if ((dt == NULL) || (dur == NULL))
2595 return NULL;
2596
2597 ret = xmlSchemaNewValue(dt->type);
2598 if (ret == NULL)
2599 return NULL;
2600
2601 r = &(ret->value.date);
2602 d = &(dt->value.date);
2603 u = &(dur->value.dur);
2604
2605 /* normalization */
2606 if (d->mon == 0)
2607 d->mon = 1;
2608
2609 /* normalize for time zone offset */
2610 u->sec -= (d->tzo * 60);
2611 d->tzo = 0;
2612
2613 /* normalization */
2614 if (d->day == 0)
2615 d->day = 1;
2616
2617 /* month */
2618 carry = d->mon + u->mon;
2619 r->mon = MODULO_RANGE(carry, 1, 13);
2620 carry = FQUOTIENT_RANGE(carry, 1, 13);
2621
2622 /* year (may be modified later) */
2623 r->year = d->year + carry;
2624 if (r->year == 0) {
2625 if (d->year > 0)
2626 r->year--;
2627 else
2628 r->year++;
2629 }
2630
2631 /* time zone */
2632 r->tzo = d->tzo;
2633 r->tz_flag = d->tz_flag;
2634
2635 /* seconds */
2636 r->sec = d->sec + u->sec;
2637 carry = FQUOTIENT((long)r->sec, 60);
2638 if (r->sec != 0.0) {
2639 r->sec = MODULO(r->sec, 60.0);
2640 }
2641
2642 /* minute */
2643 carry += d->min;
2644 r->min = MODULO(carry, 60);
2645 carry = FQUOTIENT(carry, 60);
2646
2647 /* hours */
2648 carry += d->hour;
2649 r->hour = MODULO(carry, 24);
2650 carry = FQUOTIENT(carry, 24);
2651
2652 /*
2653 * days
2654 * Note we use tempdays because the temporary values may need more
2655 * than 5 bits
2656 */
2657 if ((VALID_YEAR(r->year)) && (VALID_MONTH(r->mon)) &&
2658 (d->day > MAX_DAYINMONTH(r->year, r->mon)))
2659 tempdays = MAX_DAYINMONTH(r->year, r->mon);
2660 else if (d->day < 1)
2661 tempdays = 1;
2662 else
2663 tempdays = d->day;
2664
2665 tempdays += u->day + carry;
2666
2667 while (1) {
2668 if (tempdays < 1) {
2669 long tmon = MODULO_RANGE(r->mon-1, 1, 13);
2670 long tyr = r->year + FQUOTIENT_RANGE(r->mon-1, 1, 13);
2671 if (tyr == 0)
2672 tyr--;
2673 tempdays += MAX_DAYINMONTH(tyr, tmon);
2674 carry = -1;
2675 } else if (tempdays > MAX_DAYINMONTH(r->year, r->mon)) {
2676 tempdays = tempdays - MAX_DAYINMONTH(r->year, r->mon);
2677 carry = 1;
2678 } else
2679 break;
2680
2681 temp = r->mon + carry;
2682 r->mon = MODULO_RANGE(temp, 1, 13);
2683 r->year = r->year + FQUOTIENT_RANGE(temp, 1, 13);
2684 if (r->year == 0) {
2685 if (temp < 1)
2686 r->year--;
2687 else
2688 r->year++;
2689 }
2690 }
2691
2692 r->day = tempdays;
2693
2694 /*
2695 * adjust the date/time type to the date values
2696 */
2697 if (ret->type != XML_SCHEMAS_DATETIME) {
2698 if ((r->hour) || (r->min) || (r->sec))
2699 ret->type = XML_SCHEMAS_DATETIME;
2700 else if (ret->type != XML_SCHEMAS_DATE) {
2701 if ((r->mon != 1) && (r->day != 1))
2702 ret->type = XML_SCHEMAS_DATE;
2703 else if ((ret->type != XML_SCHEMAS_GYEARMONTH) && (r->mon != 1))
2704 ret->type = XML_SCHEMAS_GYEARMONTH;
2705 }
2706 }
2707
2708 return ret;
2709}
2710
2711/**
2712 * xmlSchemaDupVal:
2713 * @v: value to duplicate
2714 *
2715 * returns a duplicated value.
2716 */
2717static xmlSchemaValPtr
2718xmlSchemaDupVal (xmlSchemaValPtr v)
2719{
2720 xmlSchemaValPtr ret = xmlSchemaNewValue(v->type);
2721 if (ret == NULL)
2722 return ret;
2723
2724 memcpy(ret, v, sizeof(xmlSchemaVal));
2725 return ret;
2726}
2727
2728/**
2729 * xmlSchemaDateNormalize:
2730 * @dt: an #xmlSchemaValPtr
2731 *
2732 * Normalize @dt to GMT time.
2733 *
2734 */
2735static xmlSchemaValPtr
2736xmlSchemaDateNormalize (xmlSchemaValPtr dt, double offset)
2737{
2738 xmlSchemaValPtr dur, ret;
2739
2740 if (dt == NULL)
2741 return NULL;
2742
2743 if (((dt->type != XML_SCHEMAS_TIME) &&
2744 (dt->type != XML_SCHEMAS_DATETIME)) || (dt->value.date.tzo == 0))
2745 return xmlSchemaDupVal(dt);
2746
2747 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
2748 if (dur == NULL)
2749 return NULL;
2750
2751 dur->value.date.sec -= offset;
2752
2753 ret = _xmlSchemaDateAdd(dt, dur);
2754 if (ret == NULL)
2755 return NULL;
2756
2757 xmlSchemaFreeValue(dur);
2758
2759 /* ret->value.date.tzo = 0; */
2760 return ret;
2761}
2762
2763/**
2764 * _xmlSchemaDateCastYMToDays:
2765 * @dt: an #xmlSchemaValPtr
2766 *
2767 * Convert mon and year of @dt to total number of days. Take the
2768 * number of years since (or before) 1 AD and add the number of leap
2769 * years. This is a function because negative
2770 * years must be handled a little differently and there is no zero year.
2771 *
2772 * Returns number of days.
2773 */
2774static long
2775_xmlSchemaDateCastYMToDays (const xmlSchemaValPtr dt)
2776{
2777 long ret;
2778
2779 if (dt->value.date.year < 0)
2780 ret = (dt->value.date.year * 365) +
2781 (((dt->value.date.year+1)/4)-((dt->value.date.year+1)/100)+
2782 ((dt->value.date.year+1)/400)) +
2783 DAY_IN_YEAR(0, dt->value.date.mon, dt->value.date.year);
2784 else
2785 ret = ((dt->value.date.year-1) * 365) +
2786 (((dt->value.date.year-1)/4)-((dt->value.date.year-1)/100)+
2787 ((dt->value.date.year-1)/400)) +
2788 DAY_IN_YEAR(0, dt->value.date.mon, dt->value.date.year);
2789
2790 return ret;
2791}
2792
2793/**
2794 * TIME_TO_NUMBER:
2795 * @dt: an #xmlSchemaValPtr
2796 *
2797 * Calculates the number of seconds in the time portion of @dt.
2798 *
2799 * Returns seconds.
2800 */
2801#define TIME_TO_NUMBER(dt) \
2802 ((double)((dt->value.date.hour * SECS_PER_HOUR) + \
Daniel Veillardb3721c22003-03-31 11:22:25 +00002803 (dt->value.date.min * SECS_PER_MIN) + \
2804 (dt->value.date.tzo * SECS_PER_MIN)) + \
2805 dt->value.date.sec)
Daniel Veillard5a872412002-05-22 06:40:27 +00002806
2807/**
2808 * xmlSchemaCompareDates:
2809 * @x: a first date/time value
2810 * @y: a second date/time value
2811 *
2812 * Compare 2 date/times
2813 *
2814 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
2815 * case of error
2816 */
2817static int
2818xmlSchemaCompareDates (xmlSchemaValPtr x, xmlSchemaValPtr y)
2819{
2820 unsigned char xmask, ymask, xor_mask, and_mask;
2821 xmlSchemaValPtr p1, p2, q1, q2;
2822 long p1d, p2d, q1d, q2d;
2823
2824 if ((x == NULL) || (y == NULL))
2825 return -2;
2826
2827 if (x->value.date.tz_flag) {
2828
2829 if (!y->value.date.tz_flag) {
2830 p1 = xmlSchemaDateNormalize(x, 0);
2831 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
2832 /* normalize y + 14:00 */
2833 q1 = xmlSchemaDateNormalize(y, (14 * SECS_PER_HOUR));
2834
2835 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002836 if (p1d < q1d) {
2837 xmlSchemaFreeValue(p1);
2838 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002839 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002840 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00002841 double sec;
2842
2843 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00002844 if (sec < 0.0) {
2845 xmlSchemaFreeValue(p1);
2846 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002847 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002848 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00002849 /* normalize y - 14:00 */
2850 q2 = xmlSchemaDateNormalize(y, -(14 * SECS_PER_HOUR));
2851 q2d = _xmlSchemaDateCastYMToDays(q2) + q2->value.date.day;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002852 xmlSchemaFreeValue(p1);
2853 xmlSchemaFreeValue(q1);
2854 xmlSchemaFreeValue(q2);
Daniel Veillard5a872412002-05-22 06:40:27 +00002855 if (p1d > q2d)
2856 return 1;
2857 else if (p1d == q2d) {
2858 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q2);
2859 if (sec > 0.0)
2860 return 1;
2861 else
2862 return 2; /* indeterminate */
2863 }
2864 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00002865 } else {
2866 xmlSchemaFreeValue(p1);
2867 xmlSchemaFreeValue(q1);
2868 }
Daniel Veillard5a872412002-05-22 06:40:27 +00002869 }
2870 } else if (y->value.date.tz_flag) {
2871 q1 = xmlSchemaDateNormalize(y, 0);
2872 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
2873
2874 /* normalize x - 14:00 */
2875 p1 = xmlSchemaDateNormalize(x, -(14 * SECS_PER_HOUR));
2876 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
2877
Daniel Veillardfdc91562002-07-01 21:52:03 +00002878 if (p1d < q1d) {
2879 xmlSchemaFreeValue(p1);
2880 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002881 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002882 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00002883 double sec;
2884
2885 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00002886 if (sec < 0.0) {
2887 xmlSchemaFreeValue(p1);
2888 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002889 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002890 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00002891 /* normalize x + 14:00 */
2892 p2 = xmlSchemaDateNormalize(x, (14 * SECS_PER_HOUR));
2893 p2d = _xmlSchemaDateCastYMToDays(p2) + p2->value.date.day;
2894
Daniel Veillard6560a422003-03-27 21:25:38 +00002895 if (p2d > q1d) {
2896 xmlSchemaFreeValue(p1);
2897 xmlSchemaFreeValue(q1);
2898 xmlSchemaFreeValue(p2);
Daniel Veillard5a872412002-05-22 06:40:27 +00002899 return 1;
Daniel Veillard6560a422003-03-27 21:25:38 +00002900 } else if (p2d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00002901 sec = TIME_TO_NUMBER(p2) - TIME_TO_NUMBER(q1);
Daniel Veillard6560a422003-03-27 21:25:38 +00002902 xmlSchemaFreeValue(p1);
2903 xmlSchemaFreeValue(q1);
2904 xmlSchemaFreeValue(p2);
Daniel Veillard5a872412002-05-22 06:40:27 +00002905 if (sec > 0.0)
2906 return 1;
2907 else
2908 return 2; /* indeterminate */
2909 }
Daniel Veillard6560a422003-03-27 21:25:38 +00002910 xmlSchemaFreeValue(p1);
2911 xmlSchemaFreeValue(q1);
2912 xmlSchemaFreeValue(p2);
Daniel Veillard5a872412002-05-22 06:40:27 +00002913 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00002914 } else {
2915 xmlSchemaFreeValue(p1);
2916 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002917 }
2918 }
2919
2920 /*
2921 * if the same type then calculate the difference
2922 */
2923 if (x->type == y->type) {
2924 q1 = xmlSchemaDateNormalize(y, 0);
2925 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
2926
2927 p1 = xmlSchemaDateNormalize(x, 0);
2928 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
2929
Daniel Veillardfdc91562002-07-01 21:52:03 +00002930 if (p1d < q1d) {
2931 xmlSchemaFreeValue(p1);
2932 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002933 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002934 } else if (p1d > q1d) {
2935 xmlSchemaFreeValue(p1);
2936 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002937 return 1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002938 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00002939 double sec;
2940
2941 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00002942 xmlSchemaFreeValue(p1);
2943 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002944 if (sec < 0.0)
2945 return -1;
2946 else if (sec > 0.0)
2947 return 1;
2948
2949 }
2950 return 0;
2951 }
2952
2953 switch (x->type) {
2954 case XML_SCHEMAS_DATETIME:
2955 xmask = 0xf;
2956 break;
2957 case XML_SCHEMAS_DATE:
2958 xmask = 0x7;
2959 break;
2960 case XML_SCHEMAS_GYEAR:
2961 xmask = 0x1;
2962 break;
2963 case XML_SCHEMAS_GMONTH:
2964 xmask = 0x2;
2965 break;
2966 case XML_SCHEMAS_GDAY:
2967 xmask = 0x3;
2968 break;
2969 case XML_SCHEMAS_GYEARMONTH:
2970 xmask = 0x3;
2971 break;
2972 case XML_SCHEMAS_GMONTHDAY:
2973 xmask = 0x6;
2974 break;
2975 case XML_SCHEMAS_TIME:
2976 xmask = 0x8;
2977 break;
2978 default:
2979 xmask = 0;
2980 break;
2981 }
2982
2983 switch (y->type) {
2984 case XML_SCHEMAS_DATETIME:
2985 ymask = 0xf;
2986 break;
2987 case XML_SCHEMAS_DATE:
2988 ymask = 0x7;
2989 break;
2990 case XML_SCHEMAS_GYEAR:
2991 ymask = 0x1;
2992 break;
2993 case XML_SCHEMAS_GMONTH:
2994 ymask = 0x2;
2995 break;
2996 case XML_SCHEMAS_GDAY:
2997 ymask = 0x3;
2998 break;
2999 case XML_SCHEMAS_GYEARMONTH:
3000 ymask = 0x3;
3001 break;
3002 case XML_SCHEMAS_GMONTHDAY:
3003 ymask = 0x6;
3004 break;
3005 case XML_SCHEMAS_TIME:
3006 ymask = 0x8;
3007 break;
3008 default:
3009 ymask = 0;
3010 break;
3011 }
3012
3013 xor_mask = xmask ^ ymask; /* mark type differences */
3014 and_mask = xmask & ymask; /* mark field specification */
3015
3016 /* year */
3017 if (xor_mask & 1)
3018 return 2; /* indeterminate */
3019 else if (and_mask & 1) {
3020 if (x->value.date.year < y->value.date.year)
3021 return -1;
3022 else if (x->value.date.year > y->value.date.year)
3023 return 1;
3024 }
3025
3026 /* month */
3027 if (xor_mask & 2)
3028 return 2; /* indeterminate */
3029 else if (and_mask & 2) {
3030 if (x->value.date.mon < y->value.date.mon)
3031 return -1;
3032 else if (x->value.date.mon > y->value.date.mon)
3033 return 1;
3034 }
3035
3036 /* day */
3037 if (xor_mask & 4)
3038 return 2; /* indeterminate */
3039 else if (and_mask & 4) {
3040 if (x->value.date.day < y->value.date.day)
3041 return -1;
3042 else if (x->value.date.day > y->value.date.day)
3043 return 1;
3044 }
3045
3046 /* time */
3047 if (xor_mask & 8)
3048 return 2; /* indeterminate */
3049 else if (and_mask & 8) {
3050 if (x->value.date.hour < y->value.date.hour)
3051 return -1;
3052 else if (x->value.date.hour > y->value.date.hour)
3053 return 1;
3054 else if (x->value.date.min < y->value.date.min)
3055 return -1;
3056 else if (x->value.date.min > y->value.date.min)
3057 return 1;
3058 else if (x->value.date.sec < y->value.date.sec)
3059 return -1;
3060 else if (x->value.date.sec > y->value.date.sec)
3061 return 1;
3062 }
3063
Daniel Veillard070803b2002-05-03 07:29:38 +00003064 return 0;
3065}
3066
3067/**
Daniel Veillardc4c21552003-03-29 10:53:38 +00003068 * xmlSchemaCompareNormStrings:
3069 * @x: a first string value
3070 * @y: a second string value
3071 *
3072 * Compare 2 string for their normalized values.
3073 *
3074 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
3075 * case of error
3076 */
3077static int
3078xmlSchemaCompareNormStrings(xmlSchemaValPtr x, xmlSchemaValPtr y) {
3079 const xmlChar *utf1;
3080 const xmlChar *utf2;
3081 int tmp;
3082
3083 if ((x == NULL) || (y == NULL))
3084 return(-2);
3085 utf1 = x->value.str;
3086 utf2 = y->value.str;
3087
3088 while (IS_BLANK(*utf1)) utf1++;
3089 while (IS_BLANK(*utf2)) utf2++;
3090 while ((*utf1 != 0) && (*utf2 != 0)) {
3091 if (IS_BLANK(*utf1)) {
3092 if (!IS_BLANK(*utf2)) {
3093 tmp = *utf1 - *utf2;
3094 return(tmp);
3095 }
3096 while (IS_BLANK(*utf1)) utf1++;
3097 while (IS_BLANK(*utf2)) utf2++;
3098 } else {
3099 tmp = *utf1++ - *utf2++;
3100 if (tmp < 0)
3101 return(-1);
3102 if (tmp > 0)
3103 return(1);
3104 }
3105 }
3106 if (*utf1 != 0) {
3107 while (IS_BLANK(*utf1)) utf1++;
3108 if (*utf1 != 0)
3109 return(1);
3110 }
3111 if (*utf2 != 0) {
3112 while (IS_BLANK(*utf2)) utf2++;
3113 if (*utf2 != 0)
3114 return(-1);
3115 }
3116 return(0);
3117}
3118
3119/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003120 * xmlSchemaCompareFloats:
3121 * @x: a first float or double value
3122 * @y: a second float or double value
3123 *
3124 * Compare 2 values
3125 *
3126 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3127 * case of error
3128 */
3129static int
3130xmlSchemaCompareFloats(xmlSchemaValPtr x, xmlSchemaValPtr y) {
3131 double d1, d2;
3132
3133 if ((x == NULL) || (y == NULL))
3134 return(-2);
3135
3136 /*
3137 * Cast everything to doubles.
3138 */
3139 if (x->type == XML_SCHEMAS_DOUBLE)
3140 d1 = x->value.d;
3141 else if (x->type == XML_SCHEMAS_FLOAT)
3142 d1 = x->value.f;
3143 else
3144 return(-2);
3145
3146 if (y->type == XML_SCHEMAS_DOUBLE)
3147 d2 = y->value.d;
3148 else if (y->type == XML_SCHEMAS_FLOAT)
3149 d2 = y->value.f;
3150 else
3151 return(-2);
3152
3153 /*
3154 * Check for special cases.
3155 */
3156 if (xmlXPathIsNaN(d1)) {
3157 if (xmlXPathIsNaN(d2))
3158 return(0);
3159 return(1);
3160 }
3161 if (xmlXPathIsNaN(d2))
3162 return(-1);
3163 if (d1 == xmlXPathPINF) {
3164 if (d2 == xmlXPathPINF)
3165 return(0);
3166 return(1);
3167 }
3168 if (d2 == xmlXPathPINF)
3169 return(-1);
3170 if (d1 == xmlXPathNINF) {
3171 if (d2 == xmlXPathNINF)
3172 return(0);
3173 return(-1);
3174 }
3175 if (d2 == xmlXPathNINF)
3176 return(1);
3177
3178 /*
3179 * basic tests, the last one we should have equality, but
3180 * portability is more important than speed and handling
3181 * NaN or Inf in a portable way is always a challenge, so ...
3182 */
3183 if (d1 < d2)
3184 return(-1);
3185 if (d1 > d2)
3186 return(1);
3187 if (d1 == d2)
3188 return(0);
3189 return(2);
3190}
3191
3192/**
Daniel Veillard4255d502002-04-16 15:50:10 +00003193 * xmlSchemaCompareValues:
3194 * @x: a first value
3195 * @y: a second value
3196 *
3197 * Compare 2 values
3198 *
Daniel Veillard5a872412002-05-22 06:40:27 +00003199 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3200 * case of error
Daniel Veillard4255d502002-04-16 15:50:10 +00003201 */
Daniel Veillard80b19092003-03-28 13:29:53 +00003202int
Daniel Veillard4255d502002-04-16 15:50:10 +00003203xmlSchemaCompareValues(xmlSchemaValPtr x, xmlSchemaValPtr y) {
3204 if ((x == NULL) || (y == NULL))
3205 return(-2);
3206
3207 switch (x->type) {
Daniel Veillard80b19092003-03-28 13:29:53 +00003208 case XML_SCHEMAS_UNKNOWN:
3209 return(-2);
3210 case XML_SCHEMAS_INTEGER:
3211 case XML_SCHEMAS_NPINTEGER:
3212 case XML_SCHEMAS_NINTEGER:
3213 case XML_SCHEMAS_NNINTEGER:
3214 case XML_SCHEMAS_PINTEGER:
3215 case XML_SCHEMAS_INT:
3216 case XML_SCHEMAS_UINT:
3217 case XML_SCHEMAS_LONG:
3218 case XML_SCHEMAS_ULONG:
3219 case XML_SCHEMAS_SHORT:
3220 case XML_SCHEMAS_USHORT:
3221 case XML_SCHEMAS_BYTE:
3222 case XML_SCHEMAS_UBYTE:
Daniel Veillard4255d502002-04-16 15:50:10 +00003223 case XML_SCHEMAS_DECIMAL:
Daniel Veillard80b19092003-03-28 13:29:53 +00003224 if (y->type == x->type)
3225 return(xmlSchemaCompareDecimals(x, y));
3226 if ((y->type == XML_SCHEMAS_DECIMAL) ||
3227 (y->type == XML_SCHEMAS_INTEGER) ||
3228 (y->type == XML_SCHEMAS_NPINTEGER) ||
3229 (y->type == XML_SCHEMAS_NINTEGER) ||
3230 (y->type == XML_SCHEMAS_NNINTEGER) ||
3231 (y->type == XML_SCHEMAS_PINTEGER) ||
3232 (y->type == XML_SCHEMAS_INT) ||
3233 (y->type == XML_SCHEMAS_UINT) ||
3234 (y->type == XML_SCHEMAS_LONG) ||
3235 (y->type == XML_SCHEMAS_ULONG) ||
3236 (y->type == XML_SCHEMAS_SHORT) ||
3237 (y->type == XML_SCHEMAS_USHORT) ||
3238 (y->type == XML_SCHEMAS_BYTE) ||
3239 (y->type == XML_SCHEMAS_UBYTE))
Daniel Veillard4255d502002-04-16 15:50:10 +00003240 return(xmlSchemaCompareDecimals(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00003241 return(-2);
Daniel Veillard070803b2002-05-03 07:29:38 +00003242 case XML_SCHEMAS_DURATION:
3243 if (y->type == XML_SCHEMAS_DURATION)
3244 return(xmlSchemaCompareDurations(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00003245 return(-2);
3246 case XML_SCHEMAS_TIME:
3247 case XML_SCHEMAS_GDAY:
3248 case XML_SCHEMAS_GMONTH:
3249 case XML_SCHEMAS_GMONTHDAY:
3250 case XML_SCHEMAS_GYEAR:
3251 case XML_SCHEMAS_GYEARMONTH:
3252 case XML_SCHEMAS_DATE:
3253 case XML_SCHEMAS_DATETIME:
3254 if ((y->type == XML_SCHEMAS_DATETIME) ||
3255 (y->type == XML_SCHEMAS_TIME) ||
3256 (y->type == XML_SCHEMAS_GDAY) ||
3257 (y->type == XML_SCHEMAS_GMONTH) ||
3258 (y->type == XML_SCHEMAS_GMONTHDAY) ||
3259 (y->type == XML_SCHEMAS_GYEAR) ||
3260 (y->type == XML_SCHEMAS_DATE) ||
3261 (y->type == XML_SCHEMAS_GYEARMONTH))
3262 return (xmlSchemaCompareDates(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00003263 return (-2);
Daniel Veillard80b19092003-03-28 13:29:53 +00003264 case XML_SCHEMAS_NORMSTRING:
Daniel Veillard80b19092003-03-28 13:29:53 +00003265 case XML_SCHEMAS_TOKEN:
3266 case XML_SCHEMAS_LANGUAGE:
3267 case XML_SCHEMAS_NMTOKEN:
Daniel Veillard80b19092003-03-28 13:29:53 +00003268 case XML_SCHEMAS_NAME:
Daniel Veillard80b19092003-03-28 13:29:53 +00003269 case XML_SCHEMAS_NCNAME:
3270 case XML_SCHEMAS_ID:
3271 case XML_SCHEMAS_IDREF:
Daniel Veillard80b19092003-03-28 13:29:53 +00003272 case XML_SCHEMAS_ENTITY:
Daniel Veillard80b19092003-03-28 13:29:53 +00003273 case XML_SCHEMAS_NOTATION:
3274 case XML_SCHEMAS_ANYURI:
Daniel Veillardc4c21552003-03-29 10:53:38 +00003275 if ((y->type == XML_SCHEMAS_NORMSTRING) ||
3276 (y->type == XML_SCHEMAS_TOKEN) ||
3277 (y->type == XML_SCHEMAS_LANGUAGE) ||
3278 (y->type == XML_SCHEMAS_NMTOKEN) ||
3279 (y->type == XML_SCHEMAS_NAME) ||
3280 (y->type == XML_SCHEMAS_QNAME) ||
3281 (y->type == XML_SCHEMAS_NCNAME) ||
3282 (y->type == XML_SCHEMAS_ID) ||
3283 (y->type == XML_SCHEMAS_IDREF) ||
3284 (y->type == XML_SCHEMAS_ENTITY) ||
3285 (y->type == XML_SCHEMAS_NOTATION) ||
3286 (y->type == XML_SCHEMAS_ANYURI))
3287 return (xmlSchemaCompareNormStrings(x, y));
3288 return (-2);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003289 case XML_SCHEMAS_QNAME:
3290 if (y->type == XML_SCHEMAS_QNAME) {
3291 if ((xmlStrEqual(x->value.qname.name, y->value.qname.name)) &&
3292 (xmlStrEqual(x->value.qname.uri, y->value.qname.uri)))
3293 return(0);
3294 return(2);
3295 }
3296 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00003297 case XML_SCHEMAS_FLOAT:
3298 case XML_SCHEMAS_DOUBLE:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003299 if ((y->type == XML_SCHEMAS_FLOAT) ||
3300 (y->type == XML_SCHEMAS_DOUBLE))
3301 return (xmlSchemaCompareFloats(x, y));
3302 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00003303 case XML_SCHEMAS_BOOLEAN:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003304 if (y->type == XML_SCHEMAS_BOOLEAN) {
3305 if (x->value.b == y->value.b)
3306 return(0);
3307 if (x->value.b == 0)
3308 return(-1);
3309 return(1);
3310 }
3311 return (-2);
Daniel Veillard560c2a42003-07-06 21:13:49 +00003312 case XML_SCHEMAS_HEXBINARY:
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00003313 if (y->type == XML_SCHEMAS_HEXBINARY) {
3314 if (x->value.hex.total == y->value.hex.total) {
3315 int ret = xmlStrcmp(x->value.hex.str, y->value.hex.str);
3316 if (ret > 0)
3317 return(1);
3318 else if (ret == 0)
3319 return(0);
3320 }
3321 else if (x->value.hex.total > y->value.hex.total)
3322 return(1);
3323
3324 return(-1);
3325 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00003326 return (-2);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003327 case XML_SCHEMAS_BASE64BINARY:
3328 if (y->type == XML_SCHEMAS_BASE64BINARY) {
3329 if (x->value.base64.total == y->value.base64.total) {
3330 int ret = xmlStrcmp(x->value.base64.str,
3331 y->value.base64.str);
3332 if (ret > 0)
3333 return(1);
3334 else if (ret == 0)
3335 return(0);
3336 }
3337 else if (x->value.base64.total > y->value.base64.total)
3338 return(1);
3339 else
3340 return(-1);
3341 }
3342 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00003343 case XML_SCHEMAS_STRING:
3344 case XML_SCHEMAS_IDREFS:
3345 case XML_SCHEMAS_ENTITIES:
3346 case XML_SCHEMAS_NMTOKENS:
3347 TODO
3348 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00003349 }
Daniel Veillard5a872412002-05-22 06:40:27 +00003350 return -2;
Daniel Veillard4255d502002-04-16 15:50:10 +00003351}
3352
3353/**
Daniel Veillardc4c21552003-03-29 10:53:38 +00003354 * xmlSchemaNormLen:
3355 * @value: a string
3356 *
3357 * Computes the UTF8 length of the normalized value of the string
3358 *
3359 * Returns the length or -1 in case of error.
3360 */
3361static int
3362xmlSchemaNormLen(const xmlChar *value) {
3363 const xmlChar *utf;
3364 int ret = 0;
3365
3366 if (value == NULL)
3367 return(-1);
3368 utf = value;
3369 while (IS_BLANK(*utf)) utf++;
3370 while (*utf != 0) {
3371 if (utf[0] & 0x80) {
3372 if ((utf[1] & 0xc0) != 0x80)
3373 return(-1);
3374 if ((utf[0] & 0xe0) == 0xe0) {
3375 if ((utf[2] & 0xc0) != 0x80)
3376 return(-1);
3377 if ((utf[0] & 0xf0) == 0xf0) {
3378 if ((utf[0] & 0xf8) != 0xf0 || (utf[3] & 0xc0) != 0x80)
3379 return(-1);
3380 utf += 4;
3381 } else {
3382 utf += 3;
3383 }
3384 } else {
3385 utf += 2;
3386 }
3387 } else if (IS_BLANK(*utf)) {
3388 while (IS_BLANK(*utf)) utf++;
3389 if (*utf == 0)
3390 break;
3391 } else {
3392 utf++;
3393 }
3394 ret++;
3395 }
3396 return(ret);
3397}
3398
3399/**
Daniel Veillard4255d502002-04-16 15:50:10 +00003400 * xmlSchemaValidateFacet:
Daniel Veillard01c13b52002-12-10 15:19:08 +00003401 * @base: the base type
Daniel Veillard4255d502002-04-16 15:50:10 +00003402 * @facet: the facet to check
3403 * @value: the lexical repr of the value to validate
3404 * @val: the precomputed value
3405 *
3406 * Check a value against a facet condition
3407 *
3408 * Returns 0 if the element is schemas valid, a positive error code
3409 * number otherwise and -1 in case of internal or API error.
3410 */
3411int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00003412xmlSchemaValidateFacet(xmlSchemaTypePtr base ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +00003413 xmlSchemaFacetPtr facet,
Daniel Veillard4255d502002-04-16 15:50:10 +00003414 const xmlChar *value, xmlSchemaValPtr val)
3415{
3416 int ret;
3417
3418 switch (facet->type) {
3419 case XML_SCHEMA_FACET_PATTERN:
3420 ret = xmlRegexpExec(facet->regexp, value);
3421 if (ret == 1)
3422 return(0);
3423 if (ret == 0) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003424 /* TODO error code */
Daniel Veillard4255d502002-04-16 15:50:10 +00003425 return(1);
3426 }
3427 return(ret);
3428 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
3429 ret = xmlSchemaCompareValues(val, facet->val);
3430 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003431 /* TODO error code */
Daniel Veillard4255d502002-04-16 15:50:10 +00003432 return(-1);
3433 }
3434 if (ret == -1)
3435 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00003436 /* error code */
Daniel Veillard4255d502002-04-16 15:50:10 +00003437 return(1);
Daniel Veillard070803b2002-05-03 07:29:38 +00003438 case XML_SCHEMA_FACET_MAXINCLUSIVE:
3439 ret = xmlSchemaCompareValues(val, facet->val);
3440 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003441 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00003442 return(-1);
3443 }
3444 if ((ret == -1) || (ret == 0))
3445 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00003446 /* error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00003447 return(1);
3448 case XML_SCHEMA_FACET_MINEXCLUSIVE:
3449 ret = xmlSchemaCompareValues(val, facet->val);
3450 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003451 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00003452 return(-1);
3453 }
3454 if (ret == 1)
3455 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00003456 /* error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00003457 return(1);
3458 case XML_SCHEMA_FACET_MININCLUSIVE:
3459 ret = xmlSchemaCompareValues(val, facet->val);
3460 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003461 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00003462 return(-1);
3463 }
3464 if ((ret == 1) || (ret == 0))
3465 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00003466 /* error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00003467 return(1);
Daniel Veillard8651f532002-04-17 09:06:27 +00003468 case XML_SCHEMA_FACET_WHITESPACE:
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003469 /* TODO whitespaces */
Daniel Veillard8651f532002-04-17 09:06:27 +00003470 return(0);
Daniel Veillard88c58912002-04-23 07:12:20 +00003471 case XML_SCHEMA_FACET_ENUMERATION:
3472 if ((facet->value != NULL) &&
3473 (xmlStrEqual(facet->value, value)))
3474 return(0);
3475 return(1);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003476 case XML_SCHEMA_FACET_LENGTH:
3477 case XML_SCHEMA_FACET_MAXLENGTH:
3478 case XML_SCHEMA_FACET_MINLENGTH: {
3479 unsigned int len = 0;
3480
3481 if ((facet->val == NULL) ||
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003482 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
3483 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003484 (facet->val->value.decimal.frac != 0)) {
3485 return(-1);
3486 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00003487 if ((val != NULL) && (val->type == XML_SCHEMAS_HEXBINARY))
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00003488 len = val->value.hex.total;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00003489 else if ((val != NULL) && (val->type == XML_SCHEMAS_BASE64BINARY))
3490 len = val->value.base64.total;
3491 else {
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00003492 switch (base->flags) {
Daniel Veillard560c2a42003-07-06 21:13:49 +00003493 case XML_SCHEMAS_IDREF:
3494 case XML_SCHEMAS_NORMSTRING:
3495 case XML_SCHEMAS_TOKEN:
3496 case XML_SCHEMAS_LANGUAGE:
3497 case XML_SCHEMAS_NMTOKEN:
3498 case XML_SCHEMAS_NAME:
3499 case XML_SCHEMAS_NCNAME:
3500 case XML_SCHEMAS_ID:
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00003501 len = xmlSchemaNormLen(value);
3502 break;
Daniel Veillard560c2a42003-07-06 21:13:49 +00003503 case XML_SCHEMAS_STRING:
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00003504 len = xmlUTF8Strlen(value);
3505 break;
Daniel Veillard560c2a42003-07-06 21:13:49 +00003506 default:
3507 TODO
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00003508 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003509 }
3510 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003511 if (len != facet->val->value.decimal.lo)
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003512 return(1);
3513 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003514 if (len < facet->val->value.decimal.lo)
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003515 return(1);
3516 } else {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003517 if (len > facet->val->value.decimal.lo)
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003518 return(1);
3519 }
3520 break;
3521 }
Daniel Veillard560c2a42003-07-06 21:13:49 +00003522 case XML_SCHEMA_FACET_TOTALDIGITS:
3523 case XML_SCHEMA_FACET_FRACTIONDIGITS:
3524
3525 if ((facet->val == NULL) ||
3526 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
3527 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
3528 (facet->val->value.decimal.frac != 0)) {
3529 return(-1);
3530 }
3531 if ((val == NULL) ||
3532 ((val->type != XML_SCHEMAS_DECIMAL) &&
3533 (val->type != XML_SCHEMAS_INTEGER) &&
3534 (val->type != XML_SCHEMAS_NPINTEGER) &&
3535 (val->type != XML_SCHEMAS_NINTEGER) &&
3536 (val->type != XML_SCHEMAS_NNINTEGER) &&
3537 (val->type != XML_SCHEMAS_PINTEGER) &&
3538 (val->type != XML_SCHEMAS_INT) &&
3539 (val->type != XML_SCHEMAS_UINT) &&
3540 (val->type != XML_SCHEMAS_LONG) &&
3541 (val->type != XML_SCHEMAS_ULONG) &&
3542 (val->type != XML_SCHEMAS_SHORT) &&
3543 (val->type != XML_SCHEMAS_USHORT) &&
3544 (val->type != XML_SCHEMAS_BYTE) &&
3545 (val->type != XML_SCHEMAS_UBYTE))) {
3546 return(-1);
3547 }
3548 if (facet->type == XML_SCHEMA_FACET_TOTALDIGITS) {
3549 if (val->value.decimal.total > facet->val->value.decimal.lo)
3550 return(1);
3551
3552 } else if (facet->type == XML_SCHEMA_FACET_FRACTIONDIGITS) {
3553 if (val->value.decimal.frac > facet->val->value.decimal.lo)
3554 return(1);
3555 }
3556 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00003557 default:
3558 TODO
3559 }
3560 return(0);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003561
Daniel Veillard4255d502002-04-16 15:50:10 +00003562}
3563
3564#endif /* LIBXML_SCHEMAS_ENABLED */