BRANCH release for 2.5.x critical patches
[baserock-morphs:libxml2.git] / xmlschemastypes.c
1 /*
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>
21 #include <libxml/xpath.h>
22 #include <libxml/uri.h>
23
24 #include <libxml/xmlschemas.h>
25 #include <libxml/schemasInternals.h>
26 #include <libxml/xmlschemastypes.h>
27
28 #ifdef HAVE_MATH_H
29 #include <math.h>
30 #endif
31
32 #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
42 typedef enum {
43     XML_SCHEMAS_UNKNOWN = 0,
44     XML_SCHEMAS_STRING,
45     XML_SCHEMAS_NORMSTRING,
46     XML_SCHEMAS_DECIMAL,
47     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,
56     XML_SCHEMAS_FLOAT,
57     XML_SCHEMAS_DOUBLE,
58     XML_SCHEMAS_BOOLEAN,
59     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,
78     XML_SCHEMAS_INT,
79     XML_SCHEMAS_UINT,
80     XML_SCHEMAS_LONG,
81     XML_SCHEMAS_ULONG,
82     XML_SCHEMAS_SHORT,
83     XML_SCHEMAS_USHORT,
84     XML_SCHEMAS_BYTE,
85     XML_SCHEMAS_UBYTE,
86     XML_SCHEMAS_HEXBINARY
87 } xmlSchemaValType;
88
89 static unsigned long powten[10] = {
90     1, 10, 100, 1000, 10000, 100000, 1000000, 10000000L,
91     100000000L, 1000000000L
92 };
93
94 /* Date value */
95 typedef struct _xmlSchemaValDate xmlSchemaValDate;
96 typedef xmlSchemaValDate *xmlSchemaValDatePtr;
97 struct _xmlSchemaValDate {
98     long                year;
99     unsigned int        mon     :4;     /* 1 <=  mon    <= 12   */
100     unsigned int        day     :5;     /* 1 <=  day    <= 31   */
101     unsigned int        hour    :5;     /* 0 <=  hour   <= 23   */
102     unsigned int        min     :6;     /* 0 <=  min    <= 59   */
103     double              sec;
104     unsigned int        tz_flag :1;     /* is tzo explicitely set? */
105     int                 tzo     :11;    /* -1440 <= tzo <= 1440 */
106 };
107
108 /* Duration value */
109 typedef struct _xmlSchemaValDuration xmlSchemaValDuration;
110 typedef xmlSchemaValDuration *xmlSchemaValDurationPtr;
111 struct _xmlSchemaValDuration {
112     long                mon;            /* mon stores years also */
113     long                day;
114     double              sec;            /* sec stores min and hour also */
115 };
116
117 typedef struct _xmlSchemaValDecimal xmlSchemaValDecimal;
118 typedef xmlSchemaValDecimal *xmlSchemaValDecimalPtr;
119 struct _xmlSchemaValDecimal {
120     /* would use long long but not portable */
121     unsigned long lo;
122     unsigned long mi;
123     unsigned long hi;
124     unsigned int extra;
125     unsigned int sign:1;
126     unsigned int frac:7;
127     unsigned int total:8;
128 };
129
130 typedef struct _xmlSchemaValQName xmlSchemaValQName;
131 typedef xmlSchemaValQName *xmlSchemaValQNamePtr;
132 struct _xmlSchemaValQName {
133     xmlChar *name;
134     xmlChar *uri;
135 };
136
137 typedef struct _xmlSchemaValHex xmlSchemaValHex;
138 typedef xmlSchemaValHex *xmlSchemaValHexPtr;
139 struct _xmlSchemaValHex {
140     xmlChar     *str;
141     unsigned int total;
142 };
143
144 struct _xmlSchemaVal {
145     xmlSchemaValType type;
146     union {
147         xmlSchemaValDecimal     decimal;
148         xmlSchemaValDate        date;
149         xmlSchemaValDuration    dur;
150         xmlSchemaValQName       qname;
151         xmlSchemaValHex         hex;
152         float                   f;
153         double                  d;
154         int                     b;
155         xmlChar                *str;
156     } value;
157 };
158
159 static int xmlSchemaTypesInitialized = 0;
160 static xmlHashTablePtr xmlSchemaTypesBank = NULL;
161
162 /*
163  * Basic types
164  */
165 static xmlSchemaTypePtr xmlSchemaTypeStringDef = NULL;
166 static xmlSchemaTypePtr xmlSchemaTypeAnyTypeDef = NULL;
167 static xmlSchemaTypePtr xmlSchemaTypeAnySimpleTypeDef = NULL;
168 static xmlSchemaTypePtr xmlSchemaTypeDecimalDef = NULL;
169 static xmlSchemaTypePtr xmlSchemaTypeDatetimeDef = NULL;
170 static xmlSchemaTypePtr xmlSchemaTypeDateDef = NULL;
171 static xmlSchemaTypePtr xmlSchemaTypeTimeDef = NULL;
172 static xmlSchemaTypePtr xmlSchemaTypeGYearDef = NULL;
173 static xmlSchemaTypePtr xmlSchemaTypeGYearMonthDef = NULL;
174 static xmlSchemaTypePtr xmlSchemaTypeGDayDef = NULL;
175 static xmlSchemaTypePtr xmlSchemaTypeGMonthDayDef = NULL;
176 static xmlSchemaTypePtr xmlSchemaTypeGMonthDef = NULL;
177 static xmlSchemaTypePtr xmlSchemaTypeDurationDef = NULL;
178 static xmlSchemaTypePtr xmlSchemaTypeFloatDef = NULL;
179 static xmlSchemaTypePtr xmlSchemaTypeBooleanDef = NULL;
180 static xmlSchemaTypePtr xmlSchemaTypeDoubleDef = NULL;
181 static xmlSchemaTypePtr xmlSchemaTypeHexBinaryDef = NULL;
182 static xmlSchemaTypePtr xmlSchemaTypeAnyURIDef = NULL;
183
184 /*
185  * Derived types
186  */
187 static xmlSchemaTypePtr xmlSchemaTypePositiveIntegerDef = NULL;
188 static xmlSchemaTypePtr xmlSchemaTypeNonPositiveIntegerDef = NULL;
189 static xmlSchemaTypePtr xmlSchemaTypeNegativeIntegerDef = NULL;
190 static xmlSchemaTypePtr xmlSchemaTypeNonNegativeIntegerDef = NULL;
191 static xmlSchemaTypePtr xmlSchemaTypeIntegerDef = NULL;
192 static xmlSchemaTypePtr xmlSchemaTypeLongDef = NULL;
193 static xmlSchemaTypePtr xmlSchemaTypeIntDef = NULL;
194 static xmlSchemaTypePtr xmlSchemaTypeShortDef = NULL;
195 static xmlSchemaTypePtr xmlSchemaTypeByteDef = NULL;
196 static xmlSchemaTypePtr xmlSchemaTypeUnsignedLongDef = NULL;
197 static xmlSchemaTypePtr xmlSchemaTypeUnsignedIntDef = NULL;
198 static xmlSchemaTypePtr xmlSchemaTypeUnsignedShortDef = NULL;
199 static xmlSchemaTypePtr xmlSchemaTypeUnsignedByteDef = NULL;
200 static xmlSchemaTypePtr xmlSchemaTypeNormStringDef = NULL;
201 static xmlSchemaTypePtr xmlSchemaTypeTokenDef = NULL;
202 static xmlSchemaTypePtr xmlSchemaTypeLanguageDef = NULL;
203 static xmlSchemaTypePtr xmlSchemaTypeNameDef = NULL;
204 static xmlSchemaTypePtr xmlSchemaTypeQNameDef = NULL;
205 static xmlSchemaTypePtr xmlSchemaTypeNCNameDef = NULL;
206 static xmlSchemaTypePtr xmlSchemaTypeIdDef = NULL;
207 static xmlSchemaTypePtr xmlSchemaTypeIdrefDef = NULL;
208 static xmlSchemaTypePtr xmlSchemaTypeIdrefsDef = NULL;
209 static xmlSchemaTypePtr xmlSchemaTypeEntityDef = NULL;
210 static xmlSchemaTypePtr xmlSchemaTypeEntitiesDef = NULL;
211 static xmlSchemaTypePtr xmlSchemaTypeNotationDef = NULL;
212 static xmlSchemaTypePtr xmlSchemaTypeNmtokenDef = NULL;
213 static xmlSchemaTypePtr xmlSchemaTypeNmtokensDef = NULL;
214
215 /*
216  * xmlSchemaInitBasicType:
217  * @name:  the type name
218  * @type:  the value type associated
219  *
220  * Initialize one default type
221  */
222 static xmlSchemaTypePtr
223 xmlSchemaInitBasicType(const char *name, xmlSchemaValType type) {
224     xmlSchemaTypePtr ret;
225
226     ret = (xmlSchemaTypePtr) xmlMalloc(sizeof(xmlSchemaType));
227     if (ret == NULL) {
228         xmlGenericError(xmlGenericErrorContext,
229                 "Could not initilize type %s: out of memory\n", name);
230         return(NULL);
231     }
232     memset(ret, 0, sizeof(xmlSchemaType));
233     ret->name = xmlStrdup((const xmlChar *)name);
234     ret->type = XML_SCHEMA_TYPE_BASIC;
235     ret->flags = type;
236     ret->contentType = XML_SCHEMA_CONTENT_BASIC;
237     xmlHashAddEntry2(xmlSchemaTypesBank, ret->name,
238                      XML_SCHEMAS_NAMESPACE_NAME, ret);
239     return(ret);
240 }
241
242 /*
243  * xmlSchemaInitTypes:
244  *
245  * Initialize the default XML Schemas type library
246  */
247 void
248 xmlSchemaInitTypes(void)
249 {
250     if (xmlSchemaTypesInitialized != 0)
251         return;
252     xmlSchemaTypesBank = xmlHashCreate(40);
253
254     /*
255      * primitive datatypes
256      */
257     xmlSchemaTypeStringDef = xmlSchemaInitBasicType("string",
258                                                     XML_SCHEMAS_STRING);
259     xmlSchemaTypeAnyTypeDef = xmlSchemaInitBasicType("anyType",
260                                                      XML_SCHEMAS_UNKNOWN);
261     xmlSchemaTypeAnySimpleTypeDef = xmlSchemaInitBasicType("anySimpleType",
262                                                            XML_SCHEMAS_UNKNOWN);
263     xmlSchemaTypeDecimalDef = xmlSchemaInitBasicType("decimal",
264                                                      XML_SCHEMAS_DECIMAL);
265     xmlSchemaTypeDateDef = xmlSchemaInitBasicType("date",
266                                                   XML_SCHEMAS_DATE);
267     xmlSchemaTypeDatetimeDef = xmlSchemaInitBasicType("dateTime",
268                                                       XML_SCHEMAS_DATETIME);
269     xmlSchemaTypeTimeDef = xmlSchemaInitBasicType("time",
270                                                   XML_SCHEMAS_TIME);
271     xmlSchemaTypeGYearDef = xmlSchemaInitBasicType("gYear",
272                                                    XML_SCHEMAS_GYEAR);
273     xmlSchemaTypeGYearMonthDef = xmlSchemaInitBasicType("gYearMonth",
274                                                         XML_SCHEMAS_GYEARMONTH);
275     xmlSchemaTypeGMonthDef = xmlSchemaInitBasicType("gMonth",
276                                                     XML_SCHEMAS_GMONTH);
277     xmlSchemaTypeGMonthDayDef = xmlSchemaInitBasicType("gMonthDay",
278                                                        XML_SCHEMAS_GMONTHDAY);
279     xmlSchemaTypeGDayDef = xmlSchemaInitBasicType("gDay",
280                                                   XML_SCHEMAS_GDAY);
281     xmlSchemaTypeDurationDef = xmlSchemaInitBasicType("duration",
282                                                       XML_SCHEMAS_DURATION);
283     xmlSchemaTypeFloatDef = xmlSchemaInitBasicType("float",
284                                                    XML_SCHEMAS_FLOAT);
285     xmlSchemaTypeDoubleDef = xmlSchemaInitBasicType("double",
286                                                     XML_SCHEMAS_DOUBLE);
287     xmlSchemaTypeBooleanDef = xmlSchemaInitBasicType("boolean",
288                                                      XML_SCHEMAS_BOOLEAN);
289     xmlSchemaTypeAnyURIDef = xmlSchemaInitBasicType("anyURI",
290                                                     XML_SCHEMAS_ANYURI);
291     xmlSchemaTypeHexBinaryDef = xmlSchemaInitBasicType("hexBinary",
292                                                      XML_SCHEMAS_HEXBINARY);
293
294     /*
295      * derived datatypes
296      */
297     xmlSchemaTypeIntegerDef = xmlSchemaInitBasicType("integer",
298                                                      XML_SCHEMAS_INTEGER);;
299     xmlSchemaTypeNonPositiveIntegerDef =
300         xmlSchemaInitBasicType("nonPositiveInteger",
301                                XML_SCHEMAS_NPINTEGER);;
302     xmlSchemaTypeNegativeIntegerDef =
303         xmlSchemaInitBasicType("negativeInteger", XML_SCHEMAS_NINTEGER);;
304     xmlSchemaTypeLongDef =
305         xmlSchemaInitBasicType("long", XML_SCHEMAS_LONG);;
306     xmlSchemaTypeIntDef = xmlSchemaInitBasicType("int", XML_SCHEMAS_INT);;
307     xmlSchemaTypeShortDef = xmlSchemaInitBasicType("short",
308                                                    XML_SCHEMAS_SHORT);;
309     xmlSchemaTypeByteDef = xmlSchemaInitBasicType("byte",
310                                                   XML_SCHEMAS_BYTE);;
311     xmlSchemaTypeNonNegativeIntegerDef =
312         xmlSchemaInitBasicType("nonNegativeInteger",
313                                XML_SCHEMAS_NNINTEGER);
314     xmlSchemaTypeUnsignedLongDef =
315         xmlSchemaInitBasicType("unsignedLong", XML_SCHEMAS_ULONG);;
316     xmlSchemaTypeUnsignedIntDef =
317         xmlSchemaInitBasicType("unsignedInt", XML_SCHEMAS_UINT);;
318     xmlSchemaTypeUnsignedShortDef =
319         xmlSchemaInitBasicType("unsignedShort", XML_SCHEMAS_USHORT);;
320     xmlSchemaTypeUnsignedByteDef =
321         xmlSchemaInitBasicType("unsignedByte", XML_SCHEMAS_UBYTE);;
322     xmlSchemaTypePositiveIntegerDef =
323         xmlSchemaInitBasicType("positiveInteger", XML_SCHEMAS_PINTEGER);
324
325     xmlSchemaTypeNormStringDef = xmlSchemaInitBasicType("normalizedString",
326                                                         XML_SCHEMAS_NORMSTRING);
327     xmlSchemaTypeTokenDef = xmlSchemaInitBasicType("token",
328                                                    XML_SCHEMAS_TOKEN);
329     xmlSchemaTypeLanguageDef = xmlSchemaInitBasicType("language",
330                                                       XML_SCHEMAS_LANGUAGE);
331     xmlSchemaTypeIdDef = xmlSchemaInitBasicType("ID", XML_SCHEMAS_ID);
332     xmlSchemaTypeIdrefDef = xmlSchemaInitBasicType("IDREF",
333                                                    XML_SCHEMAS_IDREF);
334     xmlSchemaTypeIdrefsDef = xmlSchemaInitBasicType("IDREFS",
335                                                     XML_SCHEMAS_IDREFS);
336     xmlSchemaTypeEntityDef = xmlSchemaInitBasicType("ENTITY",
337                                                     XML_SCHEMAS_ENTITY);
338     xmlSchemaTypeEntitiesDef = xmlSchemaInitBasicType("ENTITIES",
339                                                       XML_SCHEMAS_ENTITIES);
340     xmlSchemaTypeNotationDef = xmlSchemaInitBasicType("NOTATION",
341                                                     XML_SCHEMAS_NOTATION);
342     xmlSchemaTypeNameDef = xmlSchemaInitBasicType("Name",
343                                                   XML_SCHEMAS_NAME);
344     xmlSchemaTypeQNameDef = xmlSchemaInitBasicType("QName",
345                                                    XML_SCHEMAS_QNAME);
346     xmlSchemaTypeNCNameDef = xmlSchemaInitBasicType("NCName",
347                                                     XML_SCHEMAS_NCNAME);
348     xmlSchemaTypeNmtokenDef = xmlSchemaInitBasicType("NMTOKEN",
349                                                      XML_SCHEMAS_NMTOKEN);
350     xmlSchemaTypeNmtokensDef = xmlSchemaInitBasicType("NMTOKENS",
351                                                       XML_SCHEMAS_NMTOKENS);
352     xmlSchemaTypesInitialized = 1;
353 }
354
355 /**
356  * xmlSchemaCleanupTypes:
357  *
358  * Cleanup the default XML Schemas type library
359  */
360 void    
361 xmlSchemaCleanupTypes(void) {
362     if (xmlSchemaTypesInitialized == 0)
363         return;
364     xmlHashFree(xmlSchemaTypesBank, (xmlHashDeallocator) xmlSchemaFreeType);
365     xmlSchemaTypesInitialized = 0;
366 }
367
368 /**
369  * xmlSchemaNewValue:
370  * @type:  the value type
371  *
372  * Allocate a new simple type value
373  *
374  * Returns a pointer to the new value or NULL in case of error
375  */
376 static xmlSchemaValPtr
377 xmlSchemaNewValue(xmlSchemaValType type) {
378     xmlSchemaValPtr value;
379
380     value = (xmlSchemaValPtr) xmlMalloc(sizeof(xmlSchemaVal));
381     if (value == NULL) {
382         return(NULL);
383     }
384     memset(value, 0, sizeof(xmlSchemaVal));
385     value->type = type;
386     return(value);
387 }
388
389 /**
390  * xmlSchemaFreeValue:
391  * @value:  the value to free
392  *
393  * Cleanup the default XML Schemas type library
394  */
395 void    
396 xmlSchemaFreeValue(xmlSchemaValPtr value) {
397     if (value == NULL)
398         return;
399     switch (value->type) {
400         case XML_SCHEMAS_STRING:
401         case XML_SCHEMAS_NORMSTRING:
402         case XML_SCHEMAS_TOKEN:
403         case XML_SCHEMAS_LANGUAGE:
404         case XML_SCHEMAS_NMTOKEN:
405         case XML_SCHEMAS_NMTOKENS:
406         case XML_SCHEMAS_NAME:
407         case XML_SCHEMAS_NCNAME:
408         case XML_SCHEMAS_ID:
409         case XML_SCHEMAS_IDREF:
410         case XML_SCHEMAS_IDREFS:
411         case XML_SCHEMAS_ENTITY:
412         case XML_SCHEMAS_ENTITIES:
413         case XML_SCHEMAS_NOTATION:
414         case XML_SCHEMAS_ANYURI:
415             if (value->value.str != NULL)
416                 xmlFree(value->value.str);
417             break;
418         case XML_SCHEMAS_QNAME:
419             if (value->value.qname.uri != NULL)
420                 xmlFree(value->value.qname.uri);
421             if (value->value.qname.name != NULL)
422                 xmlFree(value->value.qname.name);
423             break;
424         case XML_SCHEMAS_HEXBINARY:
425             if (value->value.hex.str != NULL)
426                 xmlFree(value->value.hex.str);
427             break;
428         default:
429             break;
430     }
431     xmlFree(value);
432 }
433
434 /**
435  * xmlSchemaGetPredefinedType:
436  * @name: the type name
437  * @ns:  the URI of the namespace usually "http://www.w3.org/2001/XMLSchema"
438  *
439  * Lookup a type in the default XML Schemas type library
440  *
441  * Returns the type if found, NULL otherwise
442  */
443 xmlSchemaTypePtr
444 xmlSchemaGetPredefinedType(const xmlChar *name, const xmlChar *ns) {
445     if (xmlSchemaTypesInitialized == 0)
446         xmlSchemaInitTypes();
447     if (name == NULL)
448         return(NULL);
449     return((xmlSchemaTypePtr) xmlHashLookup2(xmlSchemaTypesBank, name, ns));
450 }
451
452 /****************************************************************
453  *                                                              *
454  *              Convenience macros and functions                *
455  *                                                              *
456  ****************************************************************/
457
458 #define IS_TZO_CHAR(c)                                          \
459         ((c == 0) || (c == 'Z') || (c == '+') || (c == '-'))
460
461 #define VALID_YEAR(yr)          (yr != 0)
462 #define VALID_MONTH(mon)        ((mon >= 1) && (mon <= 12))
463 /* VALID_DAY should only be used when month is unknown */
464 #define VALID_DAY(day)          ((day >= 1) && (day <= 31))
465 #define VALID_HOUR(hr)          ((hr >= 0) && (hr <= 23))
466 #define VALID_MIN(min)          ((min >= 0) && (min <= 59))
467 #define VALID_SEC(sec)          ((sec >= 0) && (sec < 60))
468 #define VALID_TZO(tzo)          ((tzo > -1440) && (tzo < 1440))
469 #define IS_LEAP(y)                                              \
470         (((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0))
471
472 static const long daysInMonth[12] =
473         { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
474 static const long daysInMonthLeap[12] =
475         { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
476
477 #define MAX_DAYINMONTH(yr,mon)                                  \
478         (IS_LEAP(yr) ? daysInMonthLeap[mon - 1] : daysInMonth[mon - 1])
479
480 #define VALID_MDAY(dt)                                          \
481         (IS_LEAP(dt->year) ?                                    \
482             (dt->day <= daysInMonthLeap[dt->mon - 1]) :         \
483             (dt->day <= daysInMonth[dt->mon - 1]))
484
485 #define VALID_DATE(dt)                                          \
486         (VALID_YEAR(dt->year) && VALID_MONTH(dt->mon) && VALID_MDAY(dt))
487
488 #define VALID_TIME(dt)                                          \
489         (VALID_HOUR(dt->hour) && VALID_MIN(dt->min) &&          \
490          VALID_SEC(dt->sec) && VALID_TZO(dt->tzo))
491
492 #define VALID_DATETIME(dt)                                      \
493         (VALID_DATE(dt) && VALID_TIME(dt))
494
495 #define SECS_PER_MIN            (60)
496 #define SECS_PER_HOUR           (60 * SECS_PER_MIN)
497 #define SECS_PER_DAY            (24 * SECS_PER_HOUR)
498
499 static const long dayInYearByMonth[12] =
500         { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
501 static const long dayInLeapYearByMonth[12] =
502         { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 };
503
504 #define DAY_IN_YEAR(day, month, year)                           \
505         ((IS_LEAP(year) ?                                       \
506                 dayInLeapYearByMonth[month - 1] :               \
507                 dayInYearByMonth[month - 1]) + day)
508
509 #ifdef DEBUG
510 #define DEBUG_DATE(dt)                                                  \
511     xmlGenericError(xmlGenericErrorContext,                             \
512         "type=%o %04ld-%02u-%02uT%02u:%02u:%03f",                       \
513         dt->type,dt->value.date.year,dt->value.date.mon,                \
514         dt->value.date.day,dt->value.date.hour,dt->value.date.min,      \
515         dt->value.date.sec);                                            \
516     if (dt->value.date.tz_flag)                                         \
517         if (dt->value.date.tzo != 0)                                    \
518             xmlGenericError(xmlGenericErrorContext,                     \
519                 "%+05d\n",dt->value.date.tzo);                          \
520         else                                                            \
521             xmlGenericError(xmlGenericErrorContext, "Z\n");             \
522     else                                                                \
523         xmlGenericError(xmlGenericErrorContext,"\n")
524 #else
525 #define DEBUG_DATE(dt)
526 #endif
527
528 /**
529  * _xmlSchemaParseGYear:
530  * @dt:  pointer to a date structure
531  * @str: pointer to the string to analyze
532  *
533  * Parses a xs:gYear without time zone and fills in the appropriate
534  * field of the @dt structure. @str is updated to point just after the
535  * xs:gYear. It is supposed that @dt->year is big enough to contain
536  * the year.
537  *
538  * Returns 0 or the error code
539  */
540 static int
541 _xmlSchemaParseGYear (xmlSchemaValDatePtr dt, const xmlChar **str) {
542     const xmlChar *cur = *str, *firstChar;
543     int isneg = 0, digcnt = 0;
544
545     if (((*cur < '0') || (*cur > '9')) &&
546         (*cur != '-') && (*cur != '+'))
547         return -1;
548
549     if (*cur == '-') {
550         isneg = 1;
551         cur++;
552     }
553
554     firstChar = cur;
555
556     while ((*cur >= '0') && (*cur <= '9')) {
557         dt->year = dt->year * 10 + (*cur - '0');
558         cur++;
559         digcnt++;
560     }
561
562     /* year must be at least 4 digits (CCYY); over 4
563      * digits cannot have a leading zero. */
564     if ((digcnt < 4) || ((digcnt > 4) && (*firstChar == '0')))
565         return 1;
566
567     if (isneg)
568         dt->year = - dt->year;
569
570     if (!VALID_YEAR(dt->year))
571         return 2;
572
573     *str = cur;
574     return 0;
575 }
576
577 /**
578  * PARSE_2_DIGITS:
579  * @num:  the integer to fill in
580  * @cur:  an #xmlChar *
581  * @invalid: an integer
582  *
583  * Parses a 2-digits integer and updates @num with the value. @cur is
584  * updated to point just after the integer.
585  * In case of error, @invalid is set to %TRUE, values of @num and
586  * @cur are undefined.
587  */
588 #define PARSE_2_DIGITS(num, cur, invalid)                       \
589         if ((cur[0] < '0') || (cur[0] > '9') ||                 \
590             (cur[1] < '0') || (cur[1] > '9'))                   \
591             invalid = 1;                                        \
592         else                                                    \
593             num = (cur[0] - '0') * 10 + (cur[1] - '0');         \
594         cur += 2;
595
596 /**
597  * PARSE_FLOAT:
598  * @num:  the double to fill in
599  * @cur:  an #xmlChar *
600  * @invalid: an integer
601  *
602  * Parses a float and updates @num with the value. @cur is
603  * updated to point just after the float. The float must have a
604  * 2-digits integer part and may or may not have a decimal part.
605  * In case of error, @invalid is set to %TRUE, values of @num and
606  * @cur are undefined.
607  */
608 #define PARSE_FLOAT(num, cur, invalid)                          \
609         PARSE_2_DIGITS(num, cur, invalid);                      \
610         if (!invalid && (*cur == '.')) {                        \
611             double mult = 1;                                    \
612             cur++;                                              \
613             if ((*cur < '0') || (*cur > '9'))                   \
614                 invalid = 1;                                    \
615             while ((*cur >= '0') && (*cur <= '9')) {            \
616                 mult /= 10;                                     \
617                 num += (*cur - '0') * mult;                     \
618                 cur++;                                          \
619             }                                                   \
620         }
621
622 /**
623  * _xmlSchemaParseGMonth:
624  * @dt:  pointer to a date structure
625  * @str: pointer to the string to analyze
626  *
627  * Parses a xs:gMonth without time zone and fills in the appropriate
628  * field of the @dt structure. @str is updated to point just after the
629  * xs:gMonth.
630  *
631  * Returns 0 or the error code
632  */
633 static int
634 _xmlSchemaParseGMonth (xmlSchemaValDatePtr dt, const xmlChar **str) {
635     const xmlChar *cur = *str;
636     int ret = 0;
637
638     PARSE_2_DIGITS(dt->mon, cur, ret);
639     if (ret != 0)
640         return ret;
641
642     if (!VALID_MONTH(dt->mon))
643         return 2;
644
645     *str = cur;
646     return 0;
647 }
648
649 /**
650  * _xmlSchemaParseGDay:
651  * @dt:  pointer to a date structure
652  * @str: pointer to the string to analyze
653  *
654  * Parses a xs:gDay without time zone and fills in the appropriate
655  * field of the @dt structure. @str is updated to point just after the
656  * xs:gDay.
657  *
658  * Returns 0 or the error code
659  */
660 static int
661 _xmlSchemaParseGDay (xmlSchemaValDatePtr dt, const xmlChar **str) {
662     const xmlChar *cur = *str;
663     int ret = 0;
664
665     PARSE_2_DIGITS(dt->day, cur, ret);
666     if (ret != 0)
667         return ret;
668
669     if (!VALID_DAY(dt->day))
670         return 2;
671
672     *str = cur;
673     return 0;
674 }
675
676 /**
677  * _xmlSchemaParseTime:
678  * @dt:  pointer to a date structure
679  * @str: pointer to the string to analyze
680  *
681  * Parses a xs:time without time zone and fills in the appropriate
682  * fields of the @dt structure. @str is updated to point just after the
683  * xs:time.
684  * In case of error, values of @dt fields are undefined.
685  *
686  * Returns 0 or the error code
687  */
688 static int
689 _xmlSchemaParseTime (xmlSchemaValDatePtr dt, const xmlChar **str) {
690     const xmlChar *cur = *str;
691     unsigned int hour = 0; /* use temp var in case str is not xs:time */
692     int ret = 0;
693
694     PARSE_2_DIGITS(hour, cur, ret);
695     if (ret != 0)
696         return ret;
697
698     if (*cur != ':')
699         return 1;
700     cur++;
701
702     /* the ':' insures this string is xs:time */
703     dt->hour = hour;
704
705     PARSE_2_DIGITS(dt->min, cur, ret);
706     if (ret != 0)
707         return ret;
708
709     if (*cur != ':')
710         return 1;
711     cur++;
712
713     PARSE_FLOAT(dt->sec, cur, ret);
714     if (ret != 0)
715         return ret;
716
717     if (!VALID_TIME(dt))
718         return 2;
719
720     *str = cur;
721     return 0;
722 }
723
724 /**
725  * _xmlSchemaParseTimeZone:
726  * @dt:  pointer to a date structure
727  * @str: pointer to the string to analyze
728  *
729  * Parses a time zone without time zone and fills in the appropriate
730  * field of the @dt structure. @str is updated to point just after the
731  * time zone.
732  *
733  * Returns 0 or the error code
734  */
735 static int
736 _xmlSchemaParseTimeZone (xmlSchemaValDatePtr dt, const xmlChar **str) {
737     const xmlChar *cur = *str;
738     int ret = 0;
739
740     if (str == NULL)
741         return -1;
742
743     switch (*cur) {
744     case 0:
745         dt->tz_flag = 0;
746         dt->tzo = 0;
747         break;
748
749     case 'Z':
750         dt->tz_flag = 1;
751         dt->tzo = 0;
752         cur++;
753         break;
754
755     case '+':
756     case '-': {
757         int isneg = 0, tmp = 0;
758         isneg = (*cur == '-');
759
760         cur++;
761
762         PARSE_2_DIGITS(tmp, cur, ret);
763         if (ret != 0)
764             return ret;
765         if (!VALID_HOUR(tmp))
766             return 2;
767
768         if (*cur != ':')
769             return 1;
770         cur++;
771
772         dt->tzo = tmp * 60;
773
774         PARSE_2_DIGITS(tmp, cur, ret);
775         if (ret != 0)
776             return ret;
777         if (!VALID_MIN(tmp))
778             return 2;
779
780         dt->tzo += tmp;
781         if (isneg)
782             dt->tzo = - dt->tzo;
783
784         if (!VALID_TZO(dt->tzo))
785             return 2;
786
787         dt->tz_flag = 1;
788         break;
789       }
790     default:
791         return 1;
792     }
793
794     *str = cur;
795     return 0;
796 }
797
798 /****************************************************************
799  *                                                              *
800  *      XML Schema Dates/Times Datatypes Handling               *
801  *                                                              *
802  ****************************************************************/
803
804 /**
805  * PARSE_DIGITS:
806  * @num:  the integer to fill in
807  * @cur:  an #xmlChar *
808  * @num_type: an integer flag
809  *
810  * Parses a digits integer and updates @num with the value. @cur is
811  * updated to point just after the integer.
812  * In case of error, @num_type is set to -1, values of @num and
813  * @cur are undefined.
814  */
815 #define PARSE_DIGITS(num, cur, num_type)                        \
816         if ((*cur < '0') || (*cur > '9'))                       \
817             num_type = -1;                                      \
818         else                                                    \
819             while ((*cur >= '0') && (*cur <= '9')) {            \
820                 num = num * 10 + (*cur - '0');                  \
821                 cur++;                                          \
822             }
823
824 /**
825  * PARSE_NUM:
826  * @num:  the double to fill in
827  * @cur:  an #xmlChar *
828  * @num_type: an integer flag
829  *
830  * Parses a float or integer and updates @num with the value. @cur is
831  * updated to point just after the number. If the number is a float,
832  * then it must have an integer part and a decimal part; @num_type will
833  * be set to 1. If there is no decimal part, @num_type is set to zero.
834  * In case of error, @num_type is set to -1, values of @num and
835  * @cur are undefined.
836  */
837 #define PARSE_NUM(num, cur, num_type)                           \
838         num = 0;                                                \
839         PARSE_DIGITS(num, cur, num_type);                       \
840         if (!num_type && (*cur == '.')) {                       \
841             double mult = 1;                                    \
842             cur++;                                              \
843             if ((*cur < '0') || (*cur > '9'))                   \
844                 num_type = -1;                                  \
845             else                                                \
846                 num_type = 1;                                   \
847             while ((*cur >= '0') && (*cur <= '9')) {            \
848                 mult /= 10;                                     \
849                 num += (*cur - '0') * mult;                     \
850                 cur++;                                          \
851             }                                                   \
852         }
853
854 /**
855  * xmlSchemaValidateDates:
856  * @type: the expected type or XML_SCHEMAS_UNKNOWN
857  * @dateTime:  string to analyze
858  * @val:  the return computed value
859  *
860  * Check that @dateTime conforms to the lexical space of one of the date types.
861  * if true a value is computed and returned in @val.
862  *
863  * Returns 0 if this validates, a positive error code number otherwise
864  *         and -1 in case of internal or API error.
865  */
866 static int
867 xmlSchemaValidateDates (xmlSchemaValType type,
868                         const xmlChar *dateTime, xmlSchemaValPtr *val) {
869     xmlSchemaValPtr dt;
870     int ret;
871     const xmlChar *cur = dateTime;
872
873 #define RETURN_TYPE_IF_VALID(t)                                 \
874     if (IS_TZO_CHAR(*cur)) {                                    \
875         ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur); \
876         if (ret == 0) {                                         \
877             if (*cur != 0)                                      \
878                 goto error;                                     \
879             dt->type = t;                                       \
880             goto done;                                          \
881         }                                                       \
882     }
883
884     if (dateTime == NULL)
885         return -1;
886
887     if ((*cur != '-') && (*cur < '0') && (*cur > '9'))
888         return 1;
889
890     dt = xmlSchemaNewValue(XML_SCHEMAS_UNKNOWN);
891     if (dt == NULL)
892         return -1;
893
894     if ((cur[0] == '-') && (cur[1] == '-')) {
895         /*
896          * It's an incomplete date (xs:gMonthDay, xs:gMonth or
897          * xs:gDay)
898          */
899         cur += 2;
900
901         /* is it an xs:gDay? */
902         if (*cur == '-') {
903             if (type == XML_SCHEMAS_GMONTH)
904                 goto error;
905           ++cur;
906             ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
907             if (ret != 0)
908                 goto error;
909
910             RETURN_TYPE_IF_VALID(XML_SCHEMAS_GDAY);
911
912             goto error;
913         }
914
915         /*
916          * it should be an xs:gMonthDay or xs:gMonth
917          */
918         ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
919         if (ret != 0)
920             goto error;
921
922         /*
923          * a '-' char could indicate this type is xs:gMonthDay or
924          * a negative time zone offset. Check for xs:gMonthDay first.
925          * Also the first three char's of a negative tzo (-MM:SS) can
926          * appear to be a valid day; so even if the day portion
927          * of the xs:gMonthDay verifies, we must insure it was not
928          * a tzo.
929          */
930         if (*cur == '-') {
931             const xmlChar *rewnd = cur;
932             cur++;
933
934             ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
935             if ((ret == 0) && ((*cur == 0) || (*cur != ':'))) {
936
937                 /*
938                  * we can use the VALID_MDAY macro to validate the month
939                  * and day because the leap year test will flag year zero
940                  * as a leap year (even though zero is an invalid year).
941                  */
942                 if (VALID_MDAY((&(dt->value.date)))) {
943
944                     RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTHDAY);
945
946                     goto error;
947                 }
948             }
949
950             /*
951              * not xs:gMonthDay so rewind and check if just xs:gMonth
952              * with an optional time zone.
953              */
954             cur = rewnd;
955         }
956
957         RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTH);
958
959         goto error;
960     }
961
962     /*
963      * It's a right-truncated date or an xs:time.
964      * Try to parse an xs:time then fallback on right-truncated dates.
965      */
966     if ((*cur >= '0') && (*cur <= '9')) {
967         ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
968         if (ret == 0) {
969             /* it's an xs:time */
970             RETURN_TYPE_IF_VALID(XML_SCHEMAS_TIME);
971         }
972     }
973
974     /* fallback on date parsing */
975     cur = dateTime;
976
977     ret = _xmlSchemaParseGYear(&(dt->value.date), &cur);
978     if (ret != 0)
979         goto error;
980
981     /* is it an xs:gYear? */
982     RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEAR);
983
984     if (*cur != '-')
985         goto error;
986     cur++;
987
988     ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
989     if (ret != 0)
990         goto error;
991
992     /* is it an xs:gYearMonth? */
993     RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEARMONTH);
994
995     if (*cur != '-')
996         goto error;
997     cur++;
998
999     ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
1000     if ((ret != 0) || !VALID_DATE((&(dt->value.date))))
1001         goto error;
1002
1003     /* is it an xs:date? */
1004     RETURN_TYPE_IF_VALID(XML_SCHEMAS_DATE);
1005
1006     if (*cur != 'T')
1007         goto error;
1008     cur++;
1009
1010     /* it should be an xs:dateTime */
1011     ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
1012     if (ret != 0)
1013         goto error;
1014
1015     ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur);
1016     if ((ret != 0) || (*cur != 0) || !VALID_DATETIME((&(dt->value.date))))
1017         goto error;
1018
1019
1020     dt->type = XML_SCHEMAS_DATETIME;
1021
1022 done:
1023 #if 1
1024     if ((type != XML_SCHEMAS_UNKNOWN) && (type != dt->type))
1025         goto error;
1026 #else
1027     /*
1028      * insure the parsed type is equal to or less significant (right
1029      * truncated) than the desired type.
1030      */
1031     if ((type != XML_SCHEMAS_UNKNOWN) && (type != dt->type)) {
1032
1033         /* time only matches time */
1034         if ((type == XML_SCHEMAS_TIME) && (dt->type == XML_SCHEMAS_TIME))
1035             goto error;
1036
1037         if ((type == XML_SCHEMAS_DATETIME) &&
1038             ((dt->type != XML_SCHEMAS_DATE) ||
1039              (dt->type != XML_SCHEMAS_GYEARMONTH) ||
1040              (dt->type != XML_SCHEMAS_GYEAR)))
1041             goto error;
1042
1043         if ((type == XML_SCHEMAS_DATE) &&
1044             ((dt->type != XML_SCHEMAS_GYEAR) ||
1045              (dt->type != XML_SCHEMAS_GYEARMONTH)))
1046             goto error;
1047
1048         if ((type == XML_SCHEMAS_GYEARMONTH) && (dt->type != XML_SCHEMAS_GYEAR))
1049             goto error;
1050
1051         if ((type == XML_SCHEMAS_GMONTHDAY) && (dt->type != XML_SCHEMAS_GMONTH))
1052             goto error;
1053     }
1054 #endif
1055
1056     if (val != NULL)
1057         *val = dt;
1058     else
1059         xmlSchemaFreeValue(dt);
1060
1061     return 0;
1062
1063 error:
1064     if (dt != NULL)
1065         xmlSchemaFreeValue(dt);
1066     return 1;
1067 }
1068
1069 /**
1070  * xmlSchemaValidateDuration:
1071  * @type: the predefined type
1072  * @duration:  string to analyze
1073  * @val:  the return computed value
1074  *
1075  * Check that @duration conforms to the lexical space of the duration type.
1076  * if true a value is computed and returned in @val.
1077  *
1078  * Returns 0 if this validates, a positive error code number otherwise
1079  *         and -1 in case of internal or API error.
1080  */
1081 static int
1082 xmlSchemaValidateDuration (xmlSchemaTypePtr type ATTRIBUTE_UNUSED,
1083                            const xmlChar *duration, xmlSchemaValPtr *val) {
1084     const xmlChar  *cur = duration;
1085     xmlSchemaValPtr dur;
1086     int isneg = 0;
1087     unsigned int seq = 0;
1088     double         num;
1089     int            num_type = 0;  /* -1 = invalid, 0 = int, 1 = floating */
1090     const xmlChar  desig[]  = {'Y', 'M', 'D', 'H', 'M', 'S'};
1091     const double   multi[]  = { 0.0, 0.0, 86400.0, 3600.0, 60.0, 1.0, 0.0};
1092
1093     if (duration == NULL)
1094         return -1;
1095
1096     if (*cur == '-') {
1097         isneg = 1;
1098         cur++;
1099     }
1100
1101     /* duration must start with 'P' (after sign) */
1102     if (*cur++ != 'P')
1103         return 1;
1104
1105     if (*cur == 0)
1106         return 1;
1107
1108     dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
1109     if (dur == NULL)
1110         return -1;
1111
1112     while (*cur != 0) {
1113
1114         /* input string should be empty or invalid date/time item */
1115         if (seq >= sizeof(desig))
1116             goto error;
1117
1118         /* T designator must be present for time items */
1119         if (*cur == 'T') {
1120             if (seq <= 3) {
1121                 seq = 3;
1122                 cur++;
1123             } else
1124                 return 1;
1125         } else if (seq == 3)
1126             goto error;
1127
1128         /* parse the number portion of the item */
1129         PARSE_NUM(num, cur, num_type);
1130
1131         if ((num_type == -1) || (*cur == 0))
1132             goto error;
1133
1134         /* update duration based on item type */
1135         while (seq < sizeof(desig)) {
1136             if (*cur == desig[seq]) {
1137
1138                 /* verify numeric type; only seconds can be float */
1139                 if ((num_type != 0) && (seq < (sizeof(desig)-1)))
1140                     goto error;
1141
1142                 switch (seq) {
1143                     case 0:
1144                         dur->value.dur.mon = (long)num * 12;
1145                         break;
1146                     case 1:
1147                         dur->value.dur.mon += (long)num;
1148                         break;
1149                     default:
1150                         /* convert to seconds using multiplier */
1151                         dur->value.dur.sec += num * multi[seq];
1152                         seq++;
1153                         break;
1154                 }
1155
1156                 break;          /* exit loop */
1157             }
1158             /* no date designators found? */
1159             if (++seq == 3)
1160                 goto error;
1161         }
1162         cur++;
1163     }
1164
1165     if (isneg) {
1166         dur->value.dur.mon = -dur->value.dur.mon;
1167         dur->value.dur.day = -dur->value.dur.day;
1168         dur->value.dur.sec = -dur->value.dur.sec;
1169     }
1170
1171     if (val != NULL)
1172         *val = dur;
1173     else
1174         xmlSchemaFreeValue(dur);
1175
1176     return 0;
1177
1178 error:
1179     if (dur != NULL)
1180         xmlSchemaFreeValue(dur);
1181     return 1;
1182 }
1183
1184 /**
1185  * xmlSchemaStrip:
1186  * @value: a value
1187  *
1188  * Removes the leading and ending spaces of a string
1189  *
1190  * Returns the new string or NULL if no change was required.
1191  */
1192 static xmlChar *
1193 xmlSchemaStrip(const xmlChar *value) {
1194     const xmlChar *start = value, *end, *f;
1195
1196     if (value == NULL) return(NULL);
1197     while ((*start != 0) && (IS_BLANK(*start))) start++;
1198     end = start;
1199     while (*end != 0) end++;
1200     f = end;
1201     end--;
1202     while ((end > start) && (IS_BLANK(*end))) end--;
1203     end++;
1204     if ((start == value) && (f == end)) return(NULL);
1205     return(xmlStrndup(start, end - start));
1206 }
1207
1208 /**
1209  * xmlSchemaCollapseString:
1210  * @value: a value
1211  *
1212  * Removes and normalize white spaces in the string
1213  *
1214  * Returns the new string or NULL if no change was required.
1215  */
1216 static xmlChar *
1217 xmlSchemaCollapseString(const xmlChar *value) {
1218     const xmlChar *start = value, *end, *f;
1219     xmlChar *g;
1220     int col = 0;
1221
1222     if (value == NULL) return(NULL);
1223     while ((*start != 0) && (IS_BLANK(*start))) start++;
1224     end = start;
1225     while (*end != 0) {
1226         if ((*end == ' ') && (IS_BLANK(end[1]))) {
1227             col = end - start;
1228             break;
1229         } else if ((*end == 0xa) || (*end == 0x9) || (*end == 0xd)) {
1230             col = end - start;
1231             break;
1232         }
1233         end++;
1234     }
1235     if (col == 0) {
1236         f = end;
1237         end--;
1238         while ((end > start) && (IS_BLANK(*end))) end--;
1239         end++;
1240         if ((start == value) && (f == end)) return(NULL);
1241         return(xmlStrndup(start, end - start));
1242     }
1243     start = xmlStrdup(start);
1244     if (start == NULL) return(NULL);
1245     g = (xmlChar *) (start + col);
1246     end = g;
1247     while (*end != 0) {
1248         if (IS_BLANK(*end)) {
1249             end++;
1250             while (IS_BLANK(*end)) end++;
1251             if (*end != 0)
1252                 *g++ = ' ';
1253         } else
1254             *g++ = *end++;
1255     }
1256     *g = 0;
1257     return((xmlChar *) start);
1258 }
1259
1260 /**
1261  * xmlSchemaValAtomicListNode:
1262  * @type: the predefined atomic type for a token in the list
1263  * @value: the list value to check
1264  * @ret:  the return computed value
1265  * @node:  the node containing the value
1266  *
1267  * Check that a value conforms to the lexical space of the predefined
1268  * list type. if true a value is computed and returned in @ret.
1269  *
1270  * Returns the number of items if this validates, a negative error code
1271  *         number otherwise
1272  */
1273 static int
1274 xmlSchemaValAtomicListNode(xmlSchemaTypePtr type, const xmlChar *value,
1275                            xmlSchemaValPtr *ret, xmlNodePtr node) {
1276     xmlChar *val, *cur, *endval;
1277     int nb_values = 0;
1278     int tmp = 0;
1279
1280     if (value == NULL) {
1281         return(-1);
1282     }
1283     val = xmlStrdup(value);
1284     if (val == NULL) {
1285         return(-1);
1286     }
1287     cur = val;
1288     /*
1289      * Split the list
1290      */
1291     while (IS_BLANK(*cur)) *cur++ = 0;
1292     while (*cur != 0) {
1293         if (IS_BLANK(*cur)) {
1294             *cur = 0;
1295             cur++;
1296             while (IS_BLANK(*cur)) *cur++ = 0;
1297         } else {
1298             nb_values++;
1299             cur++;
1300             while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
1301         }
1302     }
1303     if (nb_values == 0) {
1304         if (ret != NULL) {
1305             TODO
1306         }
1307         xmlFree(val);
1308         return(nb_values);
1309     }
1310     endval = cur;
1311     cur = val;
1312     while ((*cur == 0) && (cur != endval)) cur++;
1313     while (cur != endval) {
1314         tmp = xmlSchemaValPredefTypeNode(type, cur, NULL, node);
1315         if (tmp != 0)
1316             break;
1317         while (*cur != 0) cur++;
1318         while ((*cur == 0) && (cur != endval)) cur++;
1319     }
1320     xmlFree(val);
1321     if (ret != NULL) {
1322         TODO
1323     }
1324     if (tmp == 0)
1325         return(nb_values);
1326     return(-1);
1327 }
1328
1329 /**
1330  * xmlSchemaParseUInt:
1331  * @str: pointer to the string R/W
1332  * @llo: pointer to the low result
1333  * @lmi: pointer to the mid result
1334  * @lhi: pointer to the high result
1335  *
1336  * Parse an unsigned long into 3 fields.
1337  *
1338  * Returns the number of chars parsed or -1 if overflow of the capacity
1339  */
1340 static int
1341 xmlSchemaParseUInt(const xmlChar **str, unsigned long *llo,
1342                    unsigned long *lmi, unsigned long *lhi) {
1343     unsigned long lo = 0, mi = 0, hi = 0;
1344     const xmlChar *tmp, *cur = *str;
1345     int ret = 0, i = 0;
1346
1347     while (*cur == '0') {
1348         ret++;
1349         cur++;
1350     }
1351     tmp = cur;
1352     while ((*tmp != 0) && (*tmp >= '0') && (*tmp <= '9')) {
1353         i++;tmp++;ret++;
1354     }
1355     if (i > 24) {
1356         *str = tmp;
1357         return(-1);
1358     }
1359     while (i > 16) {
1360         hi = hi * 10 + (*cur++ - '0');
1361         i--;
1362     }
1363     while (i > 8) {
1364         mi = mi * 10 + (*cur++ - '0');
1365         i--;
1366     }
1367     while (i > 0) {
1368         lo = lo * 10 + (*cur++ - '0');
1369         i--;
1370     }
1371
1372     *str = cur;
1373     *llo = lo;
1374     *lmi = mi;
1375     *lhi = hi;
1376     return(ret);
1377 }
1378
1379 /**
1380  * xmlSchemaValAtomicType:
1381  * @type: the predefined type
1382  * @value: the value to check
1383  * @val:  the return computed value
1384  * @node:  the node containing the value
1385  * flags:  flags to control the vlidation
1386  *
1387  * Check that a value conforms to the lexical space of the atomic type.
1388  * if true a value is computed and returned in @val.
1389  *
1390  * Returns 0 if this validates, a positive error code number otherwise
1391  *         and -1 in case of internal or API error.
1392  */
1393 static int
1394 xmlSchemaValAtomicType(xmlSchemaTypePtr type, const xmlChar *value,
1395                        xmlSchemaValPtr *val, xmlNodePtr node, int flags) {
1396     xmlSchemaValPtr v;
1397     xmlChar *norm = NULL;
1398     int ret = 0;
1399
1400     if (xmlSchemaTypesInitialized == 0)
1401         return(-1);
1402     if (type == NULL)
1403         return(-1);
1404
1405     if (val != NULL)
1406         *val = NULL;
1407     if ((flags == 0) && (value != NULL)) {
1408         if ((type->flags != XML_SCHEMAS_STRING) &&
1409             (type->flags != XML_SCHEMAS_NORMSTRING)) {
1410             norm = xmlSchemaCollapseString(value);
1411             if (norm != NULL)
1412                 value = norm;
1413         }
1414     }
1415
1416     switch (type->flags) {
1417         case XML_SCHEMAS_UNKNOWN:
1418             if (type == xmlSchemaTypeAnyTypeDef)
1419                 goto return0;
1420             goto error;
1421         case XML_SCHEMAS_STRING:
1422             goto return0;
1423         case XML_SCHEMAS_NORMSTRING:
1424             TODO
1425             goto return0;
1426         case XML_SCHEMAS_DECIMAL: {
1427             const xmlChar *cur = value, *tmp;
1428             unsigned int frac = 0, len, neg = 0;
1429             unsigned long base = 0;
1430             if (cur == NULL)
1431                 goto return1;
1432             if (*cur == '+')
1433                 cur++;
1434             else if (*cur == '-') {
1435                 neg = 1;
1436                 cur++;
1437             }
1438             tmp = cur;
1439             while ((*cur >= '0') && (*cur <= '9')) {
1440                 base = base * 10 + (*cur - '0');
1441                 cur++;
1442             }
1443             len = cur - tmp;
1444             if (*cur == '.') {
1445                 cur++;
1446                 tmp = cur;
1447                 while ((*cur >= '0') && (*cur <= '9')) {
1448                     base = base * 10 + (*cur - '0');
1449                     cur++;
1450                 }
1451                 frac = cur - tmp;
1452             }
1453             if (*cur != 0)
1454                 goto return1;
1455             if (val != NULL) {
1456                 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
1457                 if (v != NULL) {
1458                     v->value.decimal.lo = base;
1459                     v->value.decimal.sign = neg;
1460                     v->value.decimal.frac = frac;
1461                     v->value.decimal.total = frac + len;
1462                     *val = v;
1463                 }
1464             }
1465             goto return0;
1466         }
1467         case XML_SCHEMAS_TIME:
1468         case XML_SCHEMAS_GDAY:
1469         case XML_SCHEMAS_GMONTH:
1470         case XML_SCHEMAS_GMONTHDAY:
1471         case XML_SCHEMAS_GYEAR:
1472         case XML_SCHEMAS_GYEARMONTH:
1473         case XML_SCHEMAS_DATE:
1474         case XML_SCHEMAS_DATETIME:
1475             ret = xmlSchemaValidateDates(type->flags, value, val);
1476             break;
1477         case XML_SCHEMAS_DURATION:
1478             ret = xmlSchemaValidateDuration(type, value, val);
1479             break;
1480         case XML_SCHEMAS_FLOAT:
1481         case XML_SCHEMAS_DOUBLE: {
1482             const xmlChar *cur = value;
1483             int neg = 0;
1484             if (cur == NULL)
1485                 goto return1;
1486             if ((cur[0] == 'N') && (cur[1] == 'a') && (cur[2] == 'N')) {
1487                 cur += 3;
1488                 if (*cur != 0)
1489                     goto return1;
1490                 if (val != NULL) {
1491                     if (type == xmlSchemaTypeFloatDef) {
1492                         v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1493                         if (v != NULL) {
1494                             v->value.f = (float) xmlXPathNAN;
1495                         } else {
1496                             xmlSchemaFreeValue(v);
1497                             goto error;
1498                         }
1499                     } else {
1500                         v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1501                         if (v != NULL) {
1502                             v->value.d = xmlXPathNAN;
1503                         } else {
1504                             xmlSchemaFreeValue(v);
1505                             goto error;
1506                         }
1507                     }
1508                     *val = v;
1509                 }
1510                 goto return0;
1511             }
1512             if (*cur == '-') {
1513                 neg = 1;
1514                 cur++;
1515             }
1516             if ((cur[0] == 'I') && (cur[1] == 'N') && (cur[2] == 'F')) {
1517                 cur += 3;
1518                 if (*cur != 0)
1519                     goto return1;
1520                 if (val != NULL) {
1521                     if (type == xmlSchemaTypeFloatDef) {
1522                         v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1523                         if (v != NULL) {
1524                             if (neg)
1525                                 v->value.f = (float) xmlXPathNINF;
1526                             else
1527                                 v->value.f = (float) xmlXPathPINF;
1528                         } else {
1529                             xmlSchemaFreeValue(v);
1530                             goto error;
1531                         }
1532                     } else {
1533                         v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1534                         if (v != NULL) {
1535                             if (neg)
1536                                 v->value.d = xmlXPathNINF;
1537                             else
1538                                 v->value.d = xmlXPathPINF;
1539                         } else {
1540                             xmlSchemaFreeValue(v);
1541                             goto error;
1542                         }
1543                     }
1544                     *val = v;
1545                 }
1546                 goto return0;
1547             }
1548             if ((neg == 0) && (*cur == '+'))
1549                 cur++;
1550             if ((cur[0] == 0) || (cur[0] == '+') || (cur[0] == '-'))
1551                 goto return1;
1552             while ((*cur >= '0') && (*cur <= '9')) {
1553                 cur++;
1554             }
1555             if (*cur == '.') {
1556                 cur++;
1557                 while ((*cur >= '0') && (*cur <= '9')) 
1558                     cur++;
1559             }
1560             if ((*cur == 'e') || (*cur == 'E')) {
1561                 cur++;
1562                 if ((*cur == '-') || (*cur == '+'))
1563                     cur++;
1564                 while ((*cur >= '0') && (*cur <= '9')) 
1565                     cur++;
1566             }
1567             if (*cur != 0)
1568                 goto return1;
1569             if (val != NULL) {
1570                 if (type == xmlSchemaTypeFloatDef) {
1571                     v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1572                     if (v != NULL) {
1573                         if (sscanf((const char *)value, "%f", &(v->value.f))==1) {
1574                             *val = v;
1575                         } else {
1576                             xmlGenericError(xmlGenericErrorContext,
1577                                     "failed to scanf float %s\n", value);
1578                             xmlSchemaFreeValue(v);
1579                             goto return1;
1580                         }
1581                     } else {
1582                         goto error;
1583                     }
1584                 } else {
1585                     v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1586                     if (v != NULL) {
1587                         if (sscanf((const char *)value, "%lf", &(v->value.d))==1) {
1588                             *val = v;
1589                         } else {
1590                             xmlGenericError(xmlGenericErrorContext,
1591                                     "failed to scanf double %s\n", value);
1592                             xmlSchemaFreeValue(v);
1593                             goto return1;
1594                         }
1595                     } else {
1596                         goto error;
1597                     }
1598                 }
1599             }
1600             goto return0;
1601         }
1602         case XML_SCHEMAS_BOOLEAN: {
1603             const xmlChar *cur = value;
1604
1605             if ((cur[0] == '0') && (cur[1] == 0))
1606                 ret = 0;
1607             else if ((cur[0] == '1') && (cur[1] == 0))
1608                 ret = 1;
1609             else if ((cur[0] == 't') && (cur[1] == 'r') && (cur[2] == 'u') &&
1610                      (cur[3] == 'e') && (cur[4] == 0))
1611                 ret = 1;
1612             else if ((cur[0] == 'f') && (cur[1] == 'a') && (cur[2] == 'l') &&
1613                      (cur[3] == 's') && (cur[4] == 'e') && (cur[5] == 0))
1614                 ret = 0;
1615             else 
1616                 goto return1;
1617             if (val != NULL) {
1618                 v = xmlSchemaNewValue(XML_SCHEMAS_BOOLEAN);
1619                 if (v != NULL) {
1620                     v->value.b = ret;
1621                     *val = v;
1622                 } else {
1623                     goto error;
1624                 }
1625             }
1626             goto return0;
1627         }
1628         case XML_SCHEMAS_TOKEN: {
1629             const xmlChar *cur = value;
1630
1631             if (IS_BLANK(*cur))
1632                 goto return1;
1633
1634             while (*cur != 0) {
1635                 if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) {
1636                     goto return1;
1637                 } else if (*cur == ' ') {
1638                     cur++;
1639                     if (*cur == 0)
1640                         goto return1;
1641                     if (*cur == ' ')
1642                         goto return1;
1643                 } else {
1644                     cur++;
1645                 }
1646             }
1647             if (val != NULL) {
1648                 v = xmlSchemaNewValue(XML_SCHEMAS_TOKEN);
1649                 if (v != NULL) {
1650                     v->value.str = xmlStrdup(value);
1651                     *val = v;
1652                 } else {
1653                     goto error;
1654                 }
1655             }
1656             goto return0;
1657         }
1658         case XML_SCHEMAS_LANGUAGE:
1659             if (xmlCheckLanguageID(value) == 1) {
1660                 if (val != NULL) {
1661                     v = xmlSchemaNewValue(XML_SCHEMAS_LANGUAGE);
1662                     if (v != NULL) {
1663                         v->value.str = xmlStrdup(value);
1664                         *val = v;
1665                     } else {
1666                         goto error;
1667                     }
1668                 }
1669                 goto return0;
1670             }
1671             goto return1;
1672         case XML_SCHEMAS_NMTOKEN:
1673             if (xmlValidateNMToken(value, 1) == 0) {
1674                 if (val != NULL) {
1675                     v = xmlSchemaNewValue(XML_SCHEMAS_NMTOKEN);
1676                     if (v != NULL) {
1677                         v->value.str = xmlStrdup(value);
1678                         *val = v;
1679                     } else {
1680                         goto error;
1681                     }
1682                 }
1683                 goto return0;
1684             }
1685             goto return1;
1686         case XML_SCHEMAS_NMTOKENS:
1687             ret = xmlSchemaValAtomicListNode(xmlSchemaTypeNmtokenDef,
1688                                              value, val, node);
1689             if (ret > 0)
1690                 ret = 0;
1691             else
1692                 ret = 1;
1693             goto done;
1694         case XML_SCHEMAS_NAME:
1695             ret = xmlValidateName(value, 1);
1696             if ((ret == 0) && (val != NULL)) {
1697                 TODO;
1698             }
1699             goto done;
1700         case XML_SCHEMAS_QNAME: {
1701             xmlChar *uri = NULL;
1702             xmlChar *local = NULL;
1703
1704             ret = xmlValidateQName(value, 1);
1705             if ((ret == 0) && (node != NULL)) {
1706                 xmlChar *prefix;
1707                 local = xmlSplitQName2(value, &prefix);
1708                 if (prefix != NULL) {
1709                     xmlNsPtr ns;
1710
1711                     ns = xmlSearchNs(node->doc, node, prefix);
1712                     if (ns == NULL)
1713                         ret = 1;
1714                     else if (val != NULL)
1715                         uri = xmlStrdup(ns->href);
1716                 }
1717                 if ((local != NULL) && ((val == NULL) || (ret != 0)))
1718                     xmlFree(local);
1719                 if (prefix != NULL)
1720                     xmlFree(prefix);
1721             }
1722             if ((ret == 0) && (val != NULL)) {
1723                 v = xmlSchemaNewValue(XML_SCHEMAS_QNAME);
1724                 if (v != NULL) {
1725                     if (local != NULL)
1726                         v->value.qname.name = local;
1727                     else
1728                         v->value.qname.name = xmlStrdup(value);
1729                     if (uri != NULL)
1730                         v->value.qname.uri = uri;
1731                     
1732                     *val = v;
1733                 } else {
1734                     if (local != NULL)
1735                         xmlFree(local);
1736                     if (uri != NULL)
1737                         xmlFree(uri);
1738                     goto error;
1739                 }
1740             }
1741             goto done;
1742         }
1743         case XML_SCHEMAS_NCNAME:
1744             ret = xmlValidateNCName(value, 1);
1745             if ((ret == 0) && (val != NULL)) {
1746                 v = xmlSchemaNewValue(XML_SCHEMAS_NCNAME);
1747                 if (v != NULL) {
1748                     v->value.str = xmlStrdup(value);
1749                     *val = v;
1750                 } else {
1751                     goto error;
1752                 }
1753             }
1754             goto done;
1755         case XML_SCHEMAS_ID:
1756             ret = xmlValidateNCName(value, 1);
1757             if ((ret == 0) && (val != NULL)) {
1758                 v = xmlSchemaNewValue(XML_SCHEMAS_ID);
1759                 if (v != NULL) {
1760                     v->value.str = xmlStrdup(value);
1761                     *val = v;
1762                 } else {
1763                     goto error;
1764                 }
1765             }
1766             if ((ret == 0) && (node != NULL) &&
1767                 (node->type == XML_ATTRIBUTE_NODE)) {
1768                 xmlAttrPtr attr = (xmlAttrPtr) node;
1769                 /*
1770                  * NOTE: the IDness might have already be declared in the DTD
1771                  */
1772                 if (attr->atype != XML_ATTRIBUTE_ID) {
1773                     xmlIDPtr res;
1774                     xmlChar *strip;
1775
1776                     strip = xmlSchemaStrip(value);
1777                     if (strip != NULL) {
1778                         res = xmlAddID(NULL, node->doc, strip, attr);
1779                         xmlFree(strip);
1780                     } else
1781                         res = xmlAddID(NULL, node->doc, value, attr);
1782                     if (res == NULL) {
1783                         ret = 2;
1784                     } else {
1785                         attr->atype = XML_ATTRIBUTE_ID;
1786                     }
1787                 }
1788             }
1789             goto done;
1790         case XML_SCHEMAS_IDREF:
1791             ret = xmlValidateNCName(value, 1);
1792             if ((ret == 0) && (val != NULL)) {
1793                 TODO;
1794             }
1795             if ((ret == 0) && (node != NULL) &&
1796                 (node->type == XML_ATTRIBUTE_NODE)) {
1797                 xmlAttrPtr attr = (xmlAttrPtr) node;
1798                 xmlChar *strip;
1799
1800                 strip = xmlSchemaStrip(value);
1801                 if (strip != NULL) {
1802                     xmlAddRef(NULL, node->doc, strip, attr);
1803                     xmlFree(strip);
1804                 } else
1805                     xmlAddRef(NULL, node->doc, value, attr);
1806                 attr->atype = XML_ATTRIBUTE_IDREF;
1807             }
1808             goto done;
1809         case XML_SCHEMAS_IDREFS:
1810             ret = xmlSchemaValAtomicListNode(xmlSchemaTypeIdrefDef,
1811                                              value, val, node);
1812             if (ret < 0)
1813                 ret = 2;
1814             else
1815                 ret = 0;
1816             if ((ret == 0) && (node != NULL) &&
1817                 (node->type == XML_ATTRIBUTE_NODE)) {
1818                 xmlAttrPtr attr = (xmlAttrPtr) node;
1819
1820                 attr->atype = XML_ATTRIBUTE_IDREFS;
1821             }
1822             goto done;
1823         case XML_SCHEMAS_ENTITY: {
1824             xmlChar *strip;
1825             ret = xmlValidateNCName(value, 1);
1826             if ((node == NULL) || (node->doc == NULL))
1827                 ret = 3;
1828             if (ret == 0) {
1829                 xmlEntityPtr ent;
1830
1831                 strip = xmlSchemaStrip(value);
1832                 if (strip != NULL) {
1833                     ent = xmlGetDocEntity(node->doc, strip);
1834                     xmlFree(strip);
1835                 } else {
1836                     ent = xmlGetDocEntity(node->doc, value);
1837                 }
1838                 if ((ent == NULL) ||
1839                     (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY))
1840                     ret = 4;
1841             }
1842             if ((ret == 0) && (val != NULL)) {
1843                 TODO;
1844             }
1845             if ((ret == 0) && (node != NULL) &&
1846                 (node->type == XML_ATTRIBUTE_NODE)) {
1847                 xmlAttrPtr attr = (xmlAttrPtr) node;
1848
1849                 attr->atype = XML_ATTRIBUTE_ENTITY;
1850             }
1851             goto done;
1852         }
1853         case XML_SCHEMAS_ENTITIES:
1854             if ((node == NULL) || (node->doc == NULL))
1855                 goto return3;
1856             ret = xmlSchemaValAtomicListNode(xmlSchemaTypeEntityDef,
1857                                              value, val, node);
1858             if (ret <= 0)
1859                 ret = 1;
1860             else
1861                 ret = 0;
1862             if ((ret == 0) && (node != NULL) &&
1863                 (node->type == XML_ATTRIBUTE_NODE)) {
1864                 xmlAttrPtr attr = (xmlAttrPtr) node;
1865
1866                 attr->atype = XML_ATTRIBUTE_ENTITIES;
1867             }
1868             goto done;
1869         case XML_SCHEMAS_NOTATION: {
1870             xmlChar *uri = NULL;
1871             xmlChar *local = NULL;
1872
1873             ret = xmlValidateQName(value, 1);
1874             if ((ret == 0) && (node != NULL)) {
1875                 xmlChar *prefix;
1876                 local = xmlSplitQName2(value, &prefix);
1877                 if (prefix != NULL) {
1878                     xmlNsPtr ns;
1879
1880                     ns = xmlSearchNs(node->doc, node, prefix);
1881                     if (ns == NULL)
1882                         ret = 1;
1883                     else if (val != NULL)
1884                         uri = xmlStrdup(ns->href);
1885                 }
1886                 if ((local != NULL) && ((val == NULL) || (ret != 0)))
1887                     xmlFree(local);
1888                 if (prefix != NULL)
1889                     xmlFree(prefix);
1890             }
1891             if ((node == NULL) || (node->doc == NULL))
1892                 ret = 3;
1893             if (ret == 0) {
1894                 ret = xmlValidateNotationUse(NULL, node->doc, value);
1895                 if (ret == 1)
1896                     ret = 0;
1897                 else
1898                     ret = 1;
1899             }
1900             if ((ret == 0) && (val != NULL)) {
1901                 v = xmlSchemaNewValue(XML_SCHEMAS_NOTATION);
1902                 if (v != NULL) {
1903                     if (local != NULL)
1904                         v->value.qname.name = local;
1905                     else
1906                         v->value.qname.name = xmlStrdup(value);
1907                     if (uri != NULL)
1908                         v->value.qname.uri = uri;
1909                     
1910                     *val = v;
1911                 } else {
1912                     if (local != NULL)
1913                         xmlFree(local);
1914                     if (uri != NULL)
1915                         xmlFree(uri);
1916                     goto error;
1917                 }
1918             }
1919             goto done;
1920         }
1921         case XML_SCHEMAS_ANYURI: {
1922             xmlURIPtr uri;
1923
1924             uri = xmlParseURI((const char *) value);
1925             if (uri == NULL)
1926                 goto return1;
1927             if (val != NULL) {
1928                 TODO;
1929             }
1930             xmlFreeURI(uri);
1931             goto return0;
1932         }
1933         case XML_SCHEMAS_HEXBINARY: {
1934             const xmlChar *cur = value;
1935             xmlChar *base;
1936             int total, i = 0;
1937
1938             if (cur == NULL)
1939                 goto return1;
1940
1941             while (((*cur >= '0') && (*cur <= '9')) ||
1942                    ((*cur >= 'A') && (*cur <= 'F')) ||
1943                    ((*cur >= 'a') && (*cur <= 'f'))) {
1944                 i++;cur++;
1945             }
1946
1947             if (*cur != 0)
1948                 goto return1;
1949             if ((i % 2) != 0)
1950                 goto return1;
1951
1952             if (val != NULL) {
1953
1954                 v = xmlSchemaNewValue(XML_SCHEMAS_HEXBINARY);
1955                 if (v == NULL)
1956                     goto error;
1957
1958                 cur = xmlStrdup(value);
1959                     if (cur == NULL) {
1960                     xmlFree(v);
1961                     goto return1;
1962                 }
1963
1964                 total = i / 2;          /* number of octets */
1965
1966                 base = (xmlChar *)cur;
1967                 while (i-- > 0) {
1968                     if (*base >= 'a')
1969                         *base = *base - ('a' - 'A');
1970                     base++;
1971                 }
1972
1973                 v->value.hex.str   = (xmlChar *)cur;
1974                 v->value.hex.total = total;
1975                 *val = v;
1976             }
1977             goto return0;
1978         }
1979         case XML_SCHEMAS_INTEGER:
1980         case XML_SCHEMAS_PINTEGER:
1981         case XML_SCHEMAS_NPINTEGER:
1982         case XML_SCHEMAS_NINTEGER:
1983         case XML_SCHEMAS_NNINTEGER: {
1984             const xmlChar *cur = value;
1985             unsigned long lo, mi, hi;
1986             int sign = 0;
1987             if (cur == NULL)
1988                 goto return1;
1989             if (*cur == '-') {
1990                 sign = 1;
1991                 cur++;
1992             } else if (*cur == '+')
1993                 cur++;
1994             ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
1995             if (ret == 0)
1996                 goto return1;
1997             if (*cur != 0)
1998                 goto return1;
1999             if (type->flags == XML_SCHEMAS_NPINTEGER) {
2000                 if ((sign == 0) &&
2001                     ((hi != 0) || (mi != 0) || (lo != 0)))
2002                     goto return1;
2003             } else if (type->flags == XML_SCHEMAS_PINTEGER) {
2004                 if (sign == 1)
2005                     goto return1;
2006                 if ((hi == 0) && (mi == 0) && (lo == 0))
2007                     goto return1;
2008             } else if (type->flags == XML_SCHEMAS_NINTEGER) {
2009                 if (sign == 0)
2010                     goto return1;
2011                 if ((hi == 0) && (mi == 0) && (lo == 0))
2012                     goto return1;
2013             } else if (type->flags == XML_SCHEMAS_NNINTEGER) {
2014                 if ((sign == 1) &&
2015                     ((hi != 0) || (mi != 0) || (lo != 0)))
2016                     goto return1;
2017             }
2018             /*
2019              * We can store a value only if no overflow occured
2020              */
2021             if ((ret > 0) && (val != NULL)) {
2022                 v = xmlSchemaNewValue(type->flags);
2023                 if (v != NULL) {
2024                     v->value.decimal.lo = lo;
2025                     v->value.decimal.mi = lo;
2026                     v->value.decimal.hi = lo;
2027                     v->value.decimal.sign = sign;
2028                     v->value.decimal.frac = 0;
2029                     v->value.decimal.total = cur - value;
2030                     *val = v;
2031                 }
2032             }
2033             goto return0;
2034         }
2035         case XML_SCHEMAS_LONG:
2036         case XML_SCHEMAS_BYTE:
2037         case XML_SCHEMAS_SHORT:
2038         case XML_SCHEMAS_INT: {
2039             const xmlChar *cur = value;
2040             unsigned long lo, mi, hi;
2041             int total = 0;
2042             int sign = 0;
2043             if (cur == NULL)
2044                 goto return1;
2045             if (*cur == '-') {
2046                 sign = 1;
2047                 cur++;
2048             } else if (*cur == '+')
2049                 cur++;
2050             ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2051             if (ret <= 0)
2052                 goto return1;
2053             if (*cur != 0)
2054                 goto return1;
2055             if (type->flags == XML_SCHEMAS_LONG) {
2056                 if (hi >= 922) {
2057                     if (hi > 922)
2058                         goto return1;
2059                     if (mi >= 33720368) {
2060                         if (mi > 33720368)
2061                             goto return1;
2062                         if ((sign == 0) && (lo > 54775807))
2063                             goto return1;
2064                         if ((sign == 1) && (lo > 54775808))
2065                             goto return1;
2066                     }
2067                 }
2068             } else if (type->flags == XML_SCHEMAS_INT) {
2069                 if (hi != 0)
2070                     goto return1;
2071                 if (mi >= 21) {
2072                     if (mi > 21)
2073                         goto return1;
2074                     if ((sign == 0) && (lo > 47483647))
2075                         goto return1;
2076                     if ((sign == 1) && (lo > 47483648))
2077                         goto return1;
2078                 }
2079             } else if (type->flags == XML_SCHEMAS_SHORT) {
2080                 if ((mi != 0) || (hi != 0))
2081                     goto return1;
2082                 if ((sign == 1) && (lo > 32768))
2083                     goto return1;
2084                 if ((sign == 0) && (lo > 32767))
2085                     goto return1;
2086             } else if (type->flags == XML_SCHEMAS_BYTE) {
2087                 if ((mi != 0) || (hi != 0))
2088                     goto return1;
2089                 if ((sign == 1) && (lo > 128))
2090                     goto return1;
2091                 if ((sign == 0) && (lo > 127))
2092                     goto return1;
2093             }
2094             if (val != NULL) {
2095                 v = xmlSchemaNewValue(type->flags);
2096                 if (v != NULL) {
2097                     v->value.decimal.lo = lo;
2098                     v->value.decimal.mi = lo;
2099                     v->value.decimal.hi = lo;
2100                     v->value.decimal.sign = sign;
2101                     v->value.decimal.frac = 0;
2102                     v->value.decimal.total = total;
2103                     *val = v;
2104                 }
2105             }
2106             goto return0;
2107         }
2108         case XML_SCHEMAS_UINT:
2109         case XML_SCHEMAS_ULONG:
2110         case XML_SCHEMAS_USHORT:
2111         case XML_SCHEMAS_UBYTE: {
2112             const xmlChar *cur = value;
2113             unsigned long lo, mi, hi;
2114             int total = 0;
2115             if (cur == NULL)
2116                 goto return1;
2117             ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
2118             if (ret <= 0)
2119                 goto return1;
2120             if (*cur != 0)
2121                 goto return1;
2122             if (type->flags == XML_SCHEMAS_ULONG) {
2123                 if (hi >= 1844) {
2124                     if (hi > 1844)
2125                         goto return1;
2126                     if (mi >= 67440737) {
2127                         if (mi > 67440737)
2128                             goto return1;
2129                         if (lo > 9551615)
2130                             goto return1;
2131                     }
2132                 }
2133             } else if (type->flags == XML_SCHEMAS_UINT) {
2134                 if (hi != 0)
2135                     goto return1;
2136                 if (mi >= 42) {
2137                     if (mi > 42)
2138                         goto return1;
2139                     if (lo > 94967295)
2140                         goto return1;
2141                 }
2142             } else if (type->flags == XML_SCHEMAS_USHORT) {
2143                 if ((mi != 0) || (hi != 0))
2144                     goto return1;
2145                 if (lo > 65535)
2146                     goto return1;
2147             } else if (type->flags == XML_SCHEMAS_UBYTE) {
2148                 if ((mi != 0) || (hi != 0))
2149                     goto return1;
2150                 if (lo > 255)
2151                     goto return1;
2152             }
2153             if (val != NULL) {
2154                 v = xmlSchemaNewValue(type->flags);
2155                 if (v != NULL) {
2156                     v->value.decimal.lo = lo;
2157                     v->value.decimal.mi = mi;
2158                     v->value.decimal.hi = hi;
2159                     v->value.decimal.sign = 0;
2160                     v->value.decimal.frac = 0;
2161                     v->value.decimal.total = total;
2162                     *val = v;
2163                 }
2164             }
2165             goto return0;
2166         }
2167     }
2168
2169 done:
2170     if (norm != NULL) xmlFree(norm);
2171     return(ret);
2172 return3:
2173     if (norm != NULL) xmlFree(norm);
2174     return(3);
2175 return1:
2176     if (norm != NULL) xmlFree(norm);
2177     return(1);
2178 return0:
2179     if (norm != NULL) xmlFree(norm);
2180     return(0);
2181 error:
2182     if (norm != NULL) xmlFree(norm);
2183     return(-1);
2184 }
2185
2186 /**
2187  * xmlSchemaValPredefTypeNode:
2188  * @type: the predefined type
2189  * @value: the value to check
2190  * @val:  the return computed value
2191  * @node:  the node containing the value
2192  *
2193  * Check that a value conforms to the lexical space of the predefined type.
2194  * if true a value is computed and returned in @val.
2195  *
2196  * Returns 0 if this validates, a positive error code number otherwise
2197  *         and -1 in case of internal or API error.
2198  */
2199 int
2200 xmlSchemaValPredefTypeNode(xmlSchemaTypePtr type, const xmlChar *value,
2201                            xmlSchemaValPtr *val, xmlNodePtr node) {
2202     return(xmlSchemaValAtomicType(type, value, val, node, 0));
2203 }
2204
2205 /**
2206  * xmlSchemaValidatePredefinedType:
2207  * @type: the predefined type
2208  * @value: the value to check
2209  * @val:  the return computed value
2210  *
2211  * Check that a value conforms to the lexical space of the predefined type.
2212  * if true a value is computed and returned in @val.
2213  *
2214  * Returns 0 if this validates, a positive error code number otherwise
2215  *         and -1 in case of internal or API error.
2216  */
2217 int
2218 xmlSchemaValidatePredefinedType(xmlSchemaTypePtr type, const xmlChar *value,
2219                                 xmlSchemaValPtr *val) {
2220     return(xmlSchemaValPredefTypeNode(type, value, val, NULL));
2221 }
2222
2223 /**
2224  * xmlSchemaCompareDecimals:
2225  * @x:  a first decimal value
2226  * @y:  a second decimal value
2227  *
2228  * Compare 2 decimals
2229  *
2230  * Returns -1 if x < y, 0 if x == y, 1 if x > y and -2 in case of error
2231  */
2232 static int
2233 xmlSchemaCompareDecimals(xmlSchemaValPtr x, xmlSchemaValPtr y)
2234 {
2235     xmlSchemaValPtr swp;
2236     int order = 1, p;
2237     unsigned long tmp;
2238
2239     if ((x->value.decimal.sign) && 
2240         ((x->value.decimal.lo != 0) ||
2241          (x->value.decimal.mi != 0) ||
2242          (x->value.decimal.hi != 0))) {
2243         if ((y->value.decimal.sign) &&
2244             ((y->value.decimal.lo != 0) ||
2245              (y->value.decimal.mi != 0) ||
2246              (y->value.decimal.hi != 0)))
2247             order = -1;
2248         else
2249             return (-1);
2250     } else if ((y->value.decimal.sign) &&
2251                ((y->value.decimal.lo != 0) ||
2252                 (y->value.decimal.mi != 0) ||
2253                 (y->value.decimal.hi != 0))) {
2254         return (1);
2255     }
2256     if (x->value.decimal.frac == y->value.decimal.frac) {
2257         if (x->value.decimal.hi < y->value.decimal.hi)
2258             return (-order);
2259         if (x->value.decimal.hi < y->value.decimal.hi)
2260             return (order);
2261         if (x->value.decimal.mi < y->value.decimal.mi)
2262             return (-order);
2263         if (x->value.decimal.mi < y->value.decimal.mi)
2264             return (order);
2265         if (x->value.decimal.lo < y->value.decimal.lo)
2266             return (-order);
2267         if (x->value.decimal.lo > y->value.decimal.lo)
2268             return(order);
2269         return(0);
2270     }
2271     if (y->value.decimal.frac > x->value.decimal.frac) {
2272         swp = y;
2273         y = x;
2274         x = swp;
2275         order = -order;
2276     }
2277     p = powten[x->value.decimal.frac - y->value.decimal.frac];
2278     tmp = x->value.decimal.lo / p;
2279     if (tmp > y->value.decimal.lo)
2280         return (order);
2281     if (tmp < y->value.decimal.lo)
2282         return (-order);
2283     tmp = y->value.decimal.lo * p;
2284     if (x->value.decimal.lo < tmp)
2285         return (-order);
2286     if (x->value.decimal.lo == tmp)
2287         return (0);
2288     return (order);
2289 }
2290
2291 /**
2292  * xmlSchemaCompareDurations:
2293  * @x:  a first duration value
2294  * @y:  a second duration value
2295  *
2296  * Compare 2 durations
2297  *
2298  * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
2299  * case of error
2300  */
2301 static int
2302 xmlSchemaCompareDurations(xmlSchemaValPtr x, xmlSchemaValPtr y)
2303 {
2304     long carry, mon, day;
2305     double sec;
2306     int invert = 1;
2307     long xmon, xday, myear, minday, maxday;
2308     static const long dayRange [2][12] = {
2309         { 0, 28, 59, 89, 120, 150, 181, 212, 242, 273, 303, 334, },
2310         { 0, 31, 62, 92, 123, 153, 184, 215, 245, 276, 306, 337} };
2311
2312     if ((x == NULL) || (y == NULL))
2313         return -2;
2314
2315     /* months */
2316     mon = x->value.dur.mon - y->value.dur.mon;
2317
2318     /* seconds */
2319     sec = x->value.dur.sec - y->value.dur.sec;
2320     carry = (long)sec / SECS_PER_DAY;
2321     sec -= (double)(carry * SECS_PER_DAY);
2322
2323     /* days */
2324     day = x->value.dur.day - y->value.dur.day + carry;
2325
2326     /* easy test */
2327     if (mon == 0) {
2328         if (day == 0)
2329             if (sec == 0.0)
2330                 return 0;
2331             else if (sec < 0.0)
2332                 return -1;
2333             else
2334                 return 1;
2335         else if (day < 0)
2336             return -1;
2337         else
2338             return 1;
2339     }
2340
2341     if (mon > 0) {
2342         if ((day >= 0) && (sec >= 0.0))
2343             return 1;
2344         else {
2345             xmon = mon;
2346             xday = -day;
2347         }
2348     } else if ((day <= 0) && (sec <= 0.0)) {
2349         return -1;
2350     } else {
2351         invert = -1;
2352         xmon = -mon;
2353         xday = day;
2354     }
2355
2356     myear = xmon / 12;
2357     if (myear == 0) {
2358         minday = 0;
2359         maxday = 0;
2360     } else {
2361         maxday = 366 * ((myear + 3) / 4) +
2362                  365 * ((myear - 1) % 4);
2363         minday = maxday - 1;
2364     }
2365
2366     xmon = xmon % 12;
2367     minday += dayRange[0][xmon];
2368     maxday += dayRange[1][xmon];
2369
2370     if ((maxday == minday) && (maxday == xday))
2371         return(0); /* can this really happen ? */
2372     if (maxday < xday)
2373         return(-invert);
2374     if (minday > xday)
2375         return(invert);
2376
2377     /* indeterminate */
2378     return 2;
2379 }
2380
2381 /*
2382  * macros for adding date/times and durations
2383  */
2384 #define FQUOTIENT(a,b)                  (floor(((double)a/(double)b)))
2385 #define MODULO(a,b)                     (a - FQUOTIENT(a,b) * b)
2386 #define FQUOTIENT_RANGE(a,low,high)     (FQUOTIENT((a-low),(high-low)))
2387 #define MODULO_RANGE(a,low,high)        ((MODULO((a-low),(high-low)))+low)
2388
2389 /**
2390  * _xmlSchemaDateAdd:
2391  * @dt: an #xmlSchemaValPtr
2392  * @dur: an #xmlSchemaValPtr of type #XS_DURATION
2393  *
2394  * Compute a new date/time from @dt and @dur. This function assumes @dt
2395  * is either #XML_SCHEMAS_DATETIME, #XML_SCHEMAS_DATE, #XML_SCHEMAS_GYEARMONTH,
2396  * or #XML_SCHEMAS_GYEAR.
2397  *
2398  * Returns date/time pointer or NULL.
2399  */
2400 static xmlSchemaValPtr
2401 _xmlSchemaDateAdd (xmlSchemaValPtr dt, xmlSchemaValPtr dur)
2402 {
2403     xmlSchemaValPtr ret;
2404     long carry, tempdays, temp;
2405     xmlSchemaValDatePtr r, d;
2406     xmlSchemaValDurationPtr u;
2407
2408     if ((dt == NULL) || (dur == NULL))
2409         return NULL;
2410
2411     ret = xmlSchemaNewValue(dt->type);
2412     if (ret == NULL)
2413         return NULL;
2414
2415     r = &(ret->value.date);
2416     d = &(dt->value.date);
2417     u = &(dur->value.dur);
2418
2419     /* normalization */
2420     if (d->mon == 0)
2421         d->mon = 1;
2422
2423     /* normalize for time zone offset */
2424     u->sec -= (d->tzo * 60);
2425     d->tzo = 0;
2426
2427     /* normalization */
2428     if (d->day == 0)
2429         d->day = 1;
2430
2431     /* month */
2432     carry  = d->mon + u->mon;
2433     r->mon = MODULO_RANGE(carry, 1, 13);
2434     carry  = FQUOTIENT_RANGE(carry, 1, 13);
2435
2436     /* year (may be modified later) */
2437     r->year = d->year + carry;
2438     if (r->year == 0) {
2439         if (d->year > 0)
2440             r->year--;
2441         else
2442             r->year++;
2443     }
2444
2445     /* time zone */
2446     r->tzo     = d->tzo;
2447     r->tz_flag = d->tz_flag;
2448
2449     /* seconds */
2450     r->sec = d->sec + u->sec;
2451     carry  = FQUOTIENT((long)r->sec, 60);
2452     if (r->sec != 0.0) {
2453         r->sec = MODULO(r->sec, 60.0);
2454     }
2455
2456     /* minute */
2457     carry += d->min;
2458     r->min = MODULO(carry, 60);
2459     carry  = FQUOTIENT(carry, 60);
2460
2461     /* hours */
2462     carry  += d->hour;
2463     r->hour = MODULO(carry, 24);
2464     carry   = FQUOTIENT(carry, 24);
2465
2466     /*
2467      * days
2468      * Note we use tempdays because the temporary values may need more
2469      * than 5 bits
2470      */
2471     if ((VALID_YEAR(r->year)) && (VALID_MONTH(r->mon)) &&
2472                   (d->day > MAX_DAYINMONTH(r->year, r->mon)))
2473         tempdays = MAX_DAYINMONTH(r->year, r->mon);
2474     else if (d->day < 1)
2475         tempdays = 1;
2476     else
2477         tempdays = d->day;
2478
2479     tempdays += u->day + carry;
2480
2481     while (1) {
2482         if (tempdays < 1) {
2483             long tmon = MODULO_RANGE(r->mon-1, 1, 13);
2484             long tyr  = r->year + FQUOTIENT_RANGE(r->mon-1, 1, 13);
2485             if (tyr == 0)
2486                 tyr--;
2487             tempdays += MAX_DAYINMONTH(tyr, tmon);
2488             carry = -1;
2489         } else if (tempdays > MAX_DAYINMONTH(r->year, r->mon)) {
2490             tempdays = tempdays - MAX_DAYINMONTH(r->year, r->mon);
2491             carry = 1;
2492         } else
2493             break;
2494
2495         temp = r->mon + carry;
2496         r->mon = MODULO_RANGE(temp, 1, 13);
2497         r->year = r->year + FQUOTIENT_RANGE(temp, 1, 13);
2498         if (r->year == 0) {
2499             if (temp < 1)
2500                 r->year--;
2501             else
2502                 r->year++;
2503         }
2504     }
2505     
2506     r->day = tempdays;
2507
2508     /*
2509      * adjust the date/time type to the date values
2510      */
2511     if (ret->type != XML_SCHEMAS_DATETIME) {
2512         if ((r->hour) || (r->min) || (r->sec))
2513             ret->type = XML_SCHEMAS_DATETIME;
2514         else if (ret->type != XML_SCHEMAS_DATE) {
2515             if ((r->mon != 1) && (r->day != 1))
2516                 ret->type = XML_SCHEMAS_DATE;
2517             else if ((ret->type != XML_SCHEMAS_GYEARMONTH) && (r->mon != 1))
2518                 ret->type = XML_SCHEMAS_GYEARMONTH;
2519         }
2520     }
2521
2522     return ret;
2523 }
2524
2525 /**
2526  * xmlSchemaDupVal:
2527  * @v: value to duplicate
2528  *
2529  * returns a duplicated value.
2530  */
2531 static xmlSchemaValPtr
2532 xmlSchemaDupVal (xmlSchemaValPtr v)
2533 {
2534     xmlSchemaValPtr ret = xmlSchemaNewValue(v->type);
2535     if (ret == NULL)
2536         return ret;
2537     
2538     memcpy(ret, v, sizeof(xmlSchemaVal));
2539     return ret;
2540 }
2541
2542 /**
2543  * xmlSchemaDateNormalize:
2544  * @dt: an #xmlSchemaValPtr
2545  *
2546  * Normalize @dt to GMT time.
2547  *
2548  */
2549 static xmlSchemaValPtr
2550 xmlSchemaDateNormalize (xmlSchemaValPtr dt, double offset)
2551 {
2552     xmlSchemaValPtr dur, ret;
2553
2554     if (dt == NULL)
2555         return NULL;
2556
2557     if (((dt->type != XML_SCHEMAS_TIME) &&
2558          (dt->type != XML_SCHEMAS_DATETIME)) || (dt->value.date.tzo == 0))
2559         return xmlSchemaDupVal(dt);
2560
2561     dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
2562     if (dur == NULL)
2563         return NULL;
2564
2565     dur->value.date.sec -= offset;
2566
2567     ret = _xmlSchemaDateAdd(dt, dur);
2568     if (ret == NULL)
2569         return NULL;
2570
2571     xmlSchemaFreeValue(dur);
2572
2573     /* ret->value.date.tzo = 0; */
2574     return ret;
2575 }
2576
2577 /**
2578  * _xmlSchemaDateCastYMToDays:
2579  * @dt: an #xmlSchemaValPtr
2580  *
2581  * Convert mon and year of @dt to total number of days. Take the 
2582  * number of years since (or before) 1 AD and add the number of leap
2583  * years. This is a function  because negative
2584  * years must be handled a little differently and there is no zero year.
2585  *
2586  * Returns number of days.
2587  */
2588 static long
2589 _xmlSchemaDateCastYMToDays (const xmlSchemaValPtr dt)
2590 {
2591     long ret;
2592
2593     if (dt->value.date.year < 0)
2594         ret = (dt->value.date.year * 365) +
2595               (((dt->value.date.year+1)/4)-((dt->value.date.year+1)/100)+
2596                ((dt->value.date.year+1)/400)) +
2597               DAY_IN_YEAR(0, dt->value.date.mon, dt->value.date.year);
2598     else
2599         ret = ((dt->value.date.year-1) * 365) +
2600               (((dt->value.date.year-1)/4)-((dt->value.date.year-1)/100)+
2601                ((dt->value.date.year-1)/400)) +
2602               DAY_IN_YEAR(0, dt->value.date.mon, dt->value.date.year);
2603
2604     return ret;
2605 }
2606
2607 /**
2608  * TIME_TO_NUMBER:
2609  * @dt:  an #xmlSchemaValPtr
2610  *
2611  * Calculates the number of seconds in the time portion of @dt.
2612  *
2613  * Returns seconds.
2614  */
2615 #define TIME_TO_NUMBER(dt)                              \
2616     ((double)((dt->value.date.hour * SECS_PER_HOUR) +   \
2617               (dt->value.date.min * SECS_PER_MIN) +     \
2618               (dt->value.date.tzo * SECS_PER_MIN)) +    \
2619                dt->value.date.sec)
2620
2621 /**
2622  * xmlSchemaCompareDates:
2623  * @x:  a first date/time value
2624  * @y:  a second date/time value
2625  *
2626  * Compare 2 date/times
2627  *
2628  * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
2629  * case of error
2630  */
2631 static int
2632 xmlSchemaCompareDates (xmlSchemaValPtr x, xmlSchemaValPtr y)
2633 {
2634     unsigned char xmask, ymask, xor_mask, and_mask;
2635     xmlSchemaValPtr p1, p2, q1, q2;
2636     long p1d, p2d, q1d, q2d;
2637
2638     if ((x == NULL) || (y == NULL))
2639         return -2;
2640
2641     if (x->value.date.tz_flag) {
2642
2643         if (!y->value.date.tz_flag) {
2644             p1 = xmlSchemaDateNormalize(x, 0);
2645             p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
2646             /* normalize y + 14:00 */
2647             q1 = xmlSchemaDateNormalize(y, (14 * SECS_PER_HOUR));
2648
2649             q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
2650             if (p1d < q1d) {
2651                 xmlSchemaFreeValue(p1);
2652                 xmlSchemaFreeValue(q1);
2653                 return -1;
2654             } else if (p1d == q1d) {
2655                 double sec;
2656
2657                 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
2658                 if (sec < 0.0) {
2659                     xmlSchemaFreeValue(p1);
2660                     xmlSchemaFreeValue(q1);
2661                     return -1;
2662                 } else {
2663                     /* normalize y - 14:00 */
2664                     q2 = xmlSchemaDateNormalize(y, -(14 * SECS_PER_HOUR));
2665                     q2d = _xmlSchemaDateCastYMToDays(q2) + q2->value.date.day;
2666                     xmlSchemaFreeValue(p1);
2667                     xmlSchemaFreeValue(q1);
2668                     xmlSchemaFreeValue(q2);
2669                     if (p1d > q2d)
2670                         return 1;
2671                     else if (p1d == q2d) {
2672                         sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q2);
2673                         if (sec > 0.0)
2674                             return 1;
2675                         else
2676                             return 2; /* indeterminate */
2677                     }
2678                 }
2679             } else {
2680                 xmlSchemaFreeValue(p1);
2681                 xmlSchemaFreeValue(q1);
2682             }
2683         }
2684     } else if (y->value.date.tz_flag) {
2685         q1 = xmlSchemaDateNormalize(y, 0);
2686         q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
2687
2688         /* normalize x - 14:00 */
2689         p1 = xmlSchemaDateNormalize(x, -(14 * SECS_PER_HOUR));
2690         p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
2691
2692         if (p1d < q1d) {
2693             xmlSchemaFreeValue(p1);
2694             xmlSchemaFreeValue(q1);
2695             return -1;
2696         } else if (p1d == q1d) {
2697             double sec;
2698
2699             sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
2700             if (sec < 0.0) {
2701                 xmlSchemaFreeValue(p1);
2702                 xmlSchemaFreeValue(q1);
2703                 return -1;
2704             } else {
2705                 /* normalize x + 14:00 */
2706                 p2 = xmlSchemaDateNormalize(x, (14 * SECS_PER_HOUR));
2707                 p2d = _xmlSchemaDateCastYMToDays(p2) + p2->value.date.day;
2708
2709                 if (p2d > q1d) {
2710                     xmlSchemaFreeValue(p1);
2711                     xmlSchemaFreeValue(q1);
2712                     xmlSchemaFreeValue(p2);
2713                     return 1;
2714                 } else if (p2d == q1d) {
2715                     sec = TIME_TO_NUMBER(p2) - TIME_TO_NUMBER(q1);
2716                     xmlSchemaFreeValue(p1);
2717                     xmlSchemaFreeValue(q1);
2718                     xmlSchemaFreeValue(p2);
2719                     if (sec > 0.0)
2720                         return 1;
2721                     else
2722                         return 2; /* indeterminate */
2723                 }
2724                 xmlSchemaFreeValue(p1);
2725                 xmlSchemaFreeValue(q1);
2726                 xmlSchemaFreeValue(p2);
2727             }
2728         } else {
2729             xmlSchemaFreeValue(p1);
2730             xmlSchemaFreeValue(q1);
2731         }
2732     }
2733
2734     /*
2735      * if the same type then calculate the difference
2736      */
2737     if (x->type == y->type) {
2738         q1 = xmlSchemaDateNormalize(y, 0);
2739         q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
2740
2741         p1 = xmlSchemaDateNormalize(x, 0);
2742         p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
2743
2744         if (p1d < q1d) {
2745             xmlSchemaFreeValue(p1);
2746             xmlSchemaFreeValue(q1);
2747             return -1;
2748         } else if (p1d > q1d) {
2749             xmlSchemaFreeValue(p1);
2750             xmlSchemaFreeValue(q1);
2751             return 1;
2752         } else {
2753             double sec;
2754
2755             sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
2756             xmlSchemaFreeValue(p1);
2757             xmlSchemaFreeValue(q1);
2758             if (sec < 0.0)
2759                 return -1;
2760             else if (sec > 0.0)
2761                 return 1;
2762             
2763         }
2764         return 0;
2765     }
2766
2767     switch (x->type) {
2768         case XML_SCHEMAS_DATETIME:
2769             xmask = 0xf;
2770             break;
2771         case XML_SCHEMAS_DATE:
2772             xmask = 0x7;
2773             break;
2774         case XML_SCHEMAS_GYEAR:
2775             xmask = 0x1;
2776             break;
2777         case XML_SCHEMAS_GMONTH:
2778             xmask = 0x2;
2779             break;
2780         case XML_SCHEMAS_GDAY:
2781             xmask = 0x3;
2782             break;
2783         case XML_SCHEMAS_GYEARMONTH:
2784             xmask = 0x3;
2785             break;
2786         case XML_SCHEMAS_GMONTHDAY:
2787             xmask = 0x6;
2788             break;
2789         case XML_SCHEMAS_TIME:
2790             xmask = 0x8;
2791             break;
2792         default:
2793             xmask = 0;
2794             break;
2795     }
2796
2797     switch (y->type) {
2798         case XML_SCHEMAS_DATETIME:
2799             ymask = 0xf;
2800             break;
2801         case XML_SCHEMAS_DATE:
2802             ymask = 0x7;
2803             break;
2804         case XML_SCHEMAS_GYEAR:
2805             ymask = 0x1;
2806             break;
2807         case XML_SCHEMAS_GMONTH:
2808             ymask = 0x2;
2809             break;
2810         case XML_SCHEMAS_GDAY:
2811             ymask = 0x3;
2812             break;
2813         case XML_SCHEMAS_GYEARMONTH:
2814             ymask = 0x3;
2815             break;
2816         case XML_SCHEMAS_GMONTHDAY:
2817             ymask = 0x6;
2818             break;
2819         case XML_SCHEMAS_TIME:
2820             ymask = 0x8;
2821             break;
2822         default:
2823             ymask = 0;
2824             break;
2825     }
2826
2827     xor_mask = xmask ^ ymask;           /* mark type differences */
2828     and_mask = xmask & ymask;           /* mark field specification */
2829
2830     /* year */
2831     if (xor_mask & 1)
2832         return 2; /* indeterminate */
2833     else if (and_mask & 1) {
2834         if (x->value.date.year < y->value.date.year)
2835             return -1;
2836         else if (x->value.date.year > y->value.date.year)
2837             return 1;
2838     }
2839
2840     /* month */
2841     if (xor_mask & 2)
2842         return 2; /* indeterminate */
2843     else if (and_mask & 2) {
2844         if (x->value.date.mon < y->value.date.mon)
2845             return -1;
2846         else if (x->value.date.mon > y->value.date.mon)
2847             return 1;
2848     }
2849
2850     /* day */
2851     if (xor_mask & 4)
2852         return 2; /* indeterminate */
2853     else if (and_mask & 4) {
2854         if (x->value.date.day < y->value.date.day)
2855             return -1;
2856         else if (x->value.date.day > y->value.date.day)
2857             return 1;
2858     }
2859
2860     /* time */
2861     if (xor_mask & 8)
2862         return 2; /* indeterminate */
2863     else if (and_mask & 8) {
2864         if (x->value.date.hour < y->value.date.hour)
2865             return -1;
2866         else if (x->value.date.hour > y->value.date.hour)
2867             return 1;
2868         else if (x->value.date.min < y->value.date.min)
2869             return -1;
2870         else if (x->value.date.min > y->value.date.min)
2871             return 1;
2872         else if (x->value.date.sec < y->value.date.sec)
2873             return -1;
2874         else if (x->value.date.sec > y->value.date.sec)
2875             return 1;
2876     }
2877
2878     return 0;
2879 }
2880
2881 /**
2882  * xmlSchemaCompareNormStrings:
2883  * @x:  a first string value
2884  * @y:  a second string value
2885  *
2886  * Compare 2 string for their normalized values.
2887  *
2888  * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
2889  * case of error
2890  */
2891 static int
2892 xmlSchemaCompareNormStrings(xmlSchemaValPtr x, xmlSchemaValPtr y) {
2893     const xmlChar *utf1;
2894     const xmlChar *utf2;
2895     int tmp;
2896
2897     if ((x == NULL) || (y == NULL))
2898         return(-2);
2899     utf1 = x->value.str;
2900     utf2 = y->value.str;
2901     
2902     while (IS_BLANK(*utf1)) utf1++;
2903     while (IS_BLANK(*utf2)) utf2++;
2904     while ((*utf1 != 0) && (*utf2 != 0)) {
2905         if (IS_BLANK(*utf1)) {
2906             if (!IS_BLANK(*utf2)) {
2907                 tmp = *utf1 - *utf2;
2908                 return(tmp);
2909             }
2910             while (IS_BLANK(*utf1)) utf1++;
2911             while (IS_BLANK(*utf2)) utf2++;
2912         } else {
2913             tmp = *utf1++ - *utf2++;
2914             if (tmp < 0)
2915                 return(-1);
2916             if (tmp > 0)
2917                 return(1);
2918         }
2919     }
2920     if (*utf1 != 0) {
2921         while (IS_BLANK(*utf1)) utf1++;
2922         if (*utf1 != 0)
2923             return(1);
2924     }
2925     if (*utf2 != 0) {
2926         while (IS_BLANK(*utf2)) utf2++;
2927         if (*utf2 != 0)
2928             return(-1);
2929     }
2930     return(0);
2931 }
2932
2933 /**
2934  * xmlSchemaCompareFloats:
2935  * @x:  a first float or double value
2936  * @y:  a second float or double value
2937  *
2938  * Compare 2 values
2939  *
2940  * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
2941  * case of error
2942  */
2943 static int
2944 xmlSchemaCompareFloats(xmlSchemaValPtr x, xmlSchemaValPtr y) {
2945     double d1, d2;
2946
2947     if ((x == NULL) || (y == NULL))
2948         return(-2);
2949
2950     /*
2951      * Cast everything to doubles.
2952      */
2953     if (x->type == XML_SCHEMAS_DOUBLE)
2954         d1 = x->value.d;
2955     else if (x->type == XML_SCHEMAS_FLOAT)
2956         d1 = x->value.f;
2957     else
2958         return(-2);
2959
2960     if (y->type == XML_SCHEMAS_DOUBLE)
2961         d2 = y->value.d;
2962     else if (y->type == XML_SCHEMAS_FLOAT)
2963         d2 = y->value.f;
2964     else
2965         return(-2);
2966
2967     /*
2968      * Check for special cases.
2969      */
2970     if (xmlXPathIsNaN(d1)) {
2971         if (xmlXPathIsNaN(d2))
2972             return(0);
2973         return(1);
2974     }
2975     if (xmlXPathIsNaN(d2))
2976         return(-1);
2977     if (d1 == xmlXPathPINF) {
2978         if (d2 == xmlXPathPINF)
2979             return(0);
2980         return(1);
2981     }
2982     if (d2 == xmlXPathPINF)
2983         return(-1);
2984     if (d1 == xmlXPathNINF) {
2985         if (d2 == xmlXPathNINF)
2986             return(0);
2987         return(-1);
2988     }
2989     if (d2 == xmlXPathNINF)
2990         return(1);
2991
2992     /*
2993      * basic tests, the last one we should have equality, but
2994      * portability is more important than speed and handling
2995      * NaN or Inf in a portable way is always a challenge, so ...
2996      */
2997     if (d1 < d2)
2998         return(-1);
2999     if (d1 > d2)
3000         return(1);
3001     if (d1 == d2)
3002         return(0);
3003     return(2);
3004 }
3005
3006 /**
3007  * xmlSchemaCompareValues:
3008  * @x:  a first value
3009  * @y:  a second value
3010  *
3011  * Compare 2 values
3012  *
3013  * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3014  * case of error
3015  */
3016 int
3017 xmlSchemaCompareValues(xmlSchemaValPtr x, xmlSchemaValPtr y) {
3018     if ((x == NULL) || (y == NULL))
3019         return(-2);
3020
3021     switch (x->type) {
3022         case XML_SCHEMAS_UNKNOWN:
3023             return(-2);
3024         case XML_SCHEMAS_INTEGER:
3025         case XML_SCHEMAS_NPINTEGER:
3026         case XML_SCHEMAS_NINTEGER:
3027         case XML_SCHEMAS_NNINTEGER:
3028         case XML_SCHEMAS_PINTEGER:
3029         case XML_SCHEMAS_INT:
3030         case XML_SCHEMAS_UINT:
3031         case XML_SCHEMAS_LONG:
3032         case XML_SCHEMAS_ULONG:
3033         case XML_SCHEMAS_SHORT:
3034         case XML_SCHEMAS_USHORT:
3035         case XML_SCHEMAS_BYTE:
3036         case XML_SCHEMAS_UBYTE:
3037         case XML_SCHEMAS_DECIMAL:
3038             if (y->type == x->type)
3039                 return(xmlSchemaCompareDecimals(x, y));
3040             if ((y->type == XML_SCHEMAS_DECIMAL) ||
3041                 (y->type == XML_SCHEMAS_INTEGER) ||
3042                 (y->type == XML_SCHEMAS_NPINTEGER) ||
3043                 (y->type == XML_SCHEMAS_NINTEGER) ||
3044                 (y->type == XML_SCHEMAS_NNINTEGER) ||
3045                 (y->type == XML_SCHEMAS_PINTEGER) ||
3046                 (y->type == XML_SCHEMAS_INT) ||
3047                 (y->type == XML_SCHEMAS_UINT) ||
3048                 (y->type == XML_SCHEMAS_LONG) ||
3049                 (y->type == XML_SCHEMAS_ULONG) ||
3050                 (y->type == XML_SCHEMAS_SHORT) ||
3051                 (y->type == XML_SCHEMAS_USHORT) ||
3052                 (y->type == XML_SCHEMAS_BYTE) ||
3053                 (y->type == XML_SCHEMAS_UBYTE))
3054                 return(xmlSchemaCompareDecimals(x, y));
3055             return(-2);
3056         case XML_SCHEMAS_DURATION:
3057             if (y->type == XML_SCHEMAS_DURATION)
3058                 return(xmlSchemaCompareDurations(x, y));
3059             return(-2);
3060         case XML_SCHEMAS_TIME:
3061         case XML_SCHEMAS_GDAY:
3062         case XML_SCHEMAS_GMONTH:
3063         case XML_SCHEMAS_GMONTHDAY:
3064         case XML_SCHEMAS_GYEAR:
3065         case XML_SCHEMAS_GYEARMONTH:
3066         case XML_SCHEMAS_DATE:
3067         case XML_SCHEMAS_DATETIME:
3068             if ((y->type == XML_SCHEMAS_DATETIME)  ||
3069                 (y->type == XML_SCHEMAS_TIME)      ||
3070                 (y->type == XML_SCHEMAS_GDAY)      ||
3071                 (y->type == XML_SCHEMAS_GMONTH)    ||
3072                 (y->type == XML_SCHEMAS_GMONTHDAY) ||
3073                 (y->type == XML_SCHEMAS_GYEAR)     ||
3074                 (y->type == XML_SCHEMAS_DATE)      ||
3075                 (y->type == XML_SCHEMAS_GYEARMONTH))
3076                 return (xmlSchemaCompareDates(x, y));
3077             return (-2);
3078         case XML_SCHEMAS_NORMSTRING:
3079         case XML_SCHEMAS_TOKEN:
3080         case XML_SCHEMAS_LANGUAGE:
3081         case XML_SCHEMAS_NMTOKEN:
3082         case XML_SCHEMAS_NAME:
3083         case XML_SCHEMAS_NCNAME:
3084         case XML_SCHEMAS_ID:
3085         case XML_SCHEMAS_IDREF:
3086         case XML_SCHEMAS_ENTITY:
3087         case XML_SCHEMAS_NOTATION:
3088         case XML_SCHEMAS_ANYURI:
3089             if ((y->type == XML_SCHEMAS_NORMSTRING) ||
3090                 (y->type == XML_SCHEMAS_TOKEN) ||
3091                 (y->type == XML_SCHEMAS_LANGUAGE) ||
3092                 (y->type == XML_SCHEMAS_NMTOKEN) ||
3093                 (y->type == XML_SCHEMAS_NAME) ||
3094                 (y->type == XML_SCHEMAS_QNAME) ||
3095                 (y->type == XML_SCHEMAS_NCNAME) ||
3096                 (y->type == XML_SCHEMAS_ID) ||
3097                 (y->type == XML_SCHEMAS_IDREF) ||
3098                 (y->type == XML_SCHEMAS_ENTITY) ||
3099                 (y->type == XML_SCHEMAS_NOTATION) ||
3100                 (y->type == XML_SCHEMAS_ANYURI))
3101                 return (xmlSchemaCompareNormStrings(x, y));
3102             return (-2);
3103         case XML_SCHEMAS_QNAME:
3104             if (y->type == XML_SCHEMAS_QNAME) {
3105                 if ((xmlStrEqual(x->value.qname.name, y->value.qname.name)) &&
3106                     (xmlStrEqual(x->value.qname.uri, y->value.qname.uri)))
3107                     return(0);
3108                 return(2);
3109             }
3110             return (-2);
3111         case XML_SCHEMAS_FLOAT:
3112         case XML_SCHEMAS_DOUBLE:
3113             if ((y->type == XML_SCHEMAS_FLOAT) ||
3114                 (y->type == XML_SCHEMAS_DOUBLE))
3115                 return (xmlSchemaCompareFloats(x, y));
3116             return (-2);
3117         case XML_SCHEMAS_BOOLEAN:
3118             if (y->type == XML_SCHEMAS_BOOLEAN) {
3119                 if (x->value.b == y->value.b)
3120                     return(0);
3121                 if (x->value.b == 0)
3122                     return(-1);
3123                 return(1);
3124             }
3125             return (-2);
3126         case XML_SCHEMAS_HEXBINARY:
3127             if (y->type == XML_SCHEMAS_HEXBINARY) {
3128                 if (x->value.hex.total == y->value.hex.total) {
3129                     int ret = xmlStrcmp(x->value.hex.str, y->value.hex.str);
3130                     if (ret > 0)
3131                         return(1);
3132                     else if (ret == 0)
3133                         return(0);
3134                 }
3135                 else if (x->value.hex.total > y->value.hex.total)
3136                     return(1);
3137
3138                 return(-1);
3139             }
3140             return (-2);
3141         case XML_SCHEMAS_STRING:
3142         case XML_SCHEMAS_IDREFS:
3143         case XML_SCHEMAS_ENTITIES:
3144         case XML_SCHEMAS_NMTOKENS:
3145             TODO
3146             break;
3147     }
3148     return -2;
3149 }
3150
3151 /**
3152  * xmlSchemaNormLen:
3153  * @value:  a string
3154  *
3155  * Computes the UTF8 length of the normalized value of the string
3156  *
3157  * Returns the length or -1 in case of error.
3158  */
3159 static int
3160 xmlSchemaNormLen(const xmlChar *value) {
3161     const xmlChar *utf;
3162     int ret = 0;
3163
3164     if (value == NULL)
3165         return(-1);
3166     utf = value;
3167     while (IS_BLANK(*utf)) utf++;
3168     while (*utf != 0) {
3169         if (utf[0] & 0x80) {
3170             if ((utf[1] & 0xc0) != 0x80)
3171                 return(-1);
3172             if ((utf[0] & 0xe0) == 0xe0) {
3173                 if ((utf[2] & 0xc0) != 0x80)
3174                     return(-1);
3175                 if ((utf[0] & 0xf0) == 0xf0) {
3176                     if ((utf[0] & 0xf8) != 0xf0 || (utf[3] & 0xc0) != 0x80)
3177                         return(-1);
3178                     utf += 4;
3179                 } else {
3180                     utf += 3;
3181                 }
3182             } else {
3183                 utf += 2;
3184             }
3185         } else if (IS_BLANK(*utf)) {
3186             while (IS_BLANK(*utf)) utf++;
3187             if (*utf == 0)
3188                 break;
3189         } else {
3190             utf++;
3191         }
3192         ret++;
3193     }
3194     return(ret);
3195 }
3196
3197 /**
3198  * xmlSchemaValidateFacet:
3199  * @base:  the base type
3200  * @facet:  the facet to check
3201  * @value:  the lexical repr of the value to validate
3202  * @val:  the precomputed value
3203  *
3204  * Check a value against a facet condition
3205  *
3206  * Returns 0 if the element is schemas valid, a positive error code
3207  *     number otherwise and -1 in case of internal or API error.
3208  */
3209 int
3210 xmlSchemaValidateFacet(xmlSchemaTypePtr base ATTRIBUTE_UNUSED,
3211                        xmlSchemaFacetPtr facet,
3212                        const xmlChar *value, xmlSchemaValPtr val)
3213 {
3214     int ret;
3215
3216     switch (facet->type) {
3217         case XML_SCHEMA_FACET_PATTERN:
3218             ret = xmlRegexpExec(facet->regexp, value);
3219             if (ret == 1)
3220                 return(0);
3221             if (ret == 0) {
3222                 /* TODO error code */
3223                 return(1);
3224             }
3225             return(ret);
3226         case XML_SCHEMA_FACET_MAXEXCLUSIVE:
3227             ret = xmlSchemaCompareValues(val, facet->val);
3228             if (ret == -2) {
3229                 /* TODO error code */
3230                 return(-1);
3231             }
3232             if (ret == -1)
3233                 return(0);
3234             /* error code */
3235             return(1);
3236         case XML_SCHEMA_FACET_MAXINCLUSIVE:
3237             ret = xmlSchemaCompareValues(val, facet->val);
3238             if (ret == -2) {
3239                 /* TODO error code */
3240                 return(-1);
3241             }
3242             if ((ret == -1) || (ret == 0))
3243                 return(0);
3244             /* error code */
3245             return(1);
3246         case XML_SCHEMA_FACET_MINEXCLUSIVE:
3247             ret = xmlSchemaCompareValues(val, facet->val);
3248             if (ret == -2) {
3249                 /* TODO error code */
3250                 return(-1);
3251             }
3252             if (ret == 1)
3253                 return(0);
3254             /* error code */
3255             return(1);
3256         case XML_SCHEMA_FACET_MININCLUSIVE:
3257             ret = xmlSchemaCompareValues(val, facet->val);
3258             if (ret == -2) {
3259                 /* TODO error code */
3260                 return(-1);
3261             }
3262             if ((ret == 1) || (ret == 0))
3263                 return(0);