5f38599044632541a6b5337f87614fdc98a00b71
[platform/upstream/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 #ifdef HAVE_FLOAT_H
32 #include <float.h>
33 #endif
34
35 #define DEBUG
36
37 #ifndef LIBXML_XPATH_ENABLED
38 extern double xmlXPathNAN;
39 extern double xmlXPathPINF;
40 extern double xmlXPathNINF;
41 #endif
42
43 #define TODO                                                            \
44     xmlGenericError(xmlGenericErrorContext,                             \
45             "Unimplemented block at %s:%d\n",                           \
46             __FILE__, __LINE__);
47
48 #define XML_SCHEMAS_NAMESPACE_NAME \
49     (const xmlChar *)"http://www.w3.org/2001/XMLSchema"
50
51 #define IS_WSP_REPLACE_CH(c)    ((((c) == 0x9) || ((c) == 0xa)) || \
52                                  ((c) == 0xd))
53
54 #define IS_WSP_SPACE_CH(c)      ((c) == 0x20)
55
56 #define IS_WSP_BLANK_CH(c) IS_BLANK_CH(c)
57
58 /* Date value */
59 typedef struct _xmlSchemaValDate xmlSchemaValDate;
60 typedef xmlSchemaValDate *xmlSchemaValDatePtr;
61 struct _xmlSchemaValDate {
62     long                year;
63     unsigned int        mon     :4;     /* 1 <=  mon    <= 12   */
64     unsigned int        day     :5;     /* 1 <=  day    <= 31   */
65     unsigned int        hour    :5;     /* 0 <=  hour   <= 24   */
66     unsigned int        min     :6;     /* 0 <=  min    <= 59   */
67     double              sec;
68     unsigned int        tz_flag :1;     /* is tzo explicitely set? */
69     signed int          tzo     :12;    /* -1440 <= tzo <= 1440;
70                                            currently only -840 to +840 are needed */
71 };
72
73 /* Duration value */
74 typedef struct _xmlSchemaValDuration xmlSchemaValDuration;
75 typedef xmlSchemaValDuration *xmlSchemaValDurationPtr;
76 struct _xmlSchemaValDuration {
77     long                mon;            /* mon stores years also */
78     long        day;
79     double              sec;            /* sec stores min and hour also */
80 };
81
82 typedef struct _xmlSchemaValDecimal xmlSchemaValDecimal;
83 typedef xmlSchemaValDecimal *xmlSchemaValDecimalPtr;
84 struct _xmlSchemaValDecimal {
85     /* would use long long but not portable */
86     unsigned long lo;
87     unsigned long mi;
88     unsigned long hi;
89     unsigned int extra;
90     unsigned int sign:1;
91     unsigned int frac:7;
92     unsigned int total:8;
93 };
94
95 typedef struct _xmlSchemaValQName xmlSchemaValQName;
96 typedef xmlSchemaValQName *xmlSchemaValQNamePtr;
97 struct _xmlSchemaValQName {
98     xmlChar *name;
99     xmlChar *uri;
100 };
101
102 typedef struct _xmlSchemaValHex xmlSchemaValHex;
103 typedef xmlSchemaValHex *xmlSchemaValHexPtr;
104 struct _xmlSchemaValHex {
105     xmlChar     *str;
106     unsigned int total;
107 };
108
109 typedef struct _xmlSchemaValBase64 xmlSchemaValBase64;
110 typedef xmlSchemaValBase64 *xmlSchemaValBase64Ptr;
111 struct _xmlSchemaValBase64 {
112     xmlChar     *str;
113     unsigned int total;
114 };
115
116 struct _xmlSchemaVal {
117     xmlSchemaValType type;
118     struct _xmlSchemaVal *next;
119     union {
120         xmlSchemaValDecimal     decimal;
121         xmlSchemaValDate        date;
122         xmlSchemaValDuration    dur;
123         xmlSchemaValQName       qname;
124         xmlSchemaValHex         hex;
125         xmlSchemaValBase64      base64;
126         float                   f;
127         double                  d;
128         int                     b;
129         xmlChar                *str;
130     } value;
131 };
132
133 static int xmlSchemaTypesInitialized = 0;
134 static xmlHashTablePtr xmlSchemaTypesBank = NULL;
135
136 /*
137  * Basic types
138  */
139 static xmlSchemaTypePtr xmlSchemaTypeStringDef = NULL;
140 static xmlSchemaTypePtr xmlSchemaTypeAnyTypeDef = NULL;
141 static xmlSchemaTypePtr xmlSchemaTypeAnySimpleTypeDef = NULL;
142 static xmlSchemaTypePtr xmlSchemaTypeDecimalDef = NULL;
143 static xmlSchemaTypePtr xmlSchemaTypeDatetimeDef = NULL;
144 static xmlSchemaTypePtr xmlSchemaTypeDateDef = NULL;
145 static xmlSchemaTypePtr xmlSchemaTypeTimeDef = NULL;
146 static xmlSchemaTypePtr xmlSchemaTypeGYearDef = NULL;
147 static xmlSchemaTypePtr xmlSchemaTypeGYearMonthDef = NULL;
148 static xmlSchemaTypePtr xmlSchemaTypeGDayDef = NULL;
149 static xmlSchemaTypePtr xmlSchemaTypeGMonthDayDef = NULL;
150 static xmlSchemaTypePtr xmlSchemaTypeGMonthDef = NULL;
151 static xmlSchemaTypePtr xmlSchemaTypeDurationDef = NULL;
152 static xmlSchemaTypePtr xmlSchemaTypeFloatDef = NULL;
153 static xmlSchemaTypePtr xmlSchemaTypeBooleanDef = NULL;
154 static xmlSchemaTypePtr xmlSchemaTypeDoubleDef = NULL;
155 static xmlSchemaTypePtr xmlSchemaTypeHexBinaryDef = NULL;
156 static xmlSchemaTypePtr xmlSchemaTypeBase64BinaryDef = NULL;
157 static xmlSchemaTypePtr xmlSchemaTypeAnyURIDef = NULL;
158
159 /*
160  * Derived types
161  */
162 static xmlSchemaTypePtr xmlSchemaTypePositiveIntegerDef = NULL;
163 static xmlSchemaTypePtr xmlSchemaTypeNonPositiveIntegerDef = NULL;
164 static xmlSchemaTypePtr xmlSchemaTypeNegativeIntegerDef = NULL;
165 static xmlSchemaTypePtr xmlSchemaTypeNonNegativeIntegerDef = NULL;
166 static xmlSchemaTypePtr xmlSchemaTypeIntegerDef = NULL;
167 static xmlSchemaTypePtr xmlSchemaTypeLongDef = NULL;
168 static xmlSchemaTypePtr xmlSchemaTypeIntDef = NULL;
169 static xmlSchemaTypePtr xmlSchemaTypeShortDef = NULL;
170 static xmlSchemaTypePtr xmlSchemaTypeByteDef = NULL;
171 static xmlSchemaTypePtr xmlSchemaTypeUnsignedLongDef = NULL;
172 static xmlSchemaTypePtr xmlSchemaTypeUnsignedIntDef = NULL;
173 static xmlSchemaTypePtr xmlSchemaTypeUnsignedShortDef = NULL;
174 static xmlSchemaTypePtr xmlSchemaTypeUnsignedByteDef = NULL;
175 static xmlSchemaTypePtr xmlSchemaTypeNormStringDef = NULL;
176 static xmlSchemaTypePtr xmlSchemaTypeTokenDef = NULL;
177 static xmlSchemaTypePtr xmlSchemaTypeLanguageDef = NULL;
178 static xmlSchemaTypePtr xmlSchemaTypeNameDef = NULL;
179 static xmlSchemaTypePtr xmlSchemaTypeQNameDef = NULL;
180 static xmlSchemaTypePtr xmlSchemaTypeNCNameDef = NULL;
181 static xmlSchemaTypePtr xmlSchemaTypeIdDef = NULL;
182 static xmlSchemaTypePtr xmlSchemaTypeIdrefDef = NULL;
183 static xmlSchemaTypePtr xmlSchemaTypeIdrefsDef = NULL;
184 static xmlSchemaTypePtr xmlSchemaTypeEntityDef = NULL;
185 static xmlSchemaTypePtr xmlSchemaTypeEntitiesDef = NULL;
186 static xmlSchemaTypePtr xmlSchemaTypeNotationDef = NULL;
187 static xmlSchemaTypePtr xmlSchemaTypeNmtokenDef = NULL;
188 static xmlSchemaTypePtr xmlSchemaTypeNmtokensDef = NULL;
189
190 /************************************************************************
191  *                                                                      *
192  *                      Datatype error handlers                         *
193  *                                                                      *
194  ************************************************************************/
195 /**
196  * xmlSchemaTypeErrMemory:
197  * @extra:  extra informations
198  *
199  * Handle an out of memory condition
200  */
201 static void
202 xmlSchemaTypeErrMemory(xmlNodePtr node, const char *extra)
203 {
204     __xmlSimpleError(XML_FROM_DATATYPE, XML_ERR_NO_MEMORY, node, NULL, extra);
205 }
206
207 /************************************************************************
208  *                                                                      *
209  *                      Base types support                              *
210  *                                                                      *
211  ************************************************************************/
212
213 /**
214  * xmlSchemaNewValue:
215  * @type:  the value type
216  *
217  * Allocate a new simple type value
218  *
219  * Returns a pointer to the new value or NULL in case of error
220  */
221 static xmlSchemaValPtr
222 xmlSchemaNewValue(xmlSchemaValType type) {
223     xmlSchemaValPtr value;
224
225     value = (xmlSchemaValPtr) xmlMalloc(sizeof(xmlSchemaVal));
226     if (value == NULL) {
227         return(NULL);
228     }
229     memset(value, 0, sizeof(xmlSchemaVal));
230     value->type = type;
231     return(value);
232 }
233
234 static xmlSchemaFacetPtr
235 xmlSchemaNewMinLengthFacet(int value)
236 {
237     xmlSchemaFacetPtr ret;
238
239     ret = xmlSchemaNewFacet();
240     if (ret == NULL) {
241         return(NULL);
242     }
243     ret->type = XML_SCHEMA_FACET_MINLENGTH;
244     ret->val = xmlSchemaNewValue(XML_SCHEMAS_NNINTEGER);
245     if (ret->val == NULL) {
246         xmlFree(ret);
247         return(NULL);
248     }
249     ret->val->value.decimal.lo = value;
250     return (ret);
251 }
252
253 /*
254  * xmlSchemaInitBasicType:
255  * @name:  the type name
256  * @type:  the value type associated
257  *
258  * Initialize one primitive built-in type
259  */
260 static xmlSchemaTypePtr
261 xmlSchemaInitBasicType(const char *name, xmlSchemaValType type,
262                        xmlSchemaTypePtr baseType) {
263     xmlSchemaTypePtr ret;
264
265     ret = (xmlSchemaTypePtr) xmlMalloc(sizeof(xmlSchemaType));
266     if (ret == NULL) {
267         xmlSchemaTypeErrMemory(NULL, "could not initialize basic types");
268         return(NULL);
269     }
270     memset(ret, 0, sizeof(xmlSchemaType));
271     ret->name = (const xmlChar *)name;
272     ret->targetNamespace = XML_SCHEMAS_NAMESPACE_NAME;
273     ret->type = XML_SCHEMA_TYPE_BASIC;
274     ret->baseType = baseType;
275     ret->contentType = XML_SCHEMA_CONTENT_BASIC;
276     /*
277     * Primitive types.
278     */
279     switch (type) {
280         case XML_SCHEMAS_STRING:
281         case XML_SCHEMAS_DECIMAL:
282         case XML_SCHEMAS_DATE:
283         case XML_SCHEMAS_DATETIME:
284         case XML_SCHEMAS_TIME:
285         case XML_SCHEMAS_GYEAR:
286         case XML_SCHEMAS_GYEARMONTH:
287         case XML_SCHEMAS_GMONTH:
288         case XML_SCHEMAS_GMONTHDAY:
289         case XML_SCHEMAS_GDAY:
290         case XML_SCHEMAS_DURATION:
291         case XML_SCHEMAS_FLOAT:
292         case XML_SCHEMAS_DOUBLE:
293         case XML_SCHEMAS_BOOLEAN:
294         case XML_SCHEMAS_ANYURI:
295         case XML_SCHEMAS_HEXBINARY:
296         case XML_SCHEMAS_BASE64BINARY:
297         case XML_SCHEMAS_QNAME:
298         case XML_SCHEMAS_NOTATION:
299             ret->flags |= XML_SCHEMAS_TYPE_BUILTIN_PRIMITIVE;
300             break;
301         default:
302             break;
303     }
304     /*
305     * Set variety.
306     */
307     switch (type) {
308         case XML_SCHEMAS_ANYTYPE:
309         case XML_SCHEMAS_ANYSIMPLETYPE:
310             break;
311         case XML_SCHEMAS_IDREFS:
312         case XML_SCHEMAS_NMTOKENS:
313         case XML_SCHEMAS_ENTITIES:
314             ret->flags |= XML_SCHEMAS_TYPE_VARIETY_LIST;
315             ret->facets = xmlSchemaNewMinLengthFacet(1);
316             ret->flags |= XML_SCHEMAS_TYPE_HAS_FACETS;
317             break;
318         default:
319             ret->flags |= XML_SCHEMAS_TYPE_VARIETY_ATOMIC;
320             break;
321     }
322     xmlHashAddEntry2(xmlSchemaTypesBank, ret->name,
323                      XML_SCHEMAS_NAMESPACE_NAME, ret);
324     ret->builtInType = type;
325     return(ret);
326 }
327
328 /*
329 * WARNING: Those type reside normally in xmlschemas.c but are
330 * redefined here locally in oder of being able to use them for xs:anyType-
331 * TODO: Remove those definition if we move the types to a header file.
332 * TODO: Always keep those structs up-to-date with the originals.
333 */
334 #define UNBOUNDED (1 << 30)
335
336 typedef struct _xmlSchemaTreeItem xmlSchemaTreeItem;
337 typedef xmlSchemaTreeItem *xmlSchemaTreeItemPtr;
338 struct _xmlSchemaTreeItem {
339     xmlSchemaTypeType type;
340     xmlSchemaAnnotPtr annot;
341     xmlSchemaTreeItemPtr next;
342     xmlSchemaTreeItemPtr children;
343 };
344
345 typedef struct _xmlSchemaParticle xmlSchemaParticle;
346 typedef xmlSchemaParticle *xmlSchemaParticlePtr;
347 struct _xmlSchemaParticle {
348     xmlSchemaTypeType type;
349     xmlSchemaAnnotPtr annot;
350     xmlSchemaTreeItemPtr next;
351     xmlSchemaTreeItemPtr children;
352     int minOccurs;
353     int maxOccurs;
354     xmlNodePtr node;
355 };
356
357 typedef struct _xmlSchemaModelGroup xmlSchemaModelGroup;
358 typedef xmlSchemaModelGroup *xmlSchemaModelGroupPtr;
359 struct _xmlSchemaModelGroup {
360     xmlSchemaTypeType type;
361     xmlSchemaAnnotPtr annot;
362     xmlSchemaTreeItemPtr next;
363     xmlSchemaTreeItemPtr children;
364     xmlNodePtr node;
365 };
366
367 static xmlSchemaParticlePtr
368 xmlSchemaAddParticle(void)
369 {
370     xmlSchemaParticlePtr ret = NULL;
371
372     ret = (xmlSchemaParticlePtr)
373         xmlMalloc(sizeof(xmlSchemaParticle));
374     if (ret == NULL) {
375         xmlSchemaTypeErrMemory(NULL, "allocating particle component");
376         return (NULL);
377     }
378     memset(ret, 0, sizeof(xmlSchemaParticle));
379     ret->type = XML_SCHEMA_TYPE_PARTICLE;
380     ret->minOccurs = 1;
381     ret->maxOccurs = 1;
382     return (ret);
383 }
384
385 /*
386  * xmlSchemaInitTypes:
387  *
388  * Initialize the default XML Schemas type library
389  */
390 void
391 xmlSchemaInitTypes(void)
392 {
393     if (xmlSchemaTypesInitialized != 0)
394         return;
395     xmlSchemaTypesBank = xmlHashCreate(40);
396
397
398     /*
399     * 3.4.7 Built-in Complex Type Definition
400     */
401     xmlSchemaTypeAnyTypeDef = xmlSchemaInitBasicType("anyType",
402                                                      XML_SCHEMAS_ANYTYPE,
403                                                      NULL);
404     xmlSchemaTypeAnyTypeDef->baseType = xmlSchemaTypeAnyTypeDef;
405     xmlSchemaTypeAnyTypeDef->contentType = XML_SCHEMA_CONTENT_MIXED;
406     /*
407     * Init the content type.
408     */
409     xmlSchemaTypeAnyTypeDef->contentType = XML_SCHEMA_CONTENT_MIXED;
410     {
411         xmlSchemaParticlePtr particle;
412         xmlSchemaModelGroupPtr sequence;
413         xmlSchemaWildcardPtr wild;
414         /* First particle. */
415         particle = xmlSchemaAddParticle();
416         if (particle == NULL)
417             return;
418         xmlSchemaTypeAnyTypeDef->subtypes = (xmlSchemaTypePtr) particle;
419         /* Sequence model group. */
420         sequence = (xmlSchemaModelGroupPtr)
421             xmlMalloc(sizeof(xmlSchemaModelGroup));
422         if (sequence == NULL) {
423             xmlSchemaTypeErrMemory(NULL, "allocating model group component");
424             return;
425         }
426         memset(sequence, 0, sizeof(xmlSchemaModelGroup));
427         sequence->type = XML_SCHEMA_TYPE_SEQUENCE;
428         particle->children = (xmlSchemaTreeItemPtr) sequence;
429         /* Second particle. */
430         particle = xmlSchemaAddParticle();
431         if (particle == NULL)
432             return;
433         particle->minOccurs = 0;
434         particle->maxOccurs = UNBOUNDED;
435         sequence->children = (xmlSchemaTreeItemPtr) particle;
436         /* The wildcard */
437         wild = (xmlSchemaWildcardPtr) xmlMalloc(sizeof(xmlSchemaWildcard));
438         if (wild == NULL) {
439             xmlSchemaTypeErrMemory(NULL, "allocating wildcard component");
440             return;
441         }
442         memset(wild, 0, sizeof(xmlSchemaWildcard));
443         wild->type = XML_SCHEMA_TYPE_ANY;
444         wild->any = 1;
445         wild->processContents = XML_SCHEMAS_ANY_LAX;
446         particle->children = (xmlSchemaTreeItemPtr) wild;
447         /*
448         * Create the attribute wildcard.
449         */
450         wild = (xmlSchemaWildcardPtr) xmlMalloc(sizeof(xmlSchemaWildcard));
451         if (wild == NULL) {
452             xmlSchemaTypeErrMemory(NULL, "could not create an attribute "
453                 "wildcard on anyType");
454             return;
455         }
456         memset(wild, 0, sizeof(xmlSchemaWildcard));
457         wild->any = 1;
458         wild->processContents = XML_SCHEMAS_ANY_LAX;
459         xmlSchemaTypeAnyTypeDef->attributeWildcard = wild;
460     }
461     xmlSchemaTypeAnySimpleTypeDef = xmlSchemaInitBasicType("anySimpleType",
462                                                            XML_SCHEMAS_ANYSIMPLETYPE,
463                                                            xmlSchemaTypeAnyTypeDef);
464     /*
465     * primitive datatypes
466     */
467     xmlSchemaTypeStringDef = xmlSchemaInitBasicType("string",
468                                                     XML_SCHEMAS_STRING,
469                                                     xmlSchemaTypeAnySimpleTypeDef);
470     xmlSchemaTypeDecimalDef = xmlSchemaInitBasicType("decimal",
471                                                      XML_SCHEMAS_DECIMAL,
472                                                      xmlSchemaTypeAnySimpleTypeDef);
473     xmlSchemaTypeDateDef = xmlSchemaInitBasicType("date",
474                                                   XML_SCHEMAS_DATE,
475                                                   xmlSchemaTypeAnySimpleTypeDef);
476     xmlSchemaTypeDatetimeDef = xmlSchemaInitBasicType("dateTime",
477                                                       XML_SCHEMAS_DATETIME,
478                                                       xmlSchemaTypeAnySimpleTypeDef);
479     xmlSchemaTypeTimeDef = xmlSchemaInitBasicType("time",
480                                                   XML_SCHEMAS_TIME,
481                                                   xmlSchemaTypeAnySimpleTypeDef);
482     xmlSchemaTypeGYearDef = xmlSchemaInitBasicType("gYear",
483                                                    XML_SCHEMAS_GYEAR,
484                                                    xmlSchemaTypeAnySimpleTypeDef);
485     xmlSchemaTypeGYearMonthDef = xmlSchemaInitBasicType("gYearMonth",
486                                                         XML_SCHEMAS_GYEARMONTH,
487                                                         xmlSchemaTypeAnySimpleTypeDef);
488     xmlSchemaTypeGMonthDef = xmlSchemaInitBasicType("gMonth",
489                                                     XML_SCHEMAS_GMONTH,
490                                                     xmlSchemaTypeAnySimpleTypeDef);
491     xmlSchemaTypeGMonthDayDef = xmlSchemaInitBasicType("gMonthDay",
492                                                        XML_SCHEMAS_GMONTHDAY,
493                                                        xmlSchemaTypeAnySimpleTypeDef);
494     xmlSchemaTypeGDayDef = xmlSchemaInitBasicType("gDay",
495                                                   XML_SCHEMAS_GDAY,
496                                                   xmlSchemaTypeAnySimpleTypeDef);
497     xmlSchemaTypeDurationDef = xmlSchemaInitBasicType("duration",
498                                                       XML_SCHEMAS_DURATION,
499                                                       xmlSchemaTypeAnySimpleTypeDef);
500     xmlSchemaTypeFloatDef = xmlSchemaInitBasicType("float",
501                                                    XML_SCHEMAS_FLOAT,
502                                                    xmlSchemaTypeAnySimpleTypeDef);
503     xmlSchemaTypeDoubleDef = xmlSchemaInitBasicType("double",
504                                                     XML_SCHEMAS_DOUBLE,
505                                                     xmlSchemaTypeAnySimpleTypeDef);
506     xmlSchemaTypeBooleanDef = xmlSchemaInitBasicType("boolean",
507                                                      XML_SCHEMAS_BOOLEAN,
508                                                      xmlSchemaTypeAnySimpleTypeDef);
509     xmlSchemaTypeAnyURIDef = xmlSchemaInitBasicType("anyURI",
510                                                     XML_SCHEMAS_ANYURI,
511                                                     xmlSchemaTypeAnySimpleTypeDef);
512     xmlSchemaTypeHexBinaryDef = xmlSchemaInitBasicType("hexBinary",
513                                                      XML_SCHEMAS_HEXBINARY,
514                                                      xmlSchemaTypeAnySimpleTypeDef);
515     xmlSchemaTypeBase64BinaryDef
516         = xmlSchemaInitBasicType("base64Binary", XML_SCHEMAS_BASE64BINARY,
517         xmlSchemaTypeAnySimpleTypeDef);
518     xmlSchemaTypeNotationDef = xmlSchemaInitBasicType("NOTATION",
519                                                     XML_SCHEMAS_NOTATION,
520                                                     xmlSchemaTypeAnySimpleTypeDef);
521     xmlSchemaTypeQNameDef = xmlSchemaInitBasicType("QName",
522                                                    XML_SCHEMAS_QNAME,
523                                                    xmlSchemaTypeAnySimpleTypeDef);
524
525     /*
526      * derived datatypes
527      */
528     xmlSchemaTypeIntegerDef = xmlSchemaInitBasicType("integer",
529                                                      XML_SCHEMAS_INTEGER,
530                                                      xmlSchemaTypeDecimalDef);
531     xmlSchemaTypeNonPositiveIntegerDef =
532         xmlSchemaInitBasicType("nonPositiveInteger",
533                                XML_SCHEMAS_NPINTEGER,
534                                xmlSchemaTypeIntegerDef);
535     xmlSchemaTypeNegativeIntegerDef =
536         xmlSchemaInitBasicType("negativeInteger", XML_SCHEMAS_NINTEGER,
537         xmlSchemaTypeNonPositiveIntegerDef);
538     xmlSchemaTypeLongDef =
539         xmlSchemaInitBasicType("long", XML_SCHEMAS_LONG,
540         xmlSchemaTypeIntegerDef);
541     xmlSchemaTypeIntDef = xmlSchemaInitBasicType("int", XML_SCHEMAS_INT,
542         xmlSchemaTypeLongDef);
543     xmlSchemaTypeShortDef = xmlSchemaInitBasicType("short",
544                                                    XML_SCHEMAS_SHORT,
545                                                    xmlSchemaTypeIntDef);
546     xmlSchemaTypeByteDef = xmlSchemaInitBasicType("byte",
547                                                   XML_SCHEMAS_BYTE,
548                                                   xmlSchemaTypeShortDef);
549     xmlSchemaTypeNonNegativeIntegerDef =
550         xmlSchemaInitBasicType("nonNegativeInteger",
551                                XML_SCHEMAS_NNINTEGER,
552                                xmlSchemaTypeIntegerDef);
553     xmlSchemaTypeUnsignedLongDef =
554         xmlSchemaInitBasicType("unsignedLong", XML_SCHEMAS_ULONG,
555         xmlSchemaTypeNonNegativeIntegerDef);
556     xmlSchemaTypeUnsignedIntDef =
557         xmlSchemaInitBasicType("unsignedInt", XML_SCHEMAS_UINT,
558         xmlSchemaTypeUnsignedLongDef);
559     xmlSchemaTypeUnsignedShortDef =
560         xmlSchemaInitBasicType("unsignedShort", XML_SCHEMAS_USHORT,
561         xmlSchemaTypeUnsignedIntDef);
562     xmlSchemaTypeUnsignedByteDef =
563         xmlSchemaInitBasicType("unsignedByte", XML_SCHEMAS_UBYTE,
564         xmlSchemaTypeUnsignedShortDef);
565     xmlSchemaTypePositiveIntegerDef =
566         xmlSchemaInitBasicType("positiveInteger", XML_SCHEMAS_PINTEGER,
567         xmlSchemaTypeNonNegativeIntegerDef);
568     xmlSchemaTypeNormStringDef = xmlSchemaInitBasicType("normalizedString",
569                                                         XML_SCHEMAS_NORMSTRING,
570                                                         xmlSchemaTypeStringDef);
571     xmlSchemaTypeTokenDef = xmlSchemaInitBasicType("token",
572                                                    XML_SCHEMAS_TOKEN,
573                                                    xmlSchemaTypeNormStringDef);
574     xmlSchemaTypeLanguageDef = xmlSchemaInitBasicType("language",
575                                                       XML_SCHEMAS_LANGUAGE,
576                                                       xmlSchemaTypeTokenDef);
577     xmlSchemaTypeNameDef = xmlSchemaInitBasicType("Name",
578                                                   XML_SCHEMAS_NAME,
579                                                   xmlSchemaTypeTokenDef);
580     xmlSchemaTypeNmtokenDef = xmlSchemaInitBasicType("NMTOKEN",
581                                                      XML_SCHEMAS_NMTOKEN,
582                                                      xmlSchemaTypeTokenDef);
583     xmlSchemaTypeNCNameDef = xmlSchemaInitBasicType("NCName",
584                                                     XML_SCHEMAS_NCNAME,
585                                                     xmlSchemaTypeNameDef);
586     xmlSchemaTypeIdDef = xmlSchemaInitBasicType("ID", XML_SCHEMAS_ID,
587                                                     xmlSchemaTypeNCNameDef);
588     xmlSchemaTypeIdrefDef = xmlSchemaInitBasicType("IDREF",
589                                                    XML_SCHEMAS_IDREF,
590                                                    xmlSchemaTypeNCNameDef);
591     xmlSchemaTypeEntityDef = xmlSchemaInitBasicType("ENTITY",
592                                                     XML_SCHEMAS_ENTITY,
593                                                     xmlSchemaTypeNCNameDef);
594     /*
595     * Derived list types.
596     */
597     /* ENTITIES */
598     xmlSchemaTypeEntitiesDef = xmlSchemaInitBasicType("ENTITIES",
599                                                       XML_SCHEMAS_ENTITIES,
600                                                       xmlSchemaTypeAnySimpleTypeDef);
601     xmlSchemaTypeEntitiesDef->subtypes = xmlSchemaTypeEntityDef;
602     /* IDREFS */
603     xmlSchemaTypeIdrefsDef = xmlSchemaInitBasicType("IDREFS",
604                                                     XML_SCHEMAS_IDREFS,
605                                                     xmlSchemaTypeAnySimpleTypeDef);
606     xmlSchemaTypeIdrefsDef->subtypes = xmlSchemaTypeIdrefDef;
607
608     /* NMTOKENS */
609     xmlSchemaTypeNmtokensDef = xmlSchemaInitBasicType("NMTOKENS",
610                                                       XML_SCHEMAS_NMTOKENS,
611                                                       xmlSchemaTypeAnySimpleTypeDef);
612     xmlSchemaTypeNmtokensDef->subtypes = xmlSchemaTypeNmtokenDef;
613
614     xmlSchemaTypesInitialized = 1;
615 }
616
617 /**
618  * xmlSchemaCleanupTypes:
619  *
620  * Cleanup the default XML Schemas type library
621  */
622 void
623 xmlSchemaCleanupTypes(void) {
624     if (xmlSchemaTypesInitialized == 0)
625         return;
626     /*
627     * Free xs:anyType.
628     */
629     {
630         xmlSchemaParticlePtr particle;
631         /* Attribute wildcard. */
632         xmlSchemaFreeWildcard(xmlSchemaTypeAnyTypeDef->attributeWildcard);
633         /* Content type. */
634         particle = (xmlSchemaParticlePtr) xmlSchemaTypeAnyTypeDef->subtypes;
635         /* Wildcard. */
636         xmlSchemaFreeWildcard((xmlSchemaWildcardPtr)
637             particle->children->children->children);
638         xmlFree((xmlSchemaParticlePtr) particle->children->children);
639         /* Sequence model group. */
640         xmlFree((xmlSchemaModelGroupPtr) particle->children);
641         xmlFree((xmlSchemaParticlePtr) particle);
642         xmlSchemaTypeAnyTypeDef->subtypes = NULL;
643     }
644     xmlHashFree(xmlSchemaTypesBank, (xmlHashDeallocator) xmlSchemaFreeType);
645     xmlSchemaTypesInitialized = 0;
646 }
647
648 /**
649  * xmlSchemaIsBuiltInTypeFacet:
650  * @type: the built-in type
651  * @facetType:  the facet type
652  *
653  * Evaluates if a specific facet can be
654  * used in conjunction with a type.
655  *
656  * Returns 1 if the facet can be used with the given built-in type,
657  * 0 otherwise and -1 in case the type is not a built-in type.
658  */
659 int
660 xmlSchemaIsBuiltInTypeFacet(xmlSchemaTypePtr type, int facetType)
661 {
662     if (type == NULL)
663         return (-1);
664     if (type->type != XML_SCHEMA_TYPE_BASIC)
665         return (-1);
666     switch (type->builtInType) {
667         case XML_SCHEMAS_BOOLEAN:
668             if ((facetType == XML_SCHEMA_FACET_PATTERN) ||
669                 (facetType == XML_SCHEMA_FACET_WHITESPACE))
670                 return (1);
671             else
672                 return (0);
673         case XML_SCHEMAS_STRING:
674         case XML_SCHEMAS_NOTATION:
675         case XML_SCHEMAS_QNAME:
676         case XML_SCHEMAS_ANYURI:
677         case XML_SCHEMAS_BASE64BINARY:
678         case XML_SCHEMAS_HEXBINARY:
679             if ((facetType == XML_SCHEMA_FACET_LENGTH) ||
680                 (facetType == XML_SCHEMA_FACET_MINLENGTH) ||
681                 (facetType == XML_SCHEMA_FACET_MAXLENGTH) ||
682                 (facetType == XML_SCHEMA_FACET_PATTERN) ||
683                 (facetType == XML_SCHEMA_FACET_ENUMERATION) ||
684                 (facetType == XML_SCHEMA_FACET_WHITESPACE))
685                 return (1);
686             else
687                 return (0);
688         case XML_SCHEMAS_DECIMAL:
689             if ((facetType == XML_SCHEMA_FACET_TOTALDIGITS) ||
690                 (facetType == XML_SCHEMA_FACET_FRACTIONDIGITS) ||
691                 (facetType == XML_SCHEMA_FACET_PATTERN) ||
692                 (facetType == XML_SCHEMA_FACET_WHITESPACE) ||
693                 (facetType == XML_SCHEMA_FACET_ENUMERATION) ||
694                 (facetType == XML_SCHEMA_FACET_MAXINCLUSIVE) ||
695                 (facetType == XML_SCHEMA_FACET_MAXEXCLUSIVE) ||
696                 (facetType == XML_SCHEMA_FACET_MININCLUSIVE) ||
697                 (facetType == XML_SCHEMA_FACET_MINEXCLUSIVE))
698                 return (1);
699             else
700                 return (0);
701         case XML_SCHEMAS_TIME:
702         case XML_SCHEMAS_GDAY:
703         case XML_SCHEMAS_GMONTH:
704         case XML_SCHEMAS_GMONTHDAY:
705         case XML_SCHEMAS_GYEAR:
706         case XML_SCHEMAS_GYEARMONTH:
707         case XML_SCHEMAS_DATE:
708         case XML_SCHEMAS_DATETIME:
709         case XML_SCHEMAS_DURATION:
710         case XML_SCHEMAS_FLOAT:
711         case XML_SCHEMAS_DOUBLE:
712             if ((facetType == XML_SCHEMA_FACET_PATTERN) ||
713                 (facetType == XML_SCHEMA_FACET_ENUMERATION) ||
714                 (facetType == XML_SCHEMA_FACET_WHITESPACE) ||
715                 (facetType == XML_SCHEMA_FACET_MAXINCLUSIVE) ||
716                 (facetType == XML_SCHEMA_FACET_MAXEXCLUSIVE) ||
717                 (facetType == XML_SCHEMA_FACET_MININCLUSIVE) ||
718                 (facetType == XML_SCHEMA_FACET_MINEXCLUSIVE))
719                 return (1);
720             else
721                 return (0);
722         default:
723             break;
724     }
725     return (0);
726 }
727
728 /**
729  * xmlSchemaGetBuiltInType:
730  * @type:  the type of the built in type
731  *
732  * Gives you the type struct for a built-in
733  * type by its type id.
734  *
735  * Returns the type if found, NULL otherwise.
736  */
737 xmlSchemaTypePtr
738 xmlSchemaGetBuiltInType(xmlSchemaValType type)
739 {
740     if (xmlSchemaTypesInitialized == 0)
741         xmlSchemaInitTypes();
742     switch (type) {
743
744         case XML_SCHEMAS_ANYSIMPLETYPE:
745             return (xmlSchemaTypeAnySimpleTypeDef);
746         case XML_SCHEMAS_STRING:
747             return (xmlSchemaTypeStringDef);
748         case XML_SCHEMAS_NORMSTRING:
749             return (xmlSchemaTypeNormStringDef);
750         case XML_SCHEMAS_DECIMAL:
751             return (xmlSchemaTypeDecimalDef);
752         case XML_SCHEMAS_TIME:
753             return (xmlSchemaTypeTimeDef);
754         case XML_SCHEMAS_GDAY:
755             return (xmlSchemaTypeGDayDef);
756         case XML_SCHEMAS_GMONTH:
757             return (xmlSchemaTypeGMonthDef);
758         case XML_SCHEMAS_GMONTHDAY:
759             return (xmlSchemaTypeGMonthDayDef);
760         case XML_SCHEMAS_GYEAR:
761             return (xmlSchemaTypeGYearDef);
762         case XML_SCHEMAS_GYEARMONTH:
763             return (xmlSchemaTypeGYearMonthDef);
764         case XML_SCHEMAS_DATE:
765             return (xmlSchemaTypeDateDef);
766         case XML_SCHEMAS_DATETIME:
767             return (xmlSchemaTypeDatetimeDef);
768         case XML_SCHEMAS_DURATION:
769             return (xmlSchemaTypeDurationDef);
770         case XML_SCHEMAS_FLOAT:
771             return (xmlSchemaTypeFloatDef);
772         case XML_SCHEMAS_DOUBLE:
773             return (xmlSchemaTypeDoubleDef);
774         case XML_SCHEMAS_BOOLEAN:
775             return (xmlSchemaTypeBooleanDef);
776         case XML_SCHEMAS_TOKEN:
777             return (xmlSchemaTypeTokenDef);
778         case XML_SCHEMAS_LANGUAGE:
779             return (xmlSchemaTypeLanguageDef);
780         case XML_SCHEMAS_NMTOKEN:
781             return (xmlSchemaTypeNmtokenDef);
782         case XML_SCHEMAS_NMTOKENS:
783             return (xmlSchemaTypeNmtokensDef);
784         case XML_SCHEMAS_NAME:
785             return (xmlSchemaTypeNameDef);
786         case XML_SCHEMAS_QNAME:
787             return (xmlSchemaTypeQNameDef);
788         case XML_SCHEMAS_NCNAME:
789             return (xmlSchemaTypeNCNameDef);
790         case XML_SCHEMAS_ID:
791             return (xmlSchemaTypeIdDef);
792         case XML_SCHEMAS_IDREF:
793             return (xmlSchemaTypeIdrefDef);
794         case XML_SCHEMAS_IDREFS:
795             return (xmlSchemaTypeIdrefsDef);
796         case XML_SCHEMAS_ENTITY:
797             return (xmlSchemaTypeEntityDef);
798         case XML_SCHEMAS_ENTITIES:
799             return (xmlSchemaTypeEntitiesDef);
800         case XML_SCHEMAS_NOTATION:
801             return (xmlSchemaTypeNotationDef);
802         case XML_SCHEMAS_ANYURI:
803             return (xmlSchemaTypeAnyURIDef);
804         case XML_SCHEMAS_INTEGER:
805             return (xmlSchemaTypeIntegerDef);
806         case XML_SCHEMAS_NPINTEGER:
807             return (xmlSchemaTypeNonPositiveIntegerDef);
808         case XML_SCHEMAS_NINTEGER:
809             return (xmlSchemaTypeNegativeIntegerDef);
810         case XML_SCHEMAS_NNINTEGER:
811             return (xmlSchemaTypeNonNegativeIntegerDef);
812         case XML_SCHEMAS_PINTEGER:
813             return (xmlSchemaTypePositiveIntegerDef);
814         case XML_SCHEMAS_INT:
815             return (xmlSchemaTypeIntDef);
816         case XML_SCHEMAS_UINT:
817             return (xmlSchemaTypeUnsignedIntDef);
818         case XML_SCHEMAS_LONG:
819             return (xmlSchemaTypeLongDef);
820         case XML_SCHEMAS_ULONG:
821             return (xmlSchemaTypeUnsignedLongDef);
822         case XML_SCHEMAS_SHORT:
823             return (xmlSchemaTypeShortDef);
824         case XML_SCHEMAS_USHORT:
825             return (xmlSchemaTypeUnsignedShortDef);
826         case XML_SCHEMAS_BYTE:
827             return (xmlSchemaTypeByteDef);
828         case XML_SCHEMAS_UBYTE:
829             return (xmlSchemaTypeUnsignedByteDef);
830         case XML_SCHEMAS_HEXBINARY:
831             return (xmlSchemaTypeHexBinaryDef);
832         case XML_SCHEMAS_BASE64BINARY:
833             return (xmlSchemaTypeBase64BinaryDef);
834         case XML_SCHEMAS_ANYTYPE:
835             return (xmlSchemaTypeAnyTypeDef);
836         default:
837             return (NULL);
838     }
839 }
840
841 /**
842  * xmlSchemaValueAppend:
843  * @prev: the value
844  * @cur: the value to be appended
845  *
846  * Appends a next sibling to a list of computed values.
847  *
848  * Returns 0 if succeeded and -1 on API errors.
849  */
850 int
851 xmlSchemaValueAppend(xmlSchemaValPtr prev, xmlSchemaValPtr cur) {
852
853     if ((prev == NULL) || (cur == NULL))
854         return (-1);
855     prev->next = cur;
856     return (0);
857 }
858
859 /**
860  * xmlSchemaValueGetNext:
861  * @cur: the value
862  *
863  * Accessor for the next sibling of a list of computed values.
864  *
865  * Returns the next value or NULL if there was none, or on
866  *         API errors.
867  */
868 xmlSchemaValPtr
869 xmlSchemaValueGetNext(xmlSchemaValPtr cur) {
870
871     if (cur == NULL)
872         return (NULL);
873     return (cur->next);
874 }
875
876 /**
877  * xmlSchemaValueGetAsString:
878  * @val: the value
879  *
880  * Accessor for the string value of a computed value.
881  *
882  * Returns the string value or NULL if there was none, or on
883  *         API errors.
884  */
885 const xmlChar *
886 xmlSchemaValueGetAsString(xmlSchemaValPtr val)
887 {
888     if (val == NULL)
889         return (NULL);
890     switch (val->type) {
891         case XML_SCHEMAS_STRING:
892         case XML_SCHEMAS_NORMSTRING:
893         case XML_SCHEMAS_ANYSIMPLETYPE:
894         case XML_SCHEMAS_TOKEN:
895         case XML_SCHEMAS_LANGUAGE:
896         case XML_SCHEMAS_NMTOKEN:
897         case XML_SCHEMAS_NAME:
898         case XML_SCHEMAS_NCNAME:
899         case XML_SCHEMAS_ID:
900         case XML_SCHEMAS_IDREF:
901         case XML_SCHEMAS_ENTITY:
902         case XML_SCHEMAS_ANYURI:
903             return (BAD_CAST val->value.str);
904         default:
905             break;
906     }
907     return (NULL);
908 }
909
910 /**
911  * xmlSchemaValueGetAsBoolean:
912  * @val: the value
913  *
914  * Accessor for the boolean value of a computed value.
915  *
916  * Returns 1 if true and 0 if false, or in case of an error. Hmm.
917  */
918 int
919 xmlSchemaValueGetAsBoolean(xmlSchemaValPtr val)
920 {
921     if ((val == NULL) || (val->type != XML_SCHEMAS_BOOLEAN))
922         return (0);
923     return (val->value.b);
924 }
925
926 /**
927  * xmlSchemaNewStringValue:
928  * @type:  the value type
929  * @value:  the value
930  *
931  * Allocate a new simple type value. The type can be
932  * of XML_SCHEMAS_STRING.
933  * WARNING: This one is intended to be expanded for other
934  * string based types. We need this for anySimpleType as well.
935  * The given value is consumed and freed with the struct.
936  *
937  * Returns a pointer to the new value or NULL in case of error
938  */
939 xmlSchemaValPtr
940 xmlSchemaNewStringValue(xmlSchemaValType type,
941                         const xmlChar *value)
942 {
943     xmlSchemaValPtr val;
944
945     if (type != XML_SCHEMAS_STRING)
946         return(NULL);
947     val = (xmlSchemaValPtr) xmlMalloc(sizeof(xmlSchemaVal));
948     if (val == NULL) {
949         return(NULL);
950     }
951     memset(val, 0, sizeof(xmlSchemaVal));
952     val->type = type;
953     val->value.str = (xmlChar *) value;
954     return(val);
955 }
956
957 /**
958  * xmlSchemaNewNOTATIONValue:
959  * @name:  the notation name
960  * @ns: the notation namespace name or NULL
961  *
962  * Allocate a new NOTATION value.
963  * The given values are consumed and freed with the struct.
964  *
965  * Returns a pointer to the new value or NULL in case of error
966  */
967 xmlSchemaValPtr
968 xmlSchemaNewNOTATIONValue(const xmlChar *name,
969                           const xmlChar *ns)
970 {
971     xmlSchemaValPtr val;
972
973     val = xmlSchemaNewValue(XML_SCHEMAS_NOTATION);
974     if (val == NULL)
975         return (NULL);
976
977     val->value.qname.name = (xmlChar *)name;
978     if (ns != NULL)
979         val->value.qname.uri = (xmlChar *)ns;
980     return(val);
981 }
982
983 /**
984  * xmlSchemaNewQNameValue:
985  * @namespaceName: the namespace name
986  * @localName: the local name
987  *
988  * Allocate a new QName value.
989  * The given values are consumed and freed with the struct.
990  *
991  * Returns a pointer to the new value or NULL in case of an error.
992  */
993 xmlSchemaValPtr
994 xmlSchemaNewQNameValue(const xmlChar *namespaceName,
995                        const xmlChar *localName)
996 {
997     xmlSchemaValPtr val;
998
999     val = xmlSchemaNewValue(XML_SCHEMAS_QNAME);
1000     if (val == NULL)
1001         return (NULL);
1002
1003     val->value.qname.name = (xmlChar *) localName;
1004     val->value.qname.uri = (xmlChar *) namespaceName;
1005     return(val);
1006 }
1007
1008 /**
1009  * xmlSchemaFreeValue:
1010  * @value:  the value to free
1011  *
1012  * Cleanup the default XML Schemas type library
1013  */
1014 void
1015 xmlSchemaFreeValue(xmlSchemaValPtr value) {
1016     xmlSchemaValPtr prev;
1017
1018     while (value != NULL) {
1019         switch (value->type) {
1020             case XML_SCHEMAS_STRING:
1021             case XML_SCHEMAS_NORMSTRING:
1022             case XML_SCHEMAS_TOKEN:
1023             case XML_SCHEMAS_LANGUAGE:
1024             case XML_SCHEMAS_NMTOKEN:
1025             case XML_SCHEMAS_NMTOKENS:
1026             case XML_SCHEMAS_NAME:
1027             case XML_SCHEMAS_NCNAME:
1028             case XML_SCHEMAS_ID:
1029             case XML_SCHEMAS_IDREF:
1030             case XML_SCHEMAS_IDREFS:
1031             case XML_SCHEMAS_ENTITY:
1032             case XML_SCHEMAS_ENTITIES:
1033             case XML_SCHEMAS_ANYURI:
1034             case XML_SCHEMAS_ANYSIMPLETYPE:
1035                 if (value->value.str != NULL)
1036                     xmlFree(value->value.str);
1037                 break;
1038             case XML_SCHEMAS_NOTATION:
1039             case XML_SCHEMAS_QNAME:
1040                 if (value->value.qname.uri != NULL)
1041                     xmlFree(value->value.qname.uri);
1042                 if (value->value.qname.name != NULL)
1043                     xmlFree(value->value.qname.name);
1044                 break;
1045             case XML_SCHEMAS_HEXBINARY:
1046                 if (value->value.hex.str != NULL)
1047                     xmlFree(value->value.hex.str);
1048                 break;
1049             case XML_SCHEMAS_BASE64BINARY:
1050                 if (value->value.base64.str != NULL)
1051                     xmlFree(value->value.base64.str);
1052                 break;
1053             default:
1054                 break;
1055         }
1056         prev = value;
1057         value = value->next;
1058         xmlFree(prev);
1059     }
1060 }
1061
1062 /**
1063  * xmlSchemaGetPredefinedType:
1064  * @name: the type name
1065  * @ns:  the URI of the namespace usually "http://www.w3.org/2001/XMLSchema"
1066  *
1067  * Lookup a type in the default XML Schemas type library
1068  *
1069  * Returns the type if found, NULL otherwise
1070  */
1071 xmlSchemaTypePtr
1072 xmlSchemaGetPredefinedType(const xmlChar *name, const xmlChar *ns) {
1073     if (xmlSchemaTypesInitialized == 0)
1074         xmlSchemaInitTypes();
1075     if (name == NULL)
1076         return(NULL);
1077     return((xmlSchemaTypePtr) xmlHashLookup2(xmlSchemaTypesBank, name, ns));
1078 }
1079
1080 /**
1081  * xmlSchemaGetBuiltInListSimpleTypeItemType:
1082  * @type: the built-in simple type.
1083  *
1084  * Lookup function
1085  *
1086  * Returns the item type of @type as defined by the built-in datatype
1087  * hierarchy of XML Schema Part 2: Datatypes, or NULL in case of an error.
1088  */
1089 xmlSchemaTypePtr
1090 xmlSchemaGetBuiltInListSimpleTypeItemType(xmlSchemaTypePtr type)
1091 {
1092     if ((type == NULL) || (type->type != XML_SCHEMA_TYPE_BASIC))
1093         return (NULL);
1094     switch (type->builtInType) {
1095         case XML_SCHEMAS_NMTOKENS:
1096             return (xmlSchemaTypeNmtokenDef );
1097         case XML_SCHEMAS_IDREFS:
1098             return (xmlSchemaTypeIdrefDef);
1099         case XML_SCHEMAS_ENTITIES:
1100             return (xmlSchemaTypeEntityDef);
1101         default:
1102             return (NULL);
1103     }
1104 }
1105
1106 /****************************************************************
1107  *                                                              *
1108  *              Convenience macros and functions                *
1109  *                                                              *
1110  ****************************************************************/
1111
1112 #define IS_TZO_CHAR(c)                                          \
1113         ((c == 0) || (c == 'Z') || (c == '+') || (c == '-'))
1114
1115 #define VALID_YEAR(yr)          (yr != 0)
1116 #define VALID_MONTH(mon)        ((mon >= 1) && (mon <= 12))
1117 /* VALID_DAY should only be used when month is unknown */
1118 #define VALID_DAY(day)          ((day >= 1) && (day <= 31))
1119 #define VALID_HOUR(hr)          ((hr >= 0) && (hr <= 23))
1120 #define VALID_MIN(min)          ((min >= 0) && (min <= 59))
1121 #define VALID_SEC(sec)          ((sec >= 0) && (sec < 60))
1122 #define VALID_TZO(tzo)          ((tzo > -840) && (tzo < 840))
1123 #define IS_LEAP(y)                                              \
1124         (((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0))
1125
1126 static const unsigned int daysInMonth[12] =
1127         { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
1128 static const unsigned int daysInMonthLeap[12] =
1129         { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
1130
1131 #define MAX_DAYINMONTH(yr,mon)                                  \
1132         (IS_LEAP(yr) ? daysInMonthLeap[mon - 1] : daysInMonth[mon - 1])
1133
1134 #define VALID_MDAY(dt)                                          \
1135         (IS_LEAP(dt->year) ?                                    \
1136             (dt->day <= daysInMonthLeap[dt->mon - 1]) :         \
1137             (dt->day <= daysInMonth[dt->mon - 1]))
1138
1139 #define VALID_DATE(dt)                                          \
1140         (VALID_YEAR(dt->year) && VALID_MONTH(dt->mon) && VALID_MDAY(dt))
1141
1142 #define VALID_END_OF_DAY(dt)                                    \
1143         ((dt)->hour == 24 && (dt)->min == 0 && (dt)->sec == 0)
1144
1145 #define VALID_TIME(dt)                                          \
1146         (((VALID_HOUR(dt->hour) && VALID_MIN(dt->min) &&        \
1147           VALID_SEC(dt->sec)) || VALID_END_OF_DAY(dt)) &&       \
1148          VALID_TZO(dt->tzo))
1149
1150 #define VALID_DATETIME(dt)                                      \
1151         (VALID_DATE(dt) && VALID_TIME(dt))
1152
1153 #define SECS_PER_MIN            (60)
1154 #define SECS_PER_HOUR           (60 * SECS_PER_MIN)
1155 #define SECS_PER_DAY            (24 * SECS_PER_HOUR)
1156
1157 static const long dayInYearByMonth[12] =
1158         { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
1159 static const long dayInLeapYearByMonth[12] =
1160         { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 };
1161
1162 #define DAY_IN_YEAR(day, month, year)                           \
1163         ((IS_LEAP(year) ?                                       \
1164                 dayInLeapYearByMonth[month - 1] :               \
1165                 dayInYearByMonth[month - 1]) + day)
1166
1167 #ifdef DEBUG
1168 #define DEBUG_DATE(dt)                                                  \
1169     xmlGenericError(xmlGenericErrorContext,                             \
1170         "type=%o %04ld-%02u-%02uT%02u:%02u:%03f",                       \
1171         dt->type,dt->value.date.year,dt->value.date.mon,                \
1172         dt->value.date.day,dt->value.date.hour,dt->value.date.min,      \
1173         dt->value.date.sec);                                            \
1174     if (dt->value.date.tz_flag)                                         \
1175         if (dt->value.date.tzo != 0)                                    \
1176             xmlGenericError(xmlGenericErrorContext,                     \
1177                 "%+05d\n",dt->value.date.tzo);                          \
1178         else                                                            \
1179             xmlGenericError(xmlGenericErrorContext, "Z\n");             \
1180     else                                                                \
1181         xmlGenericError(xmlGenericErrorContext,"\n")
1182 #else
1183 #define DEBUG_DATE(dt)
1184 #endif
1185
1186 /**
1187  * _xmlSchemaParseGYear:
1188  * @dt:  pointer to a date structure
1189  * @str: pointer to the string to analyze
1190  *
1191  * Parses a xs:gYear without time zone and fills in the appropriate
1192  * field of the @dt structure. @str is updated to point just after the
1193  * xs:gYear. It is supposed that @dt->year is big enough to contain
1194  * the year.
1195  *
1196  * Returns 0 or the error code
1197  */
1198 static int
1199 _xmlSchemaParseGYear (xmlSchemaValDatePtr dt, const xmlChar **str) {
1200     const xmlChar *cur = *str, *firstChar;
1201     int isneg = 0, digcnt = 0;
1202
1203     if (((*cur < '0') || (*cur > '9')) &&
1204         (*cur != '-') && (*cur != '+'))
1205         return -1;
1206
1207     if (*cur == '-') {
1208         isneg = 1;
1209         cur++;
1210     }
1211
1212     firstChar = cur;
1213
1214     while ((*cur >= '0') && (*cur <= '9')) {
1215         dt->year = dt->year * 10 + (*cur - '0');
1216         cur++;
1217         digcnt++;
1218     }
1219
1220     /* year must be at least 4 digits (CCYY); over 4
1221      * digits cannot have a leading zero. */
1222     if ((digcnt < 4) || ((digcnt > 4) && (*firstChar == '0')))
1223         return 1;
1224
1225     if (isneg)
1226         dt->year = - dt->year;
1227
1228     if (!VALID_YEAR(dt->year))
1229         return 2;
1230
1231     *str = cur;
1232     return 0;
1233 }
1234
1235 /**
1236  * PARSE_2_DIGITS:
1237  * @num:  the integer to fill in
1238  * @cur:  an #xmlChar *
1239  * @invalid: an integer
1240  *
1241  * Parses a 2-digits integer and updates @num with the value. @cur is
1242  * updated to point just after the integer.
1243  * In case of error, @invalid is set to %TRUE, values of @num and
1244  * @cur are undefined.
1245  */
1246 #define PARSE_2_DIGITS(num, cur, invalid)                       \
1247         if ((cur[0] < '0') || (cur[0] > '9') ||                 \
1248             (cur[1] < '0') || (cur[1] > '9'))                   \
1249             invalid = 1;                                        \
1250         else                                                    \
1251             num = (cur[0] - '0') * 10 + (cur[1] - '0');         \
1252         cur += 2;
1253
1254 /**
1255  * PARSE_FLOAT:
1256  * @num:  the double to fill in
1257  * @cur:  an #xmlChar *
1258  * @invalid: an integer
1259  *
1260  * Parses a float and updates @num with the value. @cur is
1261  * updated to point just after the float. The float must have a
1262  * 2-digits integer part and may or may not have a decimal part.
1263  * In case of error, @invalid is set to %TRUE, values of @num and
1264  * @cur are undefined.
1265  */
1266 #define PARSE_FLOAT(num, cur, invalid)                          \
1267         PARSE_2_DIGITS(num, cur, invalid);                      \
1268         if (!invalid && (*cur == '.')) {                        \
1269             double mult = 1;                                    \
1270             cur++;                                              \
1271             if ((*cur < '0') || (*cur > '9'))                   \
1272                 invalid = 1;                                    \
1273             while ((*cur >= '0') && (*cur <= '9')) {            \
1274                 mult /= 10;                                     \
1275                 num += (*cur - '0') * mult;                     \
1276                 cur++;                                          \
1277             }                                                   \
1278         }
1279
1280 /**
1281  * _xmlSchemaParseGMonth:
1282  * @dt:  pointer to a date structure
1283  * @str: pointer to the string to analyze
1284  *
1285  * Parses a xs:gMonth without time zone and fills in the appropriate
1286  * field of the @dt structure. @str is updated to point just after the
1287  * xs:gMonth.
1288  *
1289  * Returns 0 or the error code
1290  */
1291 static int
1292 _xmlSchemaParseGMonth (xmlSchemaValDatePtr dt, const xmlChar **str) {
1293     const xmlChar *cur = *str;
1294     int ret = 0;
1295     unsigned int value = 0;
1296
1297     PARSE_2_DIGITS(value, cur, ret);
1298     if (ret != 0)
1299         return ret;
1300
1301     if (!VALID_MONTH(value))
1302         return 2;
1303
1304     dt->mon = value;
1305
1306     *str = cur;
1307     return 0;
1308 }
1309
1310 /**
1311  * _xmlSchemaParseGDay:
1312  * @dt:  pointer to a date structure
1313  * @str: pointer to the string to analyze
1314  *
1315  * Parses a xs:gDay without time zone and fills in the appropriate
1316  * field of the @dt structure. @str is updated to point just after the
1317  * xs:gDay.
1318  *
1319  * Returns 0 or the error code
1320  */
1321 static int
1322 _xmlSchemaParseGDay (xmlSchemaValDatePtr dt, const xmlChar **str) {
1323     const xmlChar *cur = *str;
1324     int ret = 0;
1325     unsigned int value = 0;
1326
1327     PARSE_2_DIGITS(value, cur, ret);
1328     if (ret != 0)
1329         return ret;
1330
1331     if (!VALID_DAY(value))
1332         return 2;
1333
1334     dt->day = value;
1335     *str = cur;
1336     return 0;
1337 }
1338
1339 /**
1340  * _xmlSchemaParseTime:
1341  * @dt:  pointer to a date structure
1342  * @str: pointer to the string to analyze
1343  *
1344  * Parses a xs:time without time zone and fills in the appropriate
1345  * fields of the @dt structure. @str is updated to point just after the
1346  * xs:time.
1347  * In case of error, values of @dt fields are undefined.
1348  *
1349  * Returns 0 or the error code
1350  */
1351 static int
1352 _xmlSchemaParseTime (xmlSchemaValDatePtr dt, const xmlChar **str) {
1353     const xmlChar *cur = *str;
1354     int ret = 0;
1355     int value = 0;
1356
1357     PARSE_2_DIGITS(value, cur, ret);
1358     if (ret != 0)
1359         return ret;
1360     if (*cur != ':')
1361         return 1;
1362     if (!VALID_HOUR(value) && value != 24 /* Allow end-of-day hour */)
1363         return 2;
1364     cur++;
1365
1366     /* the ':' insures this string is xs:time */
1367     dt->hour = value;
1368
1369     PARSE_2_DIGITS(value, cur, ret);
1370     if (ret != 0)
1371         return ret;
1372     if (!VALID_MIN(value))
1373         return 2;
1374     dt->min = value;
1375
1376     if (*cur != ':')
1377         return 1;
1378     cur++;
1379
1380     PARSE_FLOAT(dt->sec, cur, ret);
1381     if (ret != 0)
1382         return ret;
1383
1384     if (!VALID_TIME(dt))
1385         return 2;
1386
1387     *str = cur;
1388     return 0;
1389 }
1390
1391 /**
1392  * _xmlSchemaParseTimeZone:
1393  * @dt:  pointer to a date structure
1394  * @str: pointer to the string to analyze
1395  *
1396  * Parses a time zone without time zone and fills in the appropriate
1397  * field of the @dt structure. @str is updated to point just after the
1398  * time zone.
1399  *
1400  * Returns 0 or the error code
1401  */
1402 static int
1403 _xmlSchemaParseTimeZone (xmlSchemaValDatePtr dt, const xmlChar **str) {
1404     const xmlChar *cur;
1405     int ret = 0;
1406
1407     if (str == NULL)
1408         return -1;
1409     cur = *str;
1410
1411     switch (*cur) {
1412     case 0:
1413         dt->tz_flag = 0;
1414         dt->tzo = 0;
1415         break;
1416
1417     case 'Z':
1418         dt->tz_flag = 1;
1419         dt->tzo = 0;
1420         cur++;
1421         break;
1422
1423     case '+':
1424     case '-': {
1425         int isneg = 0, tmp = 0;
1426         isneg = (*cur == '-');
1427
1428         cur++;
1429
1430         PARSE_2_DIGITS(tmp, cur, ret);
1431         if (ret != 0)
1432             return ret;
1433         if (!VALID_HOUR(tmp))
1434             return 2;
1435
1436         if (*cur != ':')
1437             return 1;
1438         cur++;
1439
1440         dt->tzo = tmp * 60;
1441
1442         PARSE_2_DIGITS(tmp, cur, ret);
1443         if (ret != 0)
1444             return ret;
1445         if (!VALID_MIN(tmp))
1446             return 2;
1447
1448         dt->tzo += tmp;
1449         if (isneg)
1450             dt->tzo = - dt->tzo;
1451
1452         if (!VALID_TZO(dt->tzo))
1453             return 2;
1454
1455         dt->tz_flag = 1;
1456         break;
1457       }
1458     default:
1459         return 1;
1460     }
1461
1462     *str = cur;
1463     return 0;
1464 }
1465
1466 /**
1467  * _xmlSchemaBase64Decode:
1468  * @ch: a character
1469  *
1470  * Converts a base64 encoded character to its base 64 value.
1471  *
1472  * Returns 0-63 (value), 64 (pad), or -1 (not recognized)
1473  */
1474 static int
1475 _xmlSchemaBase64Decode (const xmlChar ch) {
1476     if (('A' <= ch) && (ch <= 'Z')) return ch - 'A';
1477     if (('a' <= ch) && (ch <= 'z')) return ch - 'a' + 26;
1478     if (('0' <= ch) && (ch <= '9')) return ch - '0' + 52;
1479     if ('+' == ch) return 62;
1480     if ('/' == ch) return 63;
1481     if ('=' == ch) return 64;
1482     return -1;
1483 }
1484
1485 /****************************************************************
1486  *                                                              *
1487  *      XML Schema Dates/Times Datatypes Handling               *
1488  *                                                              *
1489  ****************************************************************/
1490
1491 /**
1492  * PARSE_DIGITS:
1493  * @num:  the integer to fill in
1494  * @cur:  an #xmlChar *
1495  * @num_type: an integer flag
1496  *
1497  * Parses a digits integer and updates @num with the value. @cur is
1498  * updated to point just after the integer.
1499  * In case of error, @num_type is set to -1, values of @num and
1500  * @cur are undefined.
1501  */
1502 #define PARSE_DIGITS(num, cur, num_type)                        \
1503         if ((*cur < '0') || (*cur > '9'))                       \
1504             num_type = -1;                                      \
1505         else                                                    \
1506             while ((*cur >= '0') && (*cur <= '9')) {            \
1507                 num = num * 10 + (*cur - '0');                  \
1508                 cur++;                                          \
1509             }
1510
1511 /**
1512  * PARSE_NUM:
1513  * @num:  the double to fill in
1514  * @cur:  an #xmlChar *
1515  * @num_type: an integer flag
1516  *
1517  * Parses a float or integer and updates @num with the value. @cur is
1518  * updated to point just after the number. If the number is a float,
1519  * then it must have an integer part and a decimal part; @num_type will
1520  * be set to 1. If there is no decimal part, @num_type is set to zero.
1521  * In case of error, @num_type is set to -1, values of @num and
1522  * @cur are undefined.
1523  */
1524 #define PARSE_NUM(num, cur, num_type)                           \
1525         num = 0;                                                \
1526         PARSE_DIGITS(num, cur, num_type);                       \
1527         if (!num_type && (*cur == '.')) {                       \
1528             double mult = 1;                                    \
1529             cur++;                                              \
1530             if ((*cur < '0') || (*cur > '9'))                   \
1531                 num_type = -1;                                  \
1532             else                                                \
1533                 num_type = 1;                                   \
1534             while ((*cur >= '0') && (*cur <= '9')) {            \
1535                 mult /= 10;                                     \
1536                 num += (*cur - '0') * mult;                     \
1537                 cur++;                                          \
1538             }                                                   \
1539         }
1540
1541 /**
1542  * xmlSchemaValidateDates:
1543  * @type: the expected type or XML_SCHEMAS_UNKNOWN
1544  * @dateTime:  string to analyze
1545  * @val:  the return computed value
1546  *
1547  * Check that @dateTime conforms to the lexical space of one of the date types.
1548  * if true a value is computed and returned in @val.
1549  *
1550  * Returns 0 if this validates, a positive error code number otherwise
1551  *         and -1 in case of internal or API error.
1552  */
1553 static int
1554 xmlSchemaValidateDates (xmlSchemaValType type,
1555                         const xmlChar *dateTime, xmlSchemaValPtr *val,
1556                         int collapse) {
1557     xmlSchemaValPtr dt;
1558     int ret;
1559     const xmlChar *cur = dateTime;
1560
1561 #define RETURN_TYPE_IF_VALID(t)                                 \
1562     if (IS_TZO_CHAR(*cur)) {                                    \
1563         ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur); \
1564         if (ret == 0) {                                         \
1565             if (*cur != 0)                                      \
1566                 goto error;                                     \
1567             dt->type = t;                                       \
1568             goto done;                                          \
1569         }                                                       \
1570     }
1571
1572     if (dateTime == NULL)
1573         return -1;
1574
1575     if (collapse)
1576         while IS_WSP_BLANK_CH(*cur) cur++;
1577
1578     if ((*cur != '-') && (*cur < '0') && (*cur > '9'))
1579         return 1;
1580
1581     dt = xmlSchemaNewValue(XML_SCHEMAS_UNKNOWN);
1582     if (dt == NULL)
1583         return -1;
1584
1585     if ((cur[0] == '-') && (cur[1] == '-')) {
1586         /*
1587          * It's an incomplete date (xs:gMonthDay, xs:gMonth or
1588          * xs:gDay)
1589          */
1590         cur += 2;
1591
1592         /* is it an xs:gDay? */
1593         if (*cur == '-') {
1594             if (type == XML_SCHEMAS_GMONTH)
1595                 goto error;
1596           ++cur;
1597             ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
1598             if (ret != 0)
1599                 goto error;
1600
1601             RETURN_TYPE_IF_VALID(XML_SCHEMAS_GDAY);
1602
1603             goto error;
1604         }
1605
1606         /*
1607          * it should be an xs:gMonthDay or xs:gMonth
1608          */
1609         ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
1610         if (ret != 0)
1611             goto error;
1612
1613         /*
1614          * a '-' char could indicate this type is xs:gMonthDay or
1615          * a negative time zone offset. Check for xs:gMonthDay first.
1616          * Also the first three char's of a negative tzo (-MM:SS) can
1617          * appear to be a valid day; so even if the day portion
1618          * of the xs:gMonthDay verifies, we must insure it was not
1619          * a tzo.
1620          */
1621         if (*cur == '-') {
1622             const xmlChar *rewnd = cur;
1623             cur++;
1624
1625             ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
1626             if ((ret == 0) && ((*cur == 0) || (*cur != ':'))) {
1627
1628                 /*
1629                  * we can use the VALID_MDAY macro to validate the month
1630                  * and day because the leap year test will flag year zero
1631                  * as a leap year (even though zero is an invalid year).
1632                  * FUTURE TODO: Zero will become valid in XML Schema 1.1
1633                  * probably.
1634                  */
1635                 if (VALID_MDAY((&(dt->value.date)))) {
1636
1637                     RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTHDAY);
1638
1639                     goto error;
1640                 }
1641             }
1642
1643             /*
1644              * not xs:gMonthDay so rewind and check if just xs:gMonth
1645              * with an optional time zone.
1646              */
1647             cur = rewnd;
1648         }
1649
1650         RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTH);
1651
1652         goto error;
1653     }
1654
1655     /*
1656      * It's a right-truncated date or an xs:time.
1657      * Try to parse an xs:time then fallback on right-truncated dates.
1658      */
1659     if ((*cur >= '0') && (*cur <= '9')) {
1660         ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
1661         if (ret == 0) {
1662             /* it's an xs:time */
1663             RETURN_TYPE_IF_VALID(XML_SCHEMAS_TIME);
1664         }
1665     }
1666
1667     /* fallback on date parsing */
1668     cur = dateTime;
1669
1670     ret = _xmlSchemaParseGYear(&(dt->value.date), &cur);
1671     if (ret != 0)
1672         goto error;
1673
1674     /* is it an xs:gYear? */
1675     RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEAR);
1676
1677     if (*cur != '-')
1678         goto error;
1679     cur++;
1680
1681     ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
1682     if (ret != 0)
1683         goto error;
1684
1685     /* is it an xs:gYearMonth? */
1686     RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEARMONTH);
1687
1688     if (*cur != '-')
1689         goto error;
1690     cur++;
1691
1692     ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
1693     if ((ret != 0) || !VALID_DATE((&(dt->value.date))))
1694         goto error;
1695
1696     /* is it an xs:date? */
1697     RETURN_TYPE_IF_VALID(XML_SCHEMAS_DATE);
1698
1699     if (*cur != 'T')
1700         goto error;
1701     cur++;
1702
1703     /* it should be an xs:dateTime */
1704     ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
1705     if (ret != 0)
1706         goto error;
1707
1708     ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur);
1709     if (collapse)
1710         while IS_WSP_BLANK_CH(*cur) cur++;
1711     if ((ret != 0) || (*cur != 0) || (!(VALID_DATETIME((&(dt->value.date))))))
1712         goto error;
1713
1714
1715     dt->type = XML_SCHEMAS_DATETIME;
1716
1717 done:
1718 #if 1
1719     if ((type != XML_SCHEMAS_UNKNOWN) && (type != dt->type))
1720         goto error;
1721 #else
1722     /*
1723      * insure the parsed type is equal to or less significant (right
1724      * truncated) than the desired type.
1725      */
1726     if ((type != XML_SCHEMAS_UNKNOWN) && (type != dt->type)) {
1727
1728         /* time only matches time */
1729         if ((type == XML_SCHEMAS_TIME) && (dt->type == XML_SCHEMAS_TIME))
1730             goto error;
1731
1732         if ((type == XML_SCHEMAS_DATETIME) &&
1733             ((dt->type != XML_SCHEMAS_DATE) ||
1734              (dt->type != XML_SCHEMAS_GYEARMONTH) ||
1735              (dt->type != XML_SCHEMAS_GYEAR)))
1736             goto error;
1737
1738         if ((type == XML_SCHEMAS_DATE) &&
1739             ((dt->type != XML_SCHEMAS_GYEAR) ||
1740              (dt->type != XML_SCHEMAS_GYEARMONTH)))
1741             goto error;
1742
1743         if ((type == XML_SCHEMAS_GYEARMONTH) && (dt->type != XML_SCHEMAS_GYEAR))
1744             goto error;
1745
1746         if ((type == XML_SCHEMAS_GMONTHDAY) && (dt->type != XML_SCHEMAS_GMONTH))
1747             goto error;
1748     }
1749 #endif
1750
1751     if (val != NULL)
1752         *val = dt;
1753     else
1754         xmlSchemaFreeValue(dt);
1755
1756     return 0;
1757
1758 error:
1759     if (dt != NULL)
1760         xmlSchemaFreeValue(dt);
1761     return 1;
1762 }
1763
1764 /**
1765  * xmlSchemaValidateDuration:
1766  * @type: the predefined type
1767  * @duration:  string to analyze
1768  * @val:  the return computed value
1769  *
1770  * Check that @duration conforms to the lexical space of the duration type.
1771  * if true a value is computed and returned in @val.
1772  *
1773  * Returns 0 if this validates, a positive error code number otherwise
1774  *         and -1 in case of internal or API error.
1775  */
1776 static int
1777 xmlSchemaValidateDuration (xmlSchemaTypePtr type ATTRIBUTE_UNUSED,
1778                            const xmlChar *duration, xmlSchemaValPtr *val,
1779                            int collapse) {
1780     const xmlChar  *cur = duration;
1781     xmlSchemaValPtr dur;
1782     int isneg = 0;
1783     unsigned int seq = 0;
1784     double         num;
1785     int            num_type = 0;  /* -1 = invalid, 0 = int, 1 = floating */
1786     const xmlChar  desig[]  = {'Y', 'M', 'D', 'H', 'M', 'S'};
1787     const double   multi[]  = { 0.0, 0.0, 86400.0, 3600.0, 60.0, 1.0, 0.0};
1788
1789     if (duration == NULL)
1790         return -1;
1791
1792     if (collapse)
1793         while IS_WSP_BLANK_CH(*cur) cur++;
1794
1795     if (*cur == '-') {
1796         isneg = 1;
1797         cur++;
1798     }
1799
1800     /* duration must start with 'P' (after sign) */
1801     if (*cur++ != 'P')
1802         return 1;
1803
1804     if (*cur == 0)
1805         return 1;
1806
1807     dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
1808     if (dur == NULL)
1809         return -1;
1810
1811     while (*cur != 0) {
1812
1813         /* input string should be empty or invalid date/time item */
1814         if (seq >= sizeof(desig))
1815             goto error;
1816
1817         /* T designator must be present for time items */
1818         if (*cur == 'T') {
1819             if (seq <= 3) {
1820                 seq = 3;
1821                 cur++;
1822             } else
1823                 return 1;
1824         } else if (seq == 3)
1825             goto error;
1826
1827         /* parse the number portion of the item */
1828         PARSE_NUM(num, cur, num_type);
1829
1830         if ((num_type == -1) || (*cur == 0))
1831             goto error;
1832
1833         /* update duration based on item type */
1834         while (seq < sizeof(desig)) {
1835             if (*cur == desig[seq]) {
1836
1837                 /* verify numeric type; only seconds can be float */
1838                 if ((num_type != 0) && (seq < (sizeof(desig)-1)))
1839                     goto error;
1840
1841                 switch (seq) {
1842                     case 0:
1843                         dur->value.dur.mon = (long)num * 12;
1844                         break;
1845                     case 1:
1846                         dur->value.dur.mon += (long)num;
1847                         break;
1848                     default:
1849                         /* convert to seconds using multiplier */
1850                         dur->value.dur.sec += num * multi[seq];
1851                         seq++;
1852                         break;
1853                 }
1854
1855                 break;          /* exit loop */
1856             }
1857             /* no date designators found? */
1858             if ((++seq == 3) || (seq == 6))
1859                 goto error;
1860         }
1861         cur++;
1862         if (collapse)
1863             while IS_WSP_BLANK_CH(*cur) cur++;
1864     }
1865
1866     if (isneg) {
1867         dur->value.dur.mon = -dur->value.dur.mon;
1868         dur->value.dur.day = -dur->value.dur.day;
1869         dur->value.dur.sec = -dur->value.dur.sec;
1870     }
1871
1872     if (val != NULL)
1873         *val = dur;
1874     else
1875         xmlSchemaFreeValue(dur);
1876
1877     return 0;
1878
1879 error:
1880     if (dur != NULL)
1881         xmlSchemaFreeValue(dur);
1882     return 1;
1883 }
1884
1885 /**
1886  * xmlSchemaStrip:
1887  * @value: a value
1888  *
1889  * Removes the leading and ending spaces of a string
1890  *
1891  * Returns the new string or NULL if no change was required.
1892  */
1893 static xmlChar *
1894 xmlSchemaStrip(const xmlChar *value) {
1895     const xmlChar *start = value, *end, *f;
1896
1897     if (value == NULL) return(NULL);
1898     while ((*start != 0) && (IS_BLANK_CH(*start))) start++;
1899     end = start;
1900     while (*end != 0) end++;
1901     f = end;
1902     end--;
1903     while ((end > start) && (IS_BLANK_CH(*end))) end--;
1904     end++;
1905     if ((start == value) && (f == end)) return(NULL);
1906     return(xmlStrndup(start, end - start));
1907 }
1908
1909 /**
1910  * xmlSchemaWhiteSpaceReplace:
1911  * @value: a value
1912  *
1913  * Replaces 0xd, 0x9 and 0xa with a space.
1914  *
1915  * Returns the new string or NULL if no change was required.
1916  */
1917 xmlChar *
1918 xmlSchemaWhiteSpaceReplace(const xmlChar *value) {
1919     const xmlChar *cur = value;
1920     xmlChar *ret = NULL, *mcur;
1921
1922     if (value == NULL)
1923         return(NULL);
1924
1925     while ((*cur != 0) &&
1926         (((*cur) != 0xd) && ((*cur) != 0x9) && ((*cur) != 0xa))) {
1927         cur++;
1928     }
1929     if (*cur == 0)
1930         return (NULL);
1931     ret = xmlStrdup(value);
1932     /* TODO FIXME: I guess gcc will bark at this. */
1933     mcur = (xmlChar *)  (ret + (cur - value));
1934     do {
1935         if ( ((*mcur) == 0xd) || ((*mcur) == 0x9) || ((*mcur) == 0xa) )
1936             *mcur = ' ';
1937         mcur++;
1938     } while (*mcur != 0);
1939     return(ret);
1940 }
1941
1942 /**
1943  * xmlSchemaCollapseString:
1944  * @value: a value
1945  *
1946  * Removes and normalize white spaces in the string
1947  *
1948  * Returns the new string or NULL if no change was required.
1949  */
1950 xmlChar *
1951 xmlSchemaCollapseString(const xmlChar *value) {
1952     const xmlChar *start = value, *end, *f;
1953     xmlChar *g;
1954     int col = 0;
1955
1956     if (value == NULL) return(NULL);
1957     while ((*start != 0) && (IS_BLANK_CH(*start))) start++;
1958     end = start;
1959     while (*end != 0) {
1960         if ((*end == ' ') && (IS_BLANK_CH(end[1]))) {
1961             col = end - start;
1962             break;
1963         } else if ((*end == 0xa) || (*end == 0x9) || (*end == 0xd)) {
1964             col = end - start;
1965             break;
1966         }
1967         end++;
1968     }
1969     if (col == 0) {
1970         f = end;
1971         end--;
1972         while ((end > start) && (IS_BLANK_CH(*end))) end--;
1973         end++;
1974         if ((start == value) && (f == end)) return(NULL);
1975         return(xmlStrndup(start, end - start));
1976     }
1977     start = xmlStrdup(start);
1978     if (start == NULL) return(NULL);
1979     g = (xmlChar *) (start + col);
1980     end = g;
1981     while (*end != 0) {
1982         if (IS_BLANK_CH(*end)) {
1983             end++;
1984             while (IS_BLANK_CH(*end)) end++;
1985             if (*end != 0)
1986                 *g++ = ' ';
1987         } else
1988             *g++ = *end++;
1989     }
1990     *g = 0;
1991     return((xmlChar *) start);
1992 }
1993
1994 /**
1995  * xmlSchemaValAtomicListNode:
1996  * @type: the predefined atomic type for a token in the list
1997  * @value: the list value to check
1998  * @ret:  the return computed value
1999  * @node:  the node containing the value
2000  *
2001  * Check that a value conforms to the lexical space of the predefined
2002  * list type. if true a value is computed and returned in @ret.
2003  *
2004  * Returns the number of items if this validates, a negative error code
2005  *         number otherwise
2006  */
2007 static int
2008 xmlSchemaValAtomicListNode(xmlSchemaTypePtr type, const xmlChar *value,
2009                            xmlSchemaValPtr *ret, xmlNodePtr node) {
2010     xmlChar *val, *cur, *endval;
2011     int nb_values = 0;
2012     int tmp = 0;
2013
2014     if (value == NULL) {
2015         return(-1);
2016     }
2017     val = xmlStrdup(value);
2018     if (val == NULL) {
2019         return(-1);
2020     }
2021     if (ret != NULL) {
2022         *ret = NULL;
2023     }
2024     cur = val;
2025     /*
2026      * Split the list
2027      */
2028     while (IS_BLANK_CH(*cur)) *cur++ = 0;
2029     while (*cur != 0) {
2030         if (IS_BLANK_CH(*cur)) {
2031             *cur = 0;
2032             cur++;
2033             while (IS_BLANK_CH(*cur)) *cur++ = 0;
2034         } else {
2035             nb_values++;
2036             cur++;
2037             while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
2038         }
2039     }
2040     if (nb_values == 0) {
2041         xmlFree(val);
2042         return(nb_values);
2043     }
2044     endval = cur;
2045     cur = val;
2046     while ((*cur == 0) && (cur != endval)) cur++;
2047     while (cur != endval) {
2048         tmp = xmlSchemaValPredefTypeNode(type, cur, NULL, node);
2049         if (tmp != 0)
2050             break;
2051         while (*cur != 0) cur++;
2052         while ((*cur == 0) && (cur != endval)) cur++;
2053     }
2054     /* TODO what return value ? c.f. bug #158628
2055     if (ret != NULL) {
2056         TODO
2057     } */
2058     xmlFree(val);
2059     if (tmp == 0)
2060         return(nb_values);
2061     return(-1);
2062 }
2063
2064 /**
2065  * xmlSchemaParseUInt:
2066  * @str: pointer to the string R/W
2067  * @llo: pointer to the low result
2068  * @lmi: pointer to the mid result
2069  * @lhi: pointer to the high result
2070  *
2071  * Parse an unsigned long into 3 fields.
2072  *
2073  * Returns the number of significant digits in the number or
2074  * -1 if overflow of the capacity and -2 if it's not a number.
2075  */
2076 static int
2077 xmlSchemaParseUInt(const xmlChar **str, unsigned long *llo,
2078                    unsigned long *lmi, unsigned long *lhi) {
2079     unsigned long lo = 0, mi = 0, hi = 0;
2080     const xmlChar *tmp, *cur = *str;
2081     int ret = 0, i = 0;
2082
2083     if (!((*cur >= '0') && (*cur <= '9')))
2084         return(-2);
2085
2086     while (*cur == '0') {        /* ignore leading zeroes */
2087         cur++;
2088     }
2089     tmp = cur;
2090     while ((*tmp != 0) && (*tmp >= '0') && (*tmp <= '9')) {
2091         i++;tmp++;ret++;
2092     }
2093     if (i > 24) {
2094         *str = tmp;
2095         return(-1);
2096     }
2097     while (i > 16) {
2098         hi = hi * 10 + (*cur++ - '0');
2099         i--;
2100     }
2101     while (i > 8) {
2102         mi = mi * 10 + (*cur++ - '0');
2103         i--;
2104     }
2105     while (i > 0) {
2106         lo = lo * 10 + (*cur++ - '0');
2107         i--;
2108     }
2109
2110     *str = cur;
2111     *llo = lo;
2112     *lmi = mi;
2113     *lhi = hi;
2114     return(ret);
2115 }
2116
2117 /**
2118  * xmlSchemaValAtomicType:
2119  * @type: the predefined type
2120  * @value: the value to check
2121  * @val:  the return computed value
2122  * @node:  the node containing the value
2123  * flags:  flags to control the vlidation
2124  *
2125  * Check that a value conforms to the lexical space of the atomic type.
2126  * if true a value is computed and returned in @val.
2127  * This checks the value space for list types as well (IDREFS, NMTOKENS).
2128  *
2129  * Returns 0 if this validates, a positive error code number otherwise
2130  *         and -1 in case of internal or API error.
2131  */
2132 static int
2133 xmlSchemaValAtomicType(xmlSchemaTypePtr type, const xmlChar * value,
2134                        xmlSchemaValPtr * val, xmlNodePtr node, int flags,
2135                        xmlSchemaWhitespaceValueType ws,
2136                        int normOnTheFly, int applyNorm, int createStringValue)
2137 {
2138     xmlSchemaValPtr v;
2139     xmlChar *norm = NULL;
2140     int ret = 0;
2141
2142     if (xmlSchemaTypesInitialized == 0)
2143         xmlSchemaInitTypes();
2144     if (type == NULL)
2145         return (-1);
2146
2147     /*
2148      * validating a non existant text node is similar to validating
2149      * an empty one.
2150      */
2151     if (value == NULL)
2152         value = BAD_CAST "";
2153
2154     if (val != NULL)
2155         *val = NULL;
2156     if ((flags == 0) && (value != NULL)) {
2157
2158         if ((type->builtInType != XML_SCHEMAS_STRING) &&
2159           (type->builtInType != XML_SCHEMAS_ANYTYPE) &&
2160           (type->builtInType != XML_SCHEMAS_ANYSIMPLETYPE)) {
2161             if (type->builtInType == XML_SCHEMAS_NORMSTRING)
2162                 norm = xmlSchemaWhiteSpaceReplace(value);
2163             else
2164                 norm = xmlSchemaCollapseString(value);
2165             if (norm != NULL)
2166                 value = norm;
2167         }
2168     }
2169
2170     switch (type->builtInType) {
2171         case XML_SCHEMAS_UNKNOWN:
2172             goto error;
2173         case XML_SCHEMAS_ANYTYPE:
2174         case XML_SCHEMAS_ANYSIMPLETYPE:
2175             if ((createStringValue) && (val != NULL)) {
2176                 v = xmlSchemaNewValue(XML_SCHEMAS_ANYSIMPLETYPE);
2177                 if (v != NULL) {
2178                     v->value.str = xmlStrdup(value);
2179                     *val = v;
2180                 } else {
2181                     goto error;
2182                 }
2183             }
2184             goto return0;
2185         case XML_SCHEMAS_STRING:
2186             if (! normOnTheFly) {
2187                 const xmlChar *cur = value;
2188
2189                 if (ws == XML_SCHEMA_WHITESPACE_REPLACE) {
2190                     while (*cur != 0) {
2191                         if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) {
2192                             goto return1;
2193                         } else {
2194                             cur++;
2195                         }
2196                     }
2197                 } else if (ws == XML_SCHEMA_WHITESPACE_COLLAPSE) {
2198                     while (*cur != 0) {
2199                         if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) {
2200                             goto return1;
2201                         } else if IS_WSP_SPACE_CH(*cur) {
2202                             cur++;
2203                             if IS_WSP_SPACE_CH(*cur)
2204                                 goto return1;
2205                         } else {
2206                             cur++;
2207                         }
2208                     }
2209                 }
2210             }
2211             if (createStringValue && (val != NULL)) {
2212                 if (applyNorm) {
2213                     if (ws == XML_SCHEMA_WHITESPACE_COLLAPSE)
2214                         norm = xmlSchemaCollapseString(value);
2215                     else if (ws == XML_SCHEMA_WHITESPACE_REPLACE)
2216                         norm = xmlSchemaWhiteSpaceReplace(value);
2217                     if (norm != NULL)
2218                         value = norm;
2219                 }
2220                 v = xmlSchemaNewValue(XML_SCHEMAS_STRING);
2221                 if (v != NULL) {
2222                     v->value.str = xmlStrdup(value);
2223                     *val = v;
2224                 } else {
2225                     goto error;
2226                 }
2227             }
2228             goto return0;
2229         case XML_SCHEMAS_NORMSTRING:{
2230                 if (normOnTheFly) {
2231                     if (applyNorm) {
2232                         if (ws == XML_SCHEMA_WHITESPACE_COLLAPSE)
2233                             norm = xmlSchemaCollapseString(value);
2234                         else
2235                             norm = xmlSchemaWhiteSpaceReplace(value);
2236                         if (norm != NULL)
2237                             value = norm;
2238                     }
2239                 } else {
2240                     const xmlChar *cur = value;
2241                     while (*cur != 0) {
2242                         if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) {
2243                             goto return1;
2244                         } else {
2245                             cur++;
2246                         }
2247                     }
2248                 }
2249                 if (val != NULL) {
2250                     v = xmlSchemaNewValue(XML_SCHEMAS_NORMSTRING);
2251                     if (v != NULL) {
2252                         v->value.str = xmlStrdup(value);
2253                         *val = v;
2254                     } else {
2255                         goto error;
2256                     }
2257                 }
2258                 goto return0;
2259             }
2260         case XML_SCHEMAS_DECIMAL:{
2261                 const xmlChar *cur = value;
2262                 unsigned int len, neg, integ, hasLeadingZeroes;
2263                 xmlChar cval[25];
2264                 xmlChar *cptr = cval;
2265
2266                 if ((cur == NULL) || (*cur == 0))
2267                     goto return1;
2268
2269                 /*
2270                 * xs:decimal has a whitespace-facet value of 'collapse'.
2271                 */
2272                 if (normOnTheFly)
2273                     while IS_WSP_BLANK_CH(*cur) cur++;
2274
2275                 /*
2276                 * First we handle an optional sign.
2277                 */
2278                 neg = 0;
2279                 if (*cur == '-') {
2280                     neg = 1;
2281                     cur++;
2282                 } else if (*cur == '+')
2283                     cur++;
2284                 /*
2285                 * Disallow: "", "-", "- "
2286                 */
2287                 if (*cur == 0)
2288                     goto return1;
2289                 /*
2290                  * Next we "pre-parse" the number, in preparation for calling
2291                  * the common routine xmlSchemaParseUInt.  We get rid of any
2292                  * leading zeroes (because we have reserved only 25 chars),
2293                  * and note the position of a decimal point.
2294                  */
2295                 len = 0;
2296                 integ = ~0u;
2297                 hasLeadingZeroes = 0;
2298                 /*
2299                 * Skip leading zeroes.
2300                 */
2301                 while (*cur == '0') {
2302                     cur++;
2303                     hasLeadingZeroes = 1;
2304                 }
2305                 if (*cur != 0) {
2306                     do {
2307                         if ((*cur >= '0') && (*cur <= '9')) {
2308                             *cptr++ = *cur++;
2309                             len++;
2310                         } else if (*cur == '.') {
2311                             cur++;
2312                             integ = len;
2313                             do {
2314                                 if ((*cur >= '0') && (*cur <= '9')) {
2315                                     *cptr++ = *cur++;
2316                                     len++;
2317                                 } else
2318                                     break;
2319                             } while (len < 24);
2320                             /*
2321                             * Disallow "." but allow "00."
2322                             */
2323                             if ((len == 0) && (!hasLeadingZeroes))
2324                                 goto return1;
2325                             break;
2326                         } else
2327                             break;
2328                     } while (len < 24);
2329                 }
2330                 if (normOnTheFly)
2331                     while IS_WSP_BLANK_CH(*cur) cur++;
2332                 if (*cur != 0)
2333                     goto return1; /* error if any extraneous chars */
2334                 if (val != NULL) {
2335                     v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
2336                     if (v != NULL) {
2337                         /*
2338                         * Now evaluate the significant digits of the number
2339                         */
2340                         if (len != 0) {
2341
2342                             if (integ != ~0u) {
2343                                 /*
2344                                 * Get rid of trailing zeroes in the
2345                                 * fractional part.
2346                                 */
2347                                 while ((len != integ) && (*(cptr-1) == '0')) {
2348                                     cptr--;
2349                                     len--;
2350                                 }
2351                             }
2352                             /*
2353                             * Terminate the (preparsed) string.
2354                             */
2355                             if (len != 0) {
2356                                 *cptr = 0;
2357                                 cptr = cval;
2358
2359                                 xmlSchemaParseUInt((const xmlChar **)&cptr,
2360                                     &v->value.decimal.lo,
2361                                     &v->value.decimal.mi,
2362                                     &v->value.decimal.hi);
2363                             }
2364                         }
2365                         /*
2366                         * Set the total digits to 1 if a zero value.
2367                         */
2368                         v->value.decimal.sign = neg;
2369                         if (len == 0) {
2370                             /* Speedup for zero values. */
2371                             v->value.decimal.total = 1;
2372                         } else {
2373                             v->value.decimal.total = len;
2374                             if (integ == ~0u)
2375                                 v->value.decimal.frac = 0;
2376                             else
2377                                 v->value.decimal.frac = len - integ;
2378                         }
2379                         *val = v;
2380                     }
2381                 }
2382                 goto return0;
2383             }
2384         case XML_SCHEMAS_TIME:
2385         case XML_SCHEMAS_GDAY:
2386         case XML_SCHEMAS_GMONTH:
2387         case XML_SCHEMAS_GMONTHDAY:
2388         case XML_SCHEMAS_GYEAR:
2389         case XML_SCHEMAS_GYEARMONTH:
2390         case XML_SCHEMAS_DATE:
2391         case XML_SCHEMAS_DATETIME:
2392             ret = xmlSchemaValidateDates(type->builtInType, value, val,
2393                 normOnTheFly);
2394             break;
2395         case XML_SCHEMAS_DURATION:
2396             ret = xmlSchemaValidateDuration(type, value, val,
2397                 normOnTheFly);
2398             break;
2399         case XML_SCHEMAS_FLOAT:
2400         case XML_SCHEMAS_DOUBLE: {
2401                 const xmlChar *cur = value;
2402                 int neg = 0;
2403                 int digits_before = 0;
2404                 int digits_after = 0;
2405
2406                 if (normOnTheFly)
2407                     while IS_WSP_BLANK_CH(*cur) cur++;
2408
2409                 if ((cur[0] == 'N') && (cur[1] == 'a') && (cur[2] == 'N')) {
2410                     cur += 3;
2411                     if (*cur != 0)
2412                         goto return1;
2413                     if (val != NULL) {
2414                         if (type == xmlSchemaTypeFloatDef) {
2415                             v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
2416                             if (v != NULL) {
2417                                 v->value.f = (float) xmlXPathNAN;
2418                             } else {
2419                                 xmlSchemaFreeValue(v);
2420                                 goto error;
2421                             }
2422                         } else {
2423                             v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
2424                             if (v != NULL) {
2425                                 v->value.d = xmlXPathNAN;
2426                             } else {
2427                                 xmlSchemaFreeValue(v);
2428                                 goto error;
2429                             }
2430                         }
2431                         *val = v;
2432                     }
2433                     goto return0;
2434                 }
2435                 if (*cur == '-') {
2436                     neg = 1;
2437                     cur++;
2438                 }
2439                 if ((cur[0] == 'I') && (cur[1] == 'N') && (cur[2] == 'F')) {
2440                     cur += 3;
2441                     if (*cur != 0)
2442                         goto return1;
2443                     if (val != NULL) {
2444                         if (type == xmlSchemaTypeFloatDef) {
2445                             v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
2446                             if (v != NULL) {
2447                                 if (neg)
2448                                     v->value.f = (float) xmlXPathNINF;
2449                                 else
2450                                     v->value.f = (float) xmlXPathPINF;
2451                             } else {
2452                                 xmlSchemaFreeValue(v);
2453                                 goto error;
2454                             }
2455                         } else {
2456                             v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
2457                             if (v != NULL) {
2458                                 if (neg)
2459                                     v->value.d = xmlXPathNINF;
2460                                 else
2461                                     v->value.d = xmlXPathPINF;
2462                             } else {
2463                                 xmlSchemaFreeValue(v);
2464                                 goto error;
2465                             }
2466                         }
2467                         *val = v;
2468                     }
2469                     goto return0;
2470                 }
2471                 if ((neg == 0) && (*cur == '+'))
2472                     cur++;
2473                 if ((cur[0] == 0) || (cur[0] == '+') || (cur[0] == '-'))
2474                     goto return1;
2475                 while ((*cur >= '0') && (*cur <= '9')) {
2476                     cur++;
2477                     digits_before++;
2478                 }
2479                 if (*cur == '.') {
2480                     cur++;
2481                     while ((*cur >= '0') && (*cur <= '9')) {
2482                         cur++;
2483                         digits_after++;
2484                     }
2485                 }
2486                 if ((digits_before == 0) && (digits_after == 0))
2487                     goto return1;
2488                 if ((*cur == 'e') || (*cur == 'E')) {
2489                     cur++;
2490                     if ((*cur == '-') || (*cur == '+'))
2491                         cur++;
2492                     while ((*cur >= '0') && (*cur <= '9'))
2493                         cur++;
2494                 }
2495                 if (normOnTheFly)
2496                     while IS_WSP_BLANK_CH(*cur) cur++;
2497
2498                 if (*cur != 0)
2499                     goto return1;
2500                 if (val != NULL) {
2501                     if (type == xmlSchemaTypeFloatDef) {
2502                         v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
2503                         if (v != NULL) {
2504                             /*
2505                             * TODO: sscanf seems not to give the correct
2506                             * value for extremely high/low values.
2507                             * E.g. "1E-149" results in zero.
2508                             */
2509                             if (sscanf((const char *) value, "%f",
2510                                  &(v->value.f)) == 1) {
2511                                 *val = v;
2512                             } else {
2513                                 xmlSchemaFreeValue(v);
2514                                 goto return1;
2515                             }
2516                         } else {
2517                             goto error;
2518                         }
2519                     } else {
2520                         v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
2521                         if (v != NULL) {
2522                             /*
2523                             * TODO: sscanf seems not to give the correct
2524                             * value for extremely high/low values.
2525                             */
2526                             if (sscanf((const char *) value, "%lf",
2527                                  &(v->value.d)) == 1) {
2528                                 *val = v;
2529                             } else {
2530                                 xmlSchemaFreeValue(v);
2531                                 goto return1;
2532                             }
2533                         } else {
2534                             goto error;
2535                         }
2536                     }
2537                 }
2538                 goto return0;
2539             }
2540         case XML_SCHEMAS_BOOLEAN:{
2541                 const xmlChar *cur = value;
2542
2543                 if (normOnTheFly) {
2544                     while IS_WSP_BLANK_CH(*cur) cur++;
2545                     if (*cur == '0') {
2546                         ret = 0;
2547                         cur++;
2548                     } else if (*cur == '1') {
2549                         ret = 1;
2550                         cur++;
2551                     } else if (*cur == 't') {
2552                         cur++;
2553                         if ((*cur++ == 'r') && (*cur++ == 'u') &&
2554                             (*cur++ == 'e')) {
2555                             ret = 1;
2556                         } else
2557                             goto return1;
2558                     } else if (*cur == 'f') {
2559                         cur++;
2560                         if ((*cur++ == 'a') && (*cur++ == 'l') &&
2561                             (*cur++ == 's') && (*cur++ == 'e')) {
2562                             ret = 0;
2563                         } else
2564                             goto return1;
2565                     } else
2566                         goto return1;
2567                     if (*cur != 0) {
2568                         while IS_WSP_BLANK_CH(*cur) cur++;
2569                         if (*cur != 0)
2570                             goto return1;
2571                     }
2572                 } else {
2573                     if ((cur[0] == '0') && (cur[1] == 0))
2574                         ret = 0;
2575                     else if ((cur[0] == '1') && (cur[1] == 0))
2576                         ret = 1;
2577                     else if ((cur[0] == 't') && (cur[1] == 'r')
2578                         && (cur[2] == 'u') && (cur[3] == 'e')
2579                         && (cur[4] == 0))
2580                         ret = 1;
2581                     else if ((cur[0] == 'f') && (cur[1] == 'a')
2582                         && (cur[2] == 'l') && (cur[3] == 's')
2583                         && (cur[4] == 'e') && (cur[5] == 0))
2584                         ret = 0;
2585                     else
2586                         goto return1;
2587                 }
2588                 if (val != NULL) {
2589                     v = xmlSchemaNewValue(XML_SCHEMAS_BOOLEAN);
2590                     if (v != NULL) {
2591                         v->value.b = ret;
2592                         *val = v;
2593                     } else {
2594                         goto error;
2595                     }
2596                 }
2597                 goto return0;
2598             }
2599         case XML_SCHEMAS_TOKEN:{
2600                 const xmlChar *cur = value;
2601
2602                 if (! normOnTheFly) {
2603                     while (*cur != 0) {
2604                         if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) {
2605                             goto return1;
2606                         } else if (*cur == ' ') {
2607                             cur++;
2608                             if (*cur == 0)
2609                                 goto return1;
2610                             if (*cur == ' ')
2611                                 goto return1;
2612                         } else {
2613                             cur++;
2614                         }
2615                     }
2616                 }
2617                 if (val != NULL) {
2618                     v = xmlSchemaNewValue(XML_SCHEMAS_TOKEN);
2619                     if (v != NULL) {
2620                         v->value.str = xmlStrdup(value);
2621                         *val = v;
2622                     } else {
2623                         goto error;
2624                     }
2625                 }
2626                 goto return0;
2627             }
2628         case XML_SCHEMAS_LANGUAGE:
2629             if (normOnTheFly) {
2630                 norm = xmlSchemaCollapseString(value);
2631                 if (norm != NULL)
2632                     value = norm;
2633             }
2634             if (xmlCheckLanguageID(value) == 1) {
2635                 if (val != NULL) {
2636                     v = xmlSchemaNewValue(XML_SCHEMAS_LANGUAGE);
2637                     if (v != NULL) {
2638                         v->value.str = xmlStrdup(value);
2639                         *val = v;
2640                     } else {
2641                         goto error;
2642                     }
2643                 }
2644                 goto return0;
2645             }
2646             goto return1;
2647         case XML_SCHEMAS_NMTOKEN:
2648             if (xmlValidateNMToken(value, 1) == 0) {
2649                 if (val != NULL) {
2650                     v = xmlSchemaNewValue(XML_SCHEMAS_NMTOKEN);
2651                     if (v != NULL) {
2652                         v->value.str = xmlStrdup(value);
2653                         *val = v;
2654                     } else {
2655                         goto error;
2656                     }
2657                 }
2658                 goto return0;
2659             }
2660             goto return1;
2661         case XML_SCHEMAS_NMTOKENS:
2662             ret = xmlSchemaValAtomicListNode(xmlSchemaTypeNmtokenDef,
2663                                              value, val, node);
2664             if (ret > 0)
2665                 ret = 0;
2666             else
2667                 ret = 1;
2668             goto done;
2669         case XML_SCHEMAS_NAME:
2670             ret = xmlValidateName(value, 1);
2671             if ((ret == 0) && (val != NULL) && (value != NULL)) {
2672                 v = xmlSchemaNewValue(XML_SCHEMAS_NAME);
2673                 if (v != NULL) {
2674                      const xmlChar *start = value, *end;
2675                      while (IS_BLANK_CH(*start)) start++;
2676                      end = start;
2677                      while ((*end != 0) && (!IS_BLANK_CH(*end))) end++;
2678                      v->value.str = xmlStrndup(start, end - start);
2679                     *val = v;
2680                 } else {
2681                     goto error;
2682                 }
2683             }
2684             goto done;
2685         case XML_SCHEMAS_QNAME:{
2686                 const xmlChar *uri = NULL;
2687                 xmlChar *local = NULL;
2688
2689                 ret = xmlValidateQName(value, 1);
2690                 if (ret != 0)
2691                     goto done;
2692                 if (node != NULL) {
2693                     xmlChar *prefix;
2694                     xmlNsPtr ns;
2695
2696                     local = xmlSplitQName2(value, &prefix);
2697                     ns = xmlSearchNs(node->doc, node, prefix);
2698                     if ((ns == NULL) && (prefix != NULL)) {
2699                         xmlFree(prefix);
2700                         if (local != NULL)
2701                             xmlFree(local);
2702                         goto return1;
2703                     }
2704                     if (ns != NULL)
2705                         uri = ns->href;
2706                     if (prefix != NULL)
2707                         xmlFree(prefix);
2708                 }
2709                 if (val != NULL) {
2710                     v = xmlSchemaNewValue(XML_SCHEMAS_QNAME);
2711                     if (v == NULL) {
2712                         if (local != NULL)
2713                             xmlFree(local);
2714                         goto error;
2715                     }
2716                     if (local != NULL)
2717                         v->value.qname.name = local;
2718                     else
2719                         v->value.qname.name = xmlStrdup(value);
2720                     if (uri != NULL)
2721                         v->value.qname.uri = xmlStrdup(uri);
2722                     *val = v;
2723                 } else
2724                     if (local != NULL)
2725                         xmlFree(local);
2726                 goto done;
2727             }
2728         case XML_SCHEMAS_NCNAME:
2729             ret = xmlValidateNCName(value, 1);
2730             if ((ret == 0) && (val != NULL)) {
2731                 v = xmlSchemaNewValue(XML_SCHEMAS_NCNAME);
2732                 if (v != NULL) {
2733                     v->value.str = xmlStrdup(value);
2734                     *val = v;
2735                 } else {
2736                     goto error;
2737                 }
2738             }
2739             goto done;
2740         case XML_SCHEMAS_ID:
2741             ret = xmlValidateNCName(value, 1);
2742             if ((ret == 0) && (val != NULL)) {
2743                 v = xmlSchemaNewValue(XML_SCHEMAS_ID);
2744                 if (v != NULL) {
2745                     v->value.str = xmlStrdup(value);
2746                     *val = v;
2747                 } else {
2748                     goto error;
2749                 }
2750             }
2751             if ((ret == 0) && (node != NULL) &&
2752                 (node->type == XML_ATTRIBUTE_NODE)) {
2753                 xmlAttrPtr attr = (xmlAttrPtr) node;
2754
2755                 /*
2756                  * NOTE: the IDness might have already be declared in the DTD
2757                  */
2758                 if (attr->atype != XML_ATTRIBUTE_ID) {
2759                     xmlIDPtr res;
2760                     xmlChar *strip;
2761
2762                     strip = xmlSchemaStrip(value);
2763                     if (strip != NULL) {
2764                         res = xmlAddID(NULL, node->doc, strip, attr);
2765                         xmlFree(strip);
2766                     } else
2767                         res = xmlAddID(NULL, node->doc, value, attr);
2768                     if (res == NULL) {
2769                         ret = 2;
2770                     } else {
2771                         attr->atype = XML_ATTRIBUTE_ID;
2772                     }
2773                 }
2774             }
2775             goto done;
2776         case XML_SCHEMAS_IDREF:
2777             ret = xmlValidateNCName(value, 1);
2778             if ((ret == 0) && (val != NULL)) {
2779                 v = xmlSchemaNewValue(XML_SCHEMAS_IDREF);
2780                 if (v == NULL)
2781                     goto error;
2782                 v->value.str = xmlStrdup(value);
2783                 *val = v;
2784             }
2785             if ((ret == 0) && (node != NULL) &&
2786                 (node->type == XML_ATTRIBUTE_NODE)) {
2787                 xmlAttrPtr attr = (xmlAttrPtr) node;
2788                 xmlChar *strip;
2789
2790                 strip = xmlSchemaStrip(value);
2791                 if (strip != NULL) {
2792                     xmlAddRef(NULL, node->doc, strip, attr);
2793                     xmlFree(strip);
2794                 } else
2795                     xmlAddRef(NULL, node->doc, value, attr);
2796                 attr->atype = XML_ATTRIBUTE_IDREF;
2797             }
2798             goto done;
2799         case XML_SCHEMAS_IDREFS:
2800             ret = xmlSchemaValAtomicListNode(xmlSchemaTypeIdrefDef,
2801                                              value, val, node);
2802             if (ret < 0)
2803                 ret = 2;
2804             else
2805                 ret = 0;
2806             if ((ret == 0) && (node != NULL) &&
2807                 (node->type == XML_ATTRIBUTE_NODE)) {
2808                 xmlAttrPtr attr = (xmlAttrPtr) node;
2809
2810                 attr->atype = XML_ATTRIBUTE_IDREFS;
2811             }
2812             goto done;
2813         case XML_SCHEMAS_ENTITY:{
2814                 xmlChar *strip;
2815
2816                 ret = xmlValidateNCName(value, 1);
2817                 if ((node == NULL) || (node->doc == NULL))
2818                     ret = 3;
2819                 if (ret == 0) {
2820                     xmlEntityPtr ent;
2821
2822                     strip = xmlSchemaStrip(value);
2823                     if (strip != NULL) {
2824                         ent = xmlGetDocEntity(node->doc, strip);
2825                         xmlFree(strip);
2826                     } else {
2827                         ent = xmlGetDocEntity(node->doc, value);
2828                     }
2829                     if ((ent == NULL) ||
2830                         (ent->etype !=
2831                          XML_EXTERNAL_GENERAL_UNPARSED_ENTITY))
2832                         ret = 4;
2833                 }
2834                 if ((ret == 0) && (val != NULL)) {
2835                     TODO;
2836                 }
2837                 if ((ret == 0) && (node != NULL) &&
2838                     (node->type == XML_ATTRIBUTE_NODE)) {
2839                     xmlAttrPtr attr = (xmlAttrPtr) node;
2840
2841                     attr->atype = XML_ATTRIBUTE_ENTITY;
2842                 }
2843                 goto done;
2844             }
2845         case XML_SCHEMAS_ENTITIES:
2846             if ((node == NULL) || (node->doc == NULL))
2847                 goto return3;
2848             ret = xmlSchemaValAtomicListNode(xmlSchemaTypeEntityDef,
2849                                              value, val, node);
2850             if (ret <= 0)
2851                 ret = 1;
2852             else
2853                 ret = 0;
2854             if ((ret == 0) && (node != NULL) &&
2855                 (node->type == XML_ATTRIBUTE_NODE)) {
2856                 xmlAttrPtr attr = (xmlAttrPtr) node;
2857
2858                 attr->atype = XML_ATTRIBUTE_ENTITIES;
2859             }
2860             goto done;
2861         case XML_SCHEMAS_NOTATION:{
2862                 xmlChar *uri = NULL;
2863                 xmlChar *local = NULL;
2864
2865                 ret = xmlValidateQName(value, 1);
2866                 if ((ret == 0) && (node != NULL)) {
2867                     xmlChar *prefix;
2868
2869                     local = xmlSplitQName2(value, &prefix);
2870                     if (prefix != NULL) {
2871                         xmlNsPtr ns;
2872
2873                         ns = xmlSearchNs(node->doc, node, prefix);
2874                         if (ns == NULL)
2875                             ret = 1;
2876                         else if (val != NULL)
2877                             uri = xmlStrdup(ns->href);
2878                     }
2879                     if ((local != NULL) && ((val == NULL) || (ret != 0)))
2880                         xmlFree(local);
2881                     if (prefix != NULL)
2882                         xmlFree(prefix);
2883                 }
2884                 if ((node == NULL) || (node->doc == NULL))
2885                     ret = 3;
2886                 if (ret == 0) {
2887                     ret = xmlValidateNotationUse(NULL, node->doc, value);
2888                     if (ret == 1)
2889                         ret = 0;
2890                     else
2891                         ret = 1;
2892                 }
2893                 if ((ret == 0) && (val != NULL)) {
2894                     v = xmlSchemaNewValue(XML_SCHEMAS_NOTATION);
2895                     if (v != NULL) {
2896                         if (local != NULL)
2897                             v->value.qname.name = local;
2898                         else
2899                             v->value.qname.name = xmlStrdup(value);
2900                         if (uri != NULL)
2901                             v->value.qname.uri = uri;
2902
2903                         *val = v;
2904                     } else {
2905                         if (local != NULL)
2906                             xmlFree(local);
2907                         if (uri != NULL)
2908                             xmlFree(uri);
2909                         goto error;
2910                     }
2911                 }
2912                 goto done;
2913             }
2914         case XML_SCHEMAS_ANYURI:{
2915                 if (*value != 0) {
2916                     xmlURIPtr uri;
2917                     xmlChar *tmpval, *cur;
2918                     if (normOnTheFly) {
2919                         norm = xmlSchemaCollapseString(value);
2920                         if (norm != NULL)
2921                             value = norm;
2922                     }
2923                     tmpval = xmlStrdup(value);
2924                     for (cur = tmpval; *cur; ++cur) {
2925                         if (*cur < 32 || *cur >= 127 || *cur == ' ' ||
2926                             *cur == '<' || *cur == '>' || *cur == '"' ||
2927                             *cur == '{' || *cur == '}' || *cur == '|' ||
2928                             *cur == '\\' || *cur == '^' || *cur == '`' ||
2929                             *cur == '\'')
2930                             *cur = '_';
2931                     }
2932                     uri = xmlParseURI((const char *) tmpval);
2933                     xmlFree(tmpval);
2934                     if (uri == NULL)
2935                         goto return1;
2936                     xmlFreeURI(uri);
2937                 }
2938
2939                 if (val != NULL) {
2940                     v = xmlSchemaNewValue(XML_SCHEMAS_ANYURI);
2941                     if (v == NULL)
2942                         goto error;
2943                     v->value.str = xmlStrdup(value);
2944                     *val = v;
2945                 }
2946                 goto return0;
2947             }
2948         case XML_SCHEMAS_HEXBINARY:{
2949                 const xmlChar *cur = value, *start;
2950                 xmlChar *base;
2951                 int total, i = 0;
2952
2953                 if (cur == NULL)
2954                     goto return1;
2955
2956                 if (normOnTheFly)
2957                     while IS_WSP_BLANK_CH(*cur) cur++;
2958
2959                 start = cur;
2960                 while (((*cur >= '0') && (*cur <= '9')) ||
2961                        ((*cur >= 'A') && (*cur <= 'F')) ||
2962                        ((*cur >= 'a') && (*cur <= 'f'))) {
2963                     i++;
2964                     cur++;
2965                 }
2966                 if (normOnTheFly)
2967                     while IS_WSP_BLANK_CH(*cur) cur++;
2968
2969                 if (*cur != 0)
2970                     goto return1;
2971                 if ((i % 2) != 0)
2972                     goto return1;
2973
2974                 if (val != NULL) {
2975
2976                     v = xmlSchemaNewValue(XML_SCHEMAS_HEXBINARY);
2977                     if (v == NULL)
2978                         goto error;
2979                     /*
2980                     * Copy only the normalized piece.
2981                     * CRITICAL TODO: Check this.
2982                     */
2983                     cur = xmlStrndup(start, i);
2984                     if (cur == NULL) {
2985                         xmlSchemaTypeErrMemory(node, "allocating hexbin data");
2986                         xmlFree(v);
2987                         goto return1;
2988                     }
2989
2990                     total = i / 2;      /* number of octets */
2991
2992                     base = (xmlChar *) cur;
2993                     while (i-- > 0) {
2994                         if (*base >= 'a')
2995                             *base = *base - ('a' - 'A');
2996                         base++;
2997                     }
2998
2999                     v->value.hex.str = (xmlChar *) cur;
3000                     v->value.hex.total = total;
3001                     *val = v;
3002                 }
3003                 goto return0;
3004             }
3005         case XML_SCHEMAS_BASE64BINARY:{
3006                 /* ISSUE:
3007                  *
3008                  * Ignore all stray characters? (yes, currently)
3009                  * Worry about long lines? (no, currently)
3010                  *
3011                  * rfc2045.txt:
3012                  *
3013                  * "The encoded output stream must be represented in lines of
3014                  * no more than 76 characters each.  All line breaks or other
3015                  * characters not found in Table 1 must be ignored by decoding
3016                  * software.  In base64 data, characters other than those in
3017                  * Table 1, line breaks, and other white space probably
3018                  * indicate a transmission error, about which a warning
3019                  * message or even a message rejection might be appropriate
3020                  * under some circumstances." */
3021                 const xmlChar *cur = value;
3022                 xmlChar *base;
3023                 int total, i = 0, pad = 0;
3024
3025                 if (cur == NULL)
3026                     goto return1;
3027
3028                 for (; *cur; ++cur) {
3029                     int decc;
3030
3031                     decc = _xmlSchemaBase64Decode(*cur);
3032                     if (decc < 0) ;
3033                     else if (decc < 64)
3034                         i++;
3035                     else
3036                         break;
3037                 }
3038                 for (; *cur; ++cur) {
3039                     int decc;
3040
3041                     decc = _xmlSchemaBase64Decode(*cur);
3042                     if (decc < 0) ;
3043                     else if (decc < 64)
3044                         goto return1;
3045                     if (decc == 64)
3046                         pad++;
3047                 }
3048
3049                 /* rfc2045.txt: "Special processing is performed if fewer than
3050                  * 24 bits are available at the end of the data being encoded.
3051                  * A full encoding quantum is always completed at the end of a
3052                  * body.  When fewer than 24 input bits are available in an
3053                  * input group, zero bits are added (on the right) to form an
3054                  * integral number of 6-bit groups.  Padding at the end of the
3055                  * data is performed using the "=" character.  Since all
3056                  * base64 input is an integral number of octets, only the
3057                  * following cases can arise: (1) the final quantum of
3058                  * encoding input is an integral multiple of 24 bits; here,
3059                  * the final unit of encoded output will be an integral
3060                  * multiple ofindent: Standard input:701: Warning:old style
3061                  * assignment ambiguity in "=*".  Assuming "= *" 4 characters
3062                  * with no "=" padding, (2) the final
3063                  * quantum of encoding input is exactly 8 bits; here, the
3064                  * final unit of encoded output will be two characters
3065                  * followed by two "=" padding characters, or (3) the final
3066                  * quantum of encoding input is exactly 16 bits; here, the
3067                  * final unit of encoded output will be three characters
3068                  * followed by one "=" padding character." */
3069
3070                 total = 3 * (i / 4);
3071                 if (pad == 0) {
3072                     if (i % 4 != 0)
3073                         goto return1;
3074                 } else if (pad == 1) {
3075                     int decc;
3076
3077                     if (i % 4 != 3)
3078                         goto return1;
3079                     for (decc = _xmlSchemaBase64Decode(*cur);
3080                          (decc < 0) || (decc > 63);
3081                          decc = _xmlSchemaBase64Decode(*cur))
3082                         --cur;
3083                     /* 16bits in 24bits means 2 pad bits: nnnnnn nnmmmm mmmm00*/
3084                     /* 00111100 -> 0x3c */
3085                     if (decc & ~0x3c)
3086                         goto return1;
3087                     total += 2;
3088                 } else if (pad == 2) {
3089                     int decc;
3090
3091                     if (i % 4 != 2)
3092                         goto return1;
3093                     for (decc = _xmlSchemaBase64Decode(*cur);
3094                          (decc < 0) || (decc > 63);
3095                          decc = _xmlSchemaBase64Decode(*cur))
3096                         --cur;
3097                     /* 8bits in 12bits means 4 pad bits: nnnnnn nn0000 */
3098                     /* 00110000 -> 0x30 */
3099                     if (decc & ~0x30)
3100                         goto return1;
3101                     total += 1;
3102                 } else
3103                     goto return1;
3104
3105                 if (val != NULL) {
3106                     v = xmlSchemaNewValue(XML_SCHEMAS_BASE64BINARY);
3107                     if (v == NULL)
3108                         goto error;
3109                     base =
3110                         (xmlChar *) xmlMallocAtomic((i + pad + 1) *
3111                                                     sizeof(xmlChar));
3112                     if (base == NULL) {
3113                         xmlSchemaTypeErrMemory(node, "allocating base64 data");
3114                         xmlFree(v);
3115                         goto return1;
3116                     }
3117                     v->value.base64.str = base;
3118                     for (cur = value; *cur; ++cur)
3119                         if (_xmlSchemaBase64Decode(*cur) >= 0) {
3120                             *base = *cur;
3121                             ++base;
3122                         }
3123                     *base = 0;
3124                     v->value.base64.total = total;
3125                     *val = v;
3126                 }
3127                 goto return0;
3128             }
3129         case XML_SCHEMAS_INTEGER:
3130         case XML_SCHEMAS_PINTEGER:
3131         case XML_SCHEMAS_NPINTEGER:
3132         case XML_SCHEMAS_NINTEGER:
3133         case XML_SCHEMAS_NNINTEGER:{
3134                 const xmlChar *cur = value;
3135                 unsigned long lo, mi, hi;
3136                 int sign = 0;
3137
3138                 if (cur == NULL)
3139                     goto return1;
3140                 if (normOnTheFly)
3141                     while IS_WSP_BLANK_CH(*cur) cur++;
3142                 if (*cur == '-') {
3143                     sign = 1;
3144                     cur++;
3145                 } else if (*cur == '+')
3146                     cur++;
3147                 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
3148                 if (ret < 0)
3149                     goto return1;
3150                 if (normOnTheFly)
3151                     while IS_WSP_BLANK_CH(*cur) cur++;
3152                 if (*cur != 0)
3153                     goto return1;
3154                 if (type->builtInType == XML_SCHEMAS_NPINTEGER) {
3155                     if ((sign == 0) &&
3156                         ((hi != 0) || (mi != 0) || (lo != 0)))
3157                         goto return1;
3158                 } else if (type->builtInType == XML_SCHEMAS_PINTEGER) {
3159                     if (sign == 1)
3160                         goto return1;
3161                     if ((hi == 0) && (mi == 0) && (lo == 0))
3162                         goto return1;
3163                 } else if (type->builtInType == XML_SCHEMAS_NINTEGER) {
3164                     if (sign == 0)
3165                         goto return1;
3166                     if ((hi == 0) && (mi == 0) && (lo == 0))
3167                         goto return1;
3168                 } else if (type->builtInType == XML_SCHEMAS_NNINTEGER) {
3169                     if ((sign == 1) &&
3170                         ((hi != 0) || (mi != 0) || (lo != 0)))
3171                         goto return1;
3172                 }
3173                 if (val != NULL) {
3174                     v = xmlSchemaNewValue(type->builtInType);
3175                     if (v != NULL) {
3176                         if (ret == 0)
3177                             ret++;
3178                         v->value.decimal.lo = lo;
3179                         v->value.decimal.mi = mi;
3180                         v->value.decimal.hi = hi;
3181                         v->value.decimal.sign = sign;
3182                         v->value.decimal.frac = 0;
3183                         v->value.decimal.total = ret;
3184                         *val = v;
3185                     }
3186                 }
3187                 goto return0;
3188             }
3189         case XML_SCHEMAS_LONG:
3190         case XML_SCHEMAS_BYTE:
3191         case XML_SCHEMAS_SHORT:
3192         case XML_SCHEMAS_INT:{
3193                 const xmlChar *cur = value;
3194                 unsigned long lo, mi, hi;
3195                 int sign = 0;
3196
3197                 if (cur == NULL)
3198                     goto return1;
3199                 if (*cur == '-') {
3200                     sign = 1;
3201                     cur++;
3202                 } else if (*cur == '+')
3203                     cur++;
3204                 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
3205                 if (ret < 0)
3206                     goto return1;
3207                 if (*cur != 0)
3208                     goto return1;
3209                 if (type->builtInType == XML_SCHEMAS_LONG) {
3210                     if (hi >= 922) {
3211                         if (hi > 922)
3212                             goto return1;
3213                         if (mi >= 33720368) {
3214                             if (mi > 33720368)
3215                                 goto return1;
3216                             if ((sign == 0) && (lo > 54775807))
3217                                 goto return1;
3218                             if ((sign == 1) && (lo > 54775808))
3219                                 goto return1;
3220                         }
3221                     }
3222                 } else if (type->builtInType == XML_SCHEMAS_INT) {
3223                     if (hi != 0)
3224                         goto return1;
3225                     if (mi >= 21) {
3226                         if (mi > 21)
3227                             goto return1;
3228                         if ((sign == 0) && (lo > 47483647))
3229                             goto return1;
3230                         if ((sign == 1) && (lo > 47483648))
3231                             goto return1;
3232                     }
3233                 } else if (type->builtInType == XML_SCHEMAS_SHORT) {
3234                     if ((mi != 0) || (hi != 0))
3235                         goto return1;
3236                     if ((sign == 1) && (lo > 32768))
3237                         goto return1;
3238                     if ((sign == 0) && (lo > 32767))
3239                         goto return1;
3240                 } else if (type->builtInType == XML_SCHEMAS_BYTE) {
3241                     if ((mi != 0) || (hi != 0))
3242                         goto return1;
3243                     if ((sign == 1) && (lo > 128))
3244                         goto return1;
3245                     if ((sign == 0) && (lo > 127))
3246                         goto return1;
3247                 }
3248                 if (val != NULL) {
3249                     v = xmlSchemaNewValue(type->builtInType);
3250                     if (v != NULL) {
3251                         v->value.decimal.lo = lo;
3252                         v->value.decimal.mi = mi;
3253                         v->value.decimal.hi = hi;
3254                         v->value.decimal.sign = sign;
3255                         v->value.decimal.frac = 0;
3256                         v->value.decimal.total = ret;
3257                         *val = v;
3258                     }
3259                 }
3260                 goto return0;
3261             }
3262         case XML_SCHEMAS_UINT:
3263         case XML_SCHEMAS_ULONG:
3264         case XML_SCHEMAS_USHORT:
3265         case XML_SCHEMAS_UBYTE:{
3266                 const xmlChar *cur = value;
3267                 unsigned long lo, mi, hi;
3268
3269                 if (cur == NULL)
3270                     goto return1;
3271                 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
3272                 if (ret < 0)
3273                     goto return1;
3274                 if (*cur != 0)
3275                     goto return1;
3276                 if (type->builtInType == XML_SCHEMAS_ULONG) {
3277                     if (hi >= 1844) {
3278                         if (hi > 1844)
3279                             goto return1;
3280                         if (mi >= 67440737) {
3281                             if (mi > 67440737)
3282                                 goto return1;
3283                             if (lo > 9551615)
3284                                 goto return1;
3285                         }
3286                     }
3287                 } else if (type->builtInType == XML_SCHEMAS_UINT) {
3288                     if (hi != 0)
3289                         goto return1;
3290                     if (mi >= 42) {
3291                         if (mi > 42)
3292                             goto return1;
3293                         if (lo > 94967295)
3294                             goto return1;
3295                     }
3296                 } else if (type->builtInType == XML_SCHEMAS_USHORT) {
3297                     if ((mi != 0) || (hi != 0))
3298                         goto return1;
3299                     if (lo > 65535)
3300                         goto return1;
3301                 } else if (type->builtInType == XML_SCHEMAS_UBYTE) {
3302                     if ((mi != 0) || (hi != 0))
3303                         goto return1;
3304                     if (lo > 255)
3305                         goto return1;
3306                 }
3307                 if (val != NULL) {
3308                     v = xmlSchemaNewValue(type->builtInType);
3309                     if (v != NULL) {
3310                         v->value.decimal.lo = lo;
3311                         v->value.decimal.mi = mi;
3312                         v->value.decimal.hi = hi;
3313                         v->value.decimal.sign = 0;
3314                         v->value.decimal.frac = 0;
3315                         v->value.decimal.total = ret;
3316                         *val = v;
3317                     }
3318                 }
3319                 goto return0;
3320             }
3321     }
3322
3323   done:
3324     if (norm != NULL)
3325         xmlFree(norm);
3326     return (ret);
3327   return3:
3328     if (norm != NULL)
3329         xmlFree(norm);
3330     return (3);
3331   return1:
3332     if (norm != NULL)
3333         xmlFree(norm);
3334     return (1);
3335   return0:
3336     if (norm != NULL)
3337         xmlFree(norm);
3338     return (0);
3339   error:
3340     if (norm != NULL)
3341         xmlFree(norm);
3342     return (-1);
3343 }
3344
3345 /**
3346  * xmlSchemaValPredefTypeNode:
3347  * @type: the predefined type
3348  * @value: the value to check
3349  * @val:  the return computed value
3350  * @node:  the node containing the value
3351  *
3352  * Check that a value conforms to the lexical space of the predefined type.
3353  * if true a value is computed and returned in @val.
3354  *
3355  * Returns 0 if this validates, a positive error code number otherwise
3356  *         and -1 in case of internal or API error.
3357  */
3358 int
3359 xmlSchemaValPredefTypeNode(xmlSchemaTypePtr type, const xmlChar *value,
3360                            xmlSchemaValPtr *val, xmlNodePtr node) {
3361     return(xmlSchemaValAtomicType(type, value, val, node, 0,
3362         XML_SCHEMA_WHITESPACE_UNKNOWN, 1, 1, 0));
3363 }
3364
3365 /**
3366  * xmlSchemaValPredefTypeNodeNoNorm:
3367  * @type: the predefined type
3368  * @value: the value to check
3369  * @val:  the return computed value
3370  * @node:  the node containing the value
3371  *
3372  * Check that a value conforms to the lexical space of the predefined type.
3373  * if true a value is computed and returned in @val.
3374  * This one does apply any normalization to the value.
3375  *
3376  * Returns 0 if this validates, a positive error code number otherwise
3377  *         and -1 in case of internal or API error.
3378  */
3379 int
3380 xmlSchemaValPredefTypeNodeNoNorm(xmlSchemaTypePtr type, const xmlChar *value,
3381                                  xmlSchemaValPtr *val, xmlNodePtr node) {
3382     return(xmlSchemaValAtomicType(type, value, val, node, 1,
3383         XML_SCHEMA_WHITESPACE_UNKNOWN, 1, 0, 1));
3384 }
3385
3386 /**
3387  * xmlSchemaValidatePredefinedType:
3388  * @type: the predefined type
3389  * @value: the value to check
3390  * @val:  the return computed value
3391  *
3392  * Check that a value conforms to the lexical space of the predefined type.
3393  * if true a value is computed and returned in @val.
3394  *
3395  * Returns 0 if this validates, a positive error code number otherwise
3396  *         and -1 in case of internal or API error.
3397  */
3398 int
3399 xmlSchemaValidatePredefinedType(xmlSchemaTypePtr type, const xmlChar *value,
3400                                 xmlSchemaValPtr *val) {
3401     return(xmlSchemaValPredefTypeNode(type, value, val, NULL));
3402 }
3403
3404 /**
3405  * xmlSchemaCompareDecimals:
3406  * @x:  a first decimal value
3407  * @y:  a second decimal value
3408  *
3409  * Compare 2 decimals
3410  *
3411  * Returns -1 if x < y, 0 if x == y, 1 if x > y and -2 in case of error
3412  */
3413 static int
3414 xmlSchemaCompareDecimals(xmlSchemaValPtr x, xmlSchemaValPtr y)
3415 {
3416     xmlSchemaValPtr swp;
3417     int order = 1, integx, integy, dlen;
3418     unsigned long hi, mi, lo;
3419
3420     /*
3421      * First test: If x is -ve and not zero
3422      */
3423     if ((x->value.decimal.sign) &&
3424         ((x->value.decimal.lo != 0) ||
3425          (x->value.decimal.mi != 0) ||
3426          (x->value.decimal.hi != 0))) {
3427         /*
3428          * Then if y is -ve and not zero reverse the compare
3429          */
3430         if ((y->value.decimal.sign) &&
3431             ((y->value.decimal.lo != 0) ||
3432              (y->value.decimal.mi != 0) ||
3433              (y->value.decimal.hi != 0)))
3434             order = -1;
3435         /*
3436          * Otherwise (y >= 0) we have the answer
3437          */
3438         else
3439             return (-1);
3440     /*
3441      * If x is not -ve and y is -ve we have the answer
3442      */
3443     } else if ((y->value.decimal.sign) &&
3444                ((y->value.decimal.lo != 0) ||
3445                 (y->value.decimal.mi != 0) ||
3446                 (y->value.decimal.hi != 0))) {
3447         return (1);
3448     }
3449     /*
3450      * If it's not simply determined by a difference in sign,
3451      * then we need to compare the actual values of the two nums.
3452      * To do this, we start by looking at the integral parts.
3453      * If the number of integral digits differ, then we have our
3454      * answer.
3455      */
3456     integx = x->value.decimal.total - x->value.decimal.frac;
3457     integy = y->value.decimal.total - y->value.decimal.frac;
3458     /*
3459     * NOTE: We changed the "total" for values like "0.1"
3460     *   (or "-0.1" or ".1") to be 1, which was 2 previously.
3461     *   Therefore the special case, when such values are
3462     *   compared with 0, needs to be handled separately;
3463     *   otherwise a zero would be recognized incorrectly as
3464     *   greater than those values. This has the nice side effect
3465     *   that we gain an overall optimized comparison with zeroes.
3466     * Note that a "0" has a "total" of 1 already.
3467     */
3468     if (integx == 1) {
3469         if (x->value.decimal.lo == 0) {
3470             if (integy != 1)
3471                 return -order;
3472             else if (y->value.decimal.lo != 0)
3473                 return -order;
3474             else
3475                 return(0);
3476         }
3477     }
3478     if (integy == 1) {
3479         if (y->value.decimal.lo == 0) {
3480             if (integx != 1)
3481                 return order;
3482             else if (x->value.decimal.lo != 0)
3483                 return order;
3484             else
3485                 return(0);
3486         }
3487     }
3488
3489     if (integx > integy)
3490         return order;
3491     else if (integy > integx)
3492         return -order;
3493
3494     /*
3495      * If the number of integral digits is the same for both numbers,
3496      * then things get a little more complicated.  We need to "normalize"
3497      * the numbers in order to properly compare them.  To do this, we
3498      * look at the total length of each number (length => number of
3499      * significant digits), and divide the "shorter" by 10 (decreasing
3500      * the length) until they are of equal length.
3501      */
3502     dlen = x->value.decimal.total - y->value.decimal.total;
3503     if (dlen < 0) {     /* y has more digits than x */
3504         swp = x;
3505         hi = y->value.decimal.hi;
3506         mi = y->value.decimal.mi;
3507         lo = y->value.decimal.lo;
3508         dlen = -dlen;
3509         order = -order;
3510     } else {            /* x has more digits than y */
3511         swp = y;
3512         hi = x->value.decimal.hi;
3513         mi = x->value.decimal.mi;
3514         lo = x->value.decimal.lo;
3515     }
3516     while (dlen > 8) {  /* in effect, right shift by 10**8 */
3517         lo = mi;
3518         mi = hi;
3519         hi = 0;
3520         dlen -= 8;
3521     }
3522     while (dlen > 0) {
3523         unsigned long rem1, rem2;
3524         rem1 = (hi % 10) * 100000000L;
3525         hi = hi / 10;
3526         rem2 = (mi % 10) * 100000000L;
3527         mi = (mi + rem1) / 10;
3528         lo = (lo + rem2) / 10;
3529         dlen--;
3530     }
3531     if (hi > swp->value.decimal.hi) {
3532         return order;
3533     } else if (hi == swp->value.decimal.hi) {
3534         if (mi > swp->value.decimal.mi) {
3535             return order;
3536         } else if (mi == swp->value.decimal.mi) {
3537             if (lo > swp->value.decimal.lo) {
3538                 return order;
3539             } else if (lo == swp->value.decimal.lo) {
3540                 if (x->value.decimal.total == y->value.decimal.total) {
3541                     return 0;
3542                 } else {
3543                     return order;
3544                 }
3545             }
3546         }
3547     }
3548     return -order;
3549 }
3550
3551 /**
3552  * xmlSchemaCompareDurations:
3553  * @x:  a first duration value
3554  * @y:  a second duration value
3555  *
3556  * Compare 2 durations
3557  *
3558  * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3559  * case of error
3560  */
3561 static int
3562 xmlSchemaCompareDurations(xmlSchemaValPtr x, xmlSchemaValPtr y)
3563 {
3564     long carry, mon, day;
3565     double sec;
3566     int invert = 1;
3567     long xmon, xday, myear, minday, maxday;
3568     static const long dayRange [2][12] = {
3569         { 0, 28, 59, 89, 120, 150, 181, 212, 242, 273, 303, 334, },
3570         { 0, 31, 62, 92, 123, 153, 184, 215, 245, 276, 306, 337} };
3571
3572     if ((x == NULL) || (y == NULL))
3573         return -2;
3574
3575     /* months */
3576     mon = x->value.dur.mon - y->value.dur.mon;
3577
3578     /* seconds */
3579     sec = x->value.dur.sec - y->value.dur.sec;
3580     carry = (long)(sec / SECS_PER_DAY);
3581     sec -= ((double)carry) * SECS_PER_DAY;
3582
3583     /* days */
3584     day = x->value.dur.day - y->value.dur.day + carry;
3585
3586     /* easy test */
3587     if (mon == 0) {
3588         if (day == 0)
3589             if (sec == 0.0)
3590                 return 0;
3591             else if (sec < 0.0)
3592                 return -1;
3593             else
3594                 return 1;
3595         else if (day < 0)
3596             return -1;
3597         else
3598             return 1;
3599     }
3600
3601     if (mon > 0) {
3602         if ((day >= 0) && (sec >= 0.0))
3603             return 1;
3604         else {
3605             xmon = mon;
3606             xday = -day;
3607         }
3608     } else if ((day <= 0) && (sec <= 0.0)) {
3609         return -1;
3610     } else {
3611         invert = -1;
3612         xmon = -mon;
3613         xday = day;
3614     }
3615
3616     myear = xmon / 12;
3617     if (myear == 0) {
3618         minday = 0;
3619         maxday = 0;
3620     } else {
3621         maxday = 366 * ((myear + 3) / 4) +
3622                  365 * ((myear - 1) % 4);
3623         minday = maxday - 1;
3624     }
3625
3626     xmon = xmon % 12;
3627     minday += dayRange[0][xmon];
3628     maxday += dayRange[1][xmon];
3629
3630     if ((maxday == minday) && (maxday == xday))
3631         return(0); /* can this really happen ? */
3632     if (maxday < xday)
3633         return(-invert);
3634     if (minday > xday)
3635         return(invert);
3636
3637     /* indeterminate */
3638     return 2;
3639 }
3640
3641 /*
3642  * macros for adding date/times and durations
3643  */
3644 #define FQUOTIENT(a,b)                  (floor(((double)a/(double)b)))
3645 #define MODULO(a,b)                     (a - FQUOTIENT(a,b) * b)
3646 #define FQUOTIENT_RANGE(a,low,high)     (FQUOTIENT((a-low),(high-low)))
3647 #define MODULO_RANGE(a,low,high)        ((MODULO((a-low),(high-low)))+low)
3648
3649 /**
3650  * xmlSchemaDupVal:
3651  * @v: the #xmlSchemaValPtr value to duplicate
3652  *
3653  * Makes a copy of @v. The calling program is responsible for freeing
3654  * the returned value.
3655  *
3656  * returns a pointer to a duplicated #xmlSchemaValPtr or NULL if error.
3657  */
3658 static xmlSchemaValPtr
3659 xmlSchemaDupVal (xmlSchemaValPtr v)
3660 {
3661     xmlSchemaValPtr ret = xmlSchemaNewValue(v->type);
3662     if (ret == NULL)
3663         return NULL;
3664
3665     memcpy(ret, v, sizeof(xmlSchemaVal));
3666     ret->next = NULL;
3667     return ret;
3668 }
3669
3670 /**
3671  * xmlSchemaCopyValue:
3672  * @val:  the precomputed value to be copied
3673  *
3674  * Copies the precomputed value. This duplicates any string within.
3675  *
3676  * Returns the copy or NULL if a copy for a data-type is not implemented.
3677  */
3678 xmlSchemaValPtr
3679 xmlSchemaCopyValue(xmlSchemaValPtr val)
3680 {
3681     xmlSchemaValPtr ret = NULL, prev = NULL, cur;
3682
3683     /*
3684     * Copy the string values.
3685     */
3686     while (val != NULL) {
3687         switch (val->type) {
3688             case XML_SCHEMAS_ANYTYPE:
3689             case XML_SCHEMAS_IDREFS:
3690             case XML_SCHEMAS_ENTITIES:
3691             case XML_SCHEMAS_NMTOKENS:
3692                 xmlSchemaFreeValue(ret);
3693                 return (NULL);
3694             case XML_SCHEMAS_ANYSIMPLETYPE:
3695             case XML_SCHEMAS_STRING:
3696             case XML_SCHEMAS_NORMSTRING:
3697             case XML_SCHEMAS_TOKEN:
3698             case XML_SCHEMAS_LANGUAGE:
3699             case XML_SCHEMAS_NAME:
3700             case XML_SCHEMAS_NCNAME:
3701             case XML_SCHEMAS_ID:
3702             case XML_SCHEMAS_IDREF:
3703             case XML_SCHEMAS_ENTITY:
3704             case XML_SCHEMAS_NMTOKEN:
3705             case XML_SCHEMAS_ANYURI:
3706                 cur = xmlSchemaDupVal(val);
3707                 if (val->value.str != NULL)
3708                     cur->value.str = xmlStrdup(BAD_CAST val->value.str);
3709                 break;
3710             case XML_SCHEMAS_QNAME:
3711             case XML_SCHEMAS_NOTATION:
3712                 cur = xmlSchemaDupVal(val);
3713                 if (val->value.qname.name != NULL)
3714                     cur->value.qname.name =
3715                     xmlStrdup(BAD_CAST val->value.qname.name);
3716                 if (val->value.qname.uri != NULL)
3717                     cur->value.qname.uri =
3718                     xmlStrdup(BAD_CAST val->value.qname.uri);
3719                 break;
3720             case XML_SCHEMAS_HEXBINARY:
3721                 cur = xmlSchemaDupVal(val);
3722                 if (val->value.hex.str != NULL)
3723                     cur->value.hex.str = xmlStrdup(BAD_CAST val->value.hex.str);
3724                 break;
3725             case XML_SCHEMAS_BASE64BINARY:
3726                 cur = xmlSchemaDupVal(val);
3727                 if (val->value.base64.str != NULL)
3728                     cur->value.base64.str =
3729                     xmlStrdup(BAD_CAST val->value.base64.str);
3730                 break;
3731             default:
3732                 cur = xmlSchemaDupVal(val);
3733                 break;
3734         }
3735         if (ret == NULL)
3736             ret = cur;
3737         else
3738             prev->next = cur;
3739         prev = cur;
3740         val = val->next;
3741     }
3742     return (ret);
3743 }
3744
3745 /**
3746  * _xmlSchemaDateAdd:
3747  * @dt: an #xmlSchemaValPtr
3748  * @dur: an #xmlSchemaValPtr of type #XS_DURATION
3749  *
3750  * Compute a new date/time from @dt and @dur. This function assumes @dt
3751  * is either #XML_SCHEMAS_DATETIME, #XML_SCHEMAS_DATE, #XML_SCHEMAS_GYEARMONTH,
3752  * or #XML_SCHEMAS_GYEAR. The returned #xmlSchemaVal is the same type as
3753  * @dt. The calling program is responsible for freeing the returned value.
3754  *
3755  * Returns a pointer to a new #xmlSchemaVal or NULL if error.
3756  */
3757 static xmlSchemaValPtr
3758 _xmlSchemaDateAdd (xmlSchemaValPtr dt, xmlSchemaValPtr dur)
3759 {
3760     xmlSchemaValPtr ret, tmp;
3761     long carry, tempdays, temp;
3762     xmlSchemaValDatePtr r, d;
3763     xmlSchemaValDurationPtr u;
3764
3765     if ((dt == NULL) || (dur == NULL))
3766         return NULL;
3767
3768     ret = xmlSchemaNewValue(dt->type);
3769     if (ret == NULL)
3770         return NULL;
3771
3772     /* make a copy so we don't alter the original value */
3773     tmp = xmlSchemaDupVal(dt);
3774     if (tmp == NULL) {
3775         xmlSchemaFreeValue(ret);
3776         return NULL;
3777     }
3778
3779     r = &(ret->value.date);
3780     d = &(tmp->value.date);
3781     u = &(dur->value.dur);
3782
3783     /* normalization */
3784     if (d->mon == 0)
3785         d->mon = 1;
3786
3787     /* normalize for time zone offset */
3788     u->sec -= (d->tzo * 60);
3789     d->tzo = 0;
3790
3791     /* normalization */
3792     if (d->day == 0)
3793         d->day = 1;
3794
3795     /* month */
3796     carry  = d->mon + u->mon;
3797     r->mon = (unsigned int) MODULO_RANGE(carry, 1, 13);
3798     carry  = (long) FQUOTIENT_RANGE(carry, 1, 13);
3799
3800     /* year (may be modified later) */
3801     r->year = d->year + carry;
3802     if (r->year == 0) {
3803         if (d->year > 0)
3804             r->year--;
3805         else
3806             r->year++;
3807     }
3808
3809     /* time zone */
3810     r->tzo     = d->tzo;
3811     r->tz_flag = d->tz_flag;
3812
3813     /* seconds */
3814     r->sec = d->sec + u->sec;
3815     carry  = (long) FQUOTIENT((long)r->sec, 60);
3816     if (r->sec != 0.0) {
3817         r->sec = MODULO(r->sec, 60.0);
3818     }
3819
3820     /* minute */
3821     carry += d->min;
3822     r->min = (unsigned int) MODULO(carry, 60);
3823     carry  = (long) FQUOTIENT(carry, 60);
3824
3825     /* hours */
3826     carry  += d->hour;
3827     r->hour = (unsigned int) MODULO(carry, 24);
3828     carry   = (long)FQUOTIENT(carry, 24);
3829
3830     /*
3831      * days
3832      * Note we use tempdays because the temporary values may need more
3833      * than 5 bits
3834      */
3835     if ((VALID_YEAR(r->year)) && (VALID_MONTH(r->mon)) &&
3836                   (d->day > MAX_DAYINMONTH(r->year, r->mon)))
3837         tempdays = MAX_DAYINMONTH(r->year, r->mon);
3838     else if (d->day < 1)
3839         tempdays = 1;
3840     else
3841         tempdays = d->day;
3842
3843     tempdays += u->day + carry;
3844
3845     while (1) {
3846         if (tempdays < 1) {
3847             long tmon = (long) MODULO_RANGE((int)r->mon-1, 1, 13);
3848             long tyr  = r->year + (long)FQUOTIENT_RANGE((int)r->mon-1, 1, 13);
3849             if (tyr == 0)
3850                 tyr--;
3851             /*
3852              * Coverity detected an overrun in daysInMonth
3853              * of size 12 at position 12 with index variable "((r)->mon - 1)"
3854              */
3855             if (tmon < 1)
3856                 tmon = 1;
3857             if (tmon > 12)
3858                 tmon = 12;
3859             tempdays += MAX_DAYINMONTH(tyr, tmon);
3860             carry = -1;
3861         } else if (VALID_YEAR(r->year) && VALID_MONTH(r->mon) &&
3862                    tempdays > (long) MAX_DAYINMONTH(r->year, r->mon)) {
3863             tempdays = tempdays - MAX_DAYINMONTH(r->year, r->mon);
3864             carry = 1;
3865         } else
3866             break;
3867
3868         temp = r->mon + carry;
3869         r->mon = (unsigned int) MODULO_RANGE(temp, 1, 13);
3870         r->year = r->year + (unsigned int) FQUOTIENT_RANGE(temp, 1, 13);
3871         if (r->year == 0) {
3872             if (temp < 1)
3873                 r->year--;
3874             else
3875                 r->year++;
3876         }
3877     }
3878
3879     r->day = tempdays;
3880
3881     /*
3882      * adjust the date/time type to the date values
3883      */
3884     if (ret->type != XML_SCHEMAS_DATETIME) {
3885         if ((r->hour) || (r->min) || (r->sec))
3886             ret->type = XML_SCHEMAS_DATETIME;
3887         else if (ret->type != XML_SCHEMAS_DATE) {
3888             if ((r->mon != 1) && (r->day != 1))
3889                 ret->type = XML_SCHEMAS_DATE;
3890             else if ((ret->type != XML_SCHEMAS_GYEARMONTH) && (r->mon != 1))
3891                 ret->type = XML_SCHEMAS_GYEARMONTH;
3892         }
3893     }
3894
3895     xmlSchemaFreeValue(tmp);
3896
3897     return ret;
3898 }
3899
3900 /**
3901  * xmlSchemaDateNormalize:
3902  * @dt: an #xmlSchemaValPtr of a date/time type value.
3903  * @offset: number of seconds to adjust @dt by.
3904  *
3905  * Normalize @dt to GMT time. The @offset parameter is subtracted from
3906  * the return value is a time-zone offset is present on @dt.
3907  *
3908  * Returns a normalized copy of @dt or NULL if error.
3909  */
3910 static xmlSchemaValPtr
3911 xmlSchemaDateNormalize (xmlSchemaValPtr dt, double offset)
3912 {
3913     xmlSchemaValPtr dur, ret;
3914
3915     if (dt == NULL)
3916         return NULL;
3917
3918     if (((dt->type != XML_SCHEMAS_TIME) &&
3919          (dt->type != XML_SCHEMAS_DATETIME) &&
3920          (dt->type != XML_SCHEMAS_DATE)) || (dt->value.date.tzo == 0))
3921         return xmlSchemaDupVal(dt);
3922
3923     dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
3924     if (dur == NULL)
3925         return NULL;
3926
3927     dur->value.date.sec -= offset;
3928
3929     ret = _xmlSchemaDateAdd(dt, dur);
3930     if (ret == NULL)
3931         return NULL;
3932
3933     xmlSchemaFreeValue(dur);
3934
3935     /* ret->value.date.tzo = 0; */
3936     return ret;
3937 }
3938
3939 /**
3940  * _xmlSchemaDateCastYMToDays:
3941  * @dt: an #xmlSchemaValPtr
3942  *
3943  * Convert mon and year of @dt to total number of days. Take the
3944  * number of years since (or before) 1 AD and add the number of leap
3945  * years. This is a function  because negative
3946  * years must be handled a little differently and there is no zero year.
3947  *
3948  * Returns number of days.
3949  */
3950 static long
3951 _xmlSchemaDateCastYMToDays (const xmlSchemaValPtr dt)
3952 {
3953     long ret;
3954     int mon;
3955
3956     mon = dt->value.date.mon;
3957     if (mon <= 0) mon = 1; /* normalization */
3958
3959     if (dt->value.date.year <= 0)
3960         ret = (dt->value.date.year * 365) +
3961               (((dt->value.date.year+1)/4)-((dt->value.date.year+1)/100)+
3962                ((dt->value.date.year+1)/400)) +
3963               DAY_IN_YEAR(0, mon, dt->value.date.year);
3964     else
3965         ret = ((dt->value.date.year-1) * 365) +
3966               (((dt->value.date.year-1)/4)-((dt->value.date.year-1)/100)+
3967                ((dt->value.date.year-1)/400)) +
3968               DAY_IN_YEAR(0, mon, dt->value.date.year);
3969
3970     return ret;
3971 }
3972
3973 /**
3974  * TIME_TO_NUMBER:
3975  * @dt:  an #xmlSchemaValPtr
3976  *
3977  * Calculates the number of seconds in the time portion of @dt.
3978  *
3979  * Returns seconds.
3980  */
3981 #define TIME_TO_NUMBER(dt)                              \
3982     ((double)((dt->value.date.hour * SECS_PER_HOUR) +   \
3983               (dt->value.date.min * SECS_PER_MIN) +     \
3984               (dt->value.date.tzo * SECS_PER_MIN)) +    \
3985                dt->value.date.sec)
3986
3987 /**
3988  * xmlSchemaCompareDates:
3989  * @x:  a first date/time value
3990  * @y:  a second date/time value
3991  *
3992  * Compare 2 date/times
3993  *
3994  * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3995  * case of error
3996  */
3997 static int
3998 xmlSchemaCompareDates (xmlSchemaValPtr x, xmlSchemaValPtr y)
3999 {
4000     unsigned char xmask, ymask, xor_mask, and_mask;
4001     xmlSchemaValPtr p1, p2, q1, q2;
4002     long p1d, p2d, q1d, q2d;
4003
4004     if ((x == NULL) || (y == NULL))
4005         return -2;
4006
4007     if (x->value.date.tz_flag) {
4008
4009         if (!y->value.date.tz_flag) {
4010             p1 = xmlSchemaDateNormalize(x, 0);
4011             p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
4012             /* normalize y + 14:00 */
4013             q1 = xmlSchemaDateNormalize(y, (14 * SECS_PER_HOUR));
4014
4015             q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
4016             if (p1d < q1d) {
4017                 xmlSchemaFreeValue(p1);
4018                 xmlSchemaFreeValue(q1);
4019                 return -1;
4020             } else if (p1d == q1d) {
4021                 double sec;
4022
4023                 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
4024                 if (sec < 0.0) {
4025                     xmlSchemaFreeValue(p1);
4026                     xmlSchemaFreeValue(q1);
4027                     return -1;
4028                 } else {
4029                     int ret = 0;
4030                     /* normalize y - 14:00 */
4031                     q2 = xmlSchemaDateNormalize(y, -(14 * SECS_PER_HOUR));
4032                     q2d = _xmlSchemaDateCastYMToDays(q2) + q2->value.date.day;
4033                     if (p1d > q2d)
4034                         ret = 1;
4035                     else if (p1d == q2d) {
4036                         sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q2);
4037                         if (sec > 0.0)
4038                             ret = 1;
4039                         else
4040                             ret = 2; /* indeterminate */
4041                     }
4042                     xmlSchemaFreeValue(p1);
4043                     xmlSchemaFreeValue(q1);
4044                     xmlSchemaFreeValue(q2);
4045                     if (ret != 0)
4046                         return(ret);
4047                 }
4048             } else {
4049                 xmlSchemaFreeValue(p1);
4050                 xmlSchemaFreeValue(q1);
4051             }
4052         }
4053     } else if (y->value.date.tz_flag) {
4054         q1 = xmlSchemaDateNormalize(y, 0);
4055         q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
4056
4057         /* normalize x - 14:00 */
4058         p1 = xmlSchemaDateNormalize(x, -(14 * SECS_PER_HOUR));
4059         p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
4060
4061         if (p1d < q1d) {
4062             xmlSchemaFreeValue(p1);
4063             xmlSchemaFreeValue(q1);
4064             return -1;
4065         } else if (p1d == q1d) {
4066             double sec;
4067
4068             sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
4069             if (sec < 0.0) {
4070                 xmlSchemaFreeValue(p1);
4071                 xmlSchemaFreeValue(q1);
4072                 return -1;
4073             } else {
4074                 int ret = 0;
4075                 /* normalize x + 14:00 */
4076                 p2 = xmlSchemaDateNormalize(x, (14 * SECS_PER_HOUR));
4077                 p2d = _xmlSchemaDateCastYMToDays(p2) + p2->value.date.day;
4078
4079                 if (p2d > q1d) {
4080                     ret = 1;
4081                 } else if (p2d == q1d) {
4082                     sec = TIME_TO_NUMBER(p2) - TIME_TO_NUMBER(q1);
4083                     if (sec > 0.0)
4084                         ret = 1;
4085                     else
4086                         ret = 2; /* indeterminate */
4087                 }
4088                 xmlSchemaFreeValue(p1);
4089                 xmlSchemaFreeValue(q1);
4090                 xmlSchemaFreeValue(p2);
4091                 if (ret != 0)
4092                     return(ret);
4093             }
4094         } else {
4095             xmlSchemaFreeValue(p1);
4096             xmlSchemaFreeValue(q1);
4097         }
4098     }
4099
4100     /*
4101      * if the same type then calculate the difference
4102      */
4103     if (x->type == y->type) {
4104         int ret = 0;
4105         q1 = xmlSchemaDateNormalize(y, 0);
4106         q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
4107
4108         p1 = xmlSchemaDateNormalize(x, 0);
4109         p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
4110
4111         if (p1d < q1d) {
4112             ret = -1;
4113         } else if (p1d > q1d) {
4114             ret = 1;
4115         } else {
4116             double sec;
4117
4118             sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
4119             if (sec < 0.0)
4120                 ret = -1;
4121             else if (sec > 0.0)
4122                 ret = 1;
4123
4124         }
4125         xmlSchemaFreeValue(p1);
4126         xmlSchemaFreeValue(q1);
4127         return(ret);
4128     }
4129
4130     switch (x->type) {
4131         case XML_SCHEMAS_DATETIME:
4132             xmask = 0xf;
4133             break;
4134         case XML_SCHEMAS_DATE:
4135             xmask = 0x7;
4136             break;
4137         case XML_SCHEMAS_GYEAR:
4138             xmask = 0x1;
4139             break;
4140         case XML_SCHEMAS_GMONTH:
4141             xmask = 0x2;
4142             break;
4143         case XML_SCHEMAS_GDAY:
4144             xmask = 0x3;
4145             break;
4146         case XML_SCHEMAS_GYEARMONTH:
4147             xmask = 0x3;
4148             break;
4149         case XML_SCHEMAS_GMONTHDAY:
4150             xmask = 0x6;
4151             break;
4152         case XML_SCHEMAS_TIME:
4153             xmask = 0x8;
4154             break;
4155         default:
4156             xmask = 0;
4157             break;
4158     }
4159
4160     switch (y->type) {
4161         case XML_SCHEMAS_DATETIME:
4162             ymask = 0xf;
4163             break;
4164         case XML_SCHEMAS_DATE:
4165             ymask = 0x7;
4166             break;
4167         case XML_SCHEMAS_GYEAR:
4168             ymask = 0x1;
4169             break;
4170         case XML_SCHEMAS_GMONTH:
4171             ymask = 0x2;
4172             break;
4173         case XML_SCHEMAS_GDAY:
4174             ymask = 0x3;
4175             break;
4176         case XML_SCHEMAS_GYEARMONTH:
4177             ymask = 0x3;
4178             break;
4179         case XML_SCHEMAS_GMONTHDAY:
4180             ymask = 0x6;
4181             break;
4182         case XML_SCHEMAS_TIME:
4183             ymask = 0x8;
4184             break;
4185         default:
4186             ymask = 0;
4187             break;
4188     }
4189
4190     xor_mask = xmask ^ ymask;           /* mark type differences */
4191     and_mask = xmask & ymask;           /* mark field specification */
4192
4193     /* year */
4194     if (xor_mask & 1)
4195         return 2; /* indeterminate */
4196     else if (and_mask & 1) {
4197         if (x->value.date.year < y->value.date.year)
4198             return -1;
4199         else if (x->value.date.year > y->value.date.year)
4200             return 1;
4201     }
4202
4203     /* month */
4204     if (xor_mask & 2)
4205         return 2; /* indeterminate */
4206     else if (and_mask & 2) {
4207         if (x->value.date.mon < y->value.date.mon)
4208             return -1;
4209         else if (x->value.date.mon > y->value.date.mon)
4210             return 1;
4211     }
4212
4213     /* day */
4214     if (xor_mask & 4)
4215         return 2; /* indeterminate */
4216     else if (and_mask & 4) {
4217         if (x->value.date.day < y->value.date.day)
4218             return -1;
4219         else if (x->value.date.day > y->value.date.day)
4220             return 1;
4221     }
4222
4223     /* time */
4224     if (xor_mask & 8)
4225         return 2; /* indeterminate */
4226     else if (and_mask & 8) {
4227         if (x->value.date.hour < y->value.date.hour)
4228             return -1;
4229         else if (x->value.date.hour > y->value.date.hour)
4230             return 1;
4231         else if (x->value.date.min < y->value.date.min)
4232             return -1;
4233         else if (x->value.date.min > y->value.date.min)
4234             return 1;
4235         else if (x->value.date.sec < y->value.date.sec)
4236             return -1;
4237         else if (x->value.date.sec > y->value.date.sec)
4238             return 1;
4239     }
4240
4241     return 0;
4242 }
4243
4244 /**
4245  * xmlSchemaComparePreserveReplaceStrings:
4246  * @x:  a first string value
4247  * @y:  a second string value
4248  * @invert: inverts the result if x < y or x > y.
4249  *
4250  * Compare 2 string for their normalized values.
4251  * @x is a string with whitespace of "preserve", @y is
4252  * a string with a whitespace of "replace". I.e. @x could
4253  * be an "xsd:string" and @y an "xsd:normalizedString".
4254  *
4255  * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
4256  * case of error
4257  */
4258 static int
4259 xmlSchemaComparePreserveReplaceStrings(const xmlChar *x,
4260                                        const xmlChar *y,
4261                                        int invert)
4262 {
4263     int tmp;
4264
4265     while ((*x != 0) && (*y != 0)) {
4266         if (IS_WSP_REPLACE_CH(*y)) {
4267             if (! IS_WSP_SPACE_CH(*x)) {
4268                 if ((*x - 0x20) < 0) {
4269                     if (invert)
4270                         return(1);
4271                     else
4272                         return(-1);
4273                 } else {
4274                     if (invert)
4275                         return(-1);
4276                     else
4277                         return(1);
4278                 }
4279             }
4280         } else {
4281             tmp = *x - *y;
4282             if (tmp < 0) {
4283                 if (invert)
4284                     return(1);
4285                 else
4286                     return(-1);
4287             }
4288             if (tmp > 0) {
4289                 if (invert)
4290                     return(-1);
4291                 else
4292                     return(1);
4293             }
4294         }
4295         x++;
4296         y++;
4297     }
4298     if (*x != 0) {
4299         if (invert)
4300             return(-1);
4301         else
4302             return(1);
4303     }
4304     if (*y != 0) {
4305         if (invert)
4306             return(1);
4307         else
4308             return(-1);
4309     }
4310     return(0);
4311 }
4312
4313 /**
4314  * xmlSchemaComparePreserveCollapseStrings:
4315  * @x:  a first string value
4316  * @y:  a second string value
4317  *
4318  * Compare 2 string for their normalized values.
4319  * @x is a string with whitespace of "preserve", @y is
4320  * a string with a whitespace of "collapse". I.e. @x could
4321  * be an "xsd:string" and @y an "xsd:normalizedString".
4322  *
4323  * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
4324  * case of error
4325  */
4326 static int
4327 xmlSchemaComparePreserveCollapseStrings(const xmlChar *x,
4328                                         const xmlChar *y,
4329                                         int invert)
4330 {
4331     int tmp;
4332
4333     /*
4334     * Skip leading blank chars of the collapsed string.
4335     */
4336     while IS_WSP_BLANK_CH(*y)
4337         y++;
4338
4339     while ((*x != 0) && (*y != 0)) {
4340         if IS_WSP_BLANK_CH(*y) {
4341             if (! IS_WSP_SPACE_CH(*x)) {
4342                 /*
4343                 * The yv character would have been replaced to 0x20.
4344                 */
4345                 if ((*x - 0x20) < 0) {
4346                     if (invert)
4347                         return(1);
4348                     else
4349                         return(-1);
4350                 } else {
4351                     if (invert)
4352                         return(-1);
4353                     else
4354                         return(1);
4355                 }
4356             }
4357             x++;
4358             y++;
4359             /*
4360             * Skip contiguous blank chars of the collapsed string.
4361             */
4362             while IS_WSP_BLANK_CH(*y)
4363                 y++;
4364         } else {
4365             tmp = *x++ - *y++;
4366             if (tmp < 0) {
4367                 if (invert)
4368                     return(1);
4369                 else
4370                     return(-1);
4371             }
4372             if (tmp > 0) {
4373                 if (invert)
4374                     return(-1);
4375                 else
4376                     return(1);
4377             }
4378         }
4379     }
4380     if (*x != 0) {
4381          if (invert)
4382              return(-1);
4383          else
4384              return(1);
4385     }
4386     if (*y != 0) {
4387         /*
4388         * Skip trailing blank chars of the collapsed string.
4389         */
4390         while IS_WSP_BLANK_CH(*y)
4391             y++;
4392         if (*y != 0) {
4393             if (invert)
4394                 return(1);
4395             else
4396                 return(-1);
4397         }
4398     }
4399     return(0);
4400 }
4401
4402 /**
4403  * xmlSchemaComparePreserveCollapseStrings:
4404  * @x:  a first string value
4405  * @y:  a second string value
4406  *
4407  * Compare 2 string for their normalized values.
4408  * @x is a string with whitespace of "preserve", @y is
4409  * a string with a whitespace of "collapse". I.e. @x could
4410  * be an "xsd:string" and @y an "xsd:normalizedString".
4411  *
4412  * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
4413  * case of error
4414  */
4415 static int
4416 xmlSchemaCompareReplaceCollapseStrings(const xmlChar *x,
4417                                        const xmlChar *y,
4418                                        int invert)
4419 {
4420     int tmp;
4421
4422     /*
4423     * Skip leading blank chars of the collapsed string.
4424     */
4425     while IS_WSP_BLANK_CH(*y)
4426         y++;
4427
4428     while ((*x != 0) && (*y != 0)) {
4429         if IS_WSP_BLANK_CH(*y) {
4430             if (! IS_WSP_BLANK_CH(*x)) {
4431                 /*
4432                 * The yv character would have been replaced to 0x20.
4433                 */
4434                 if ((*x - 0x20) < 0) {
4435                     if (invert)
4436                         return(1);
4437                     else
4438                         return(-1);
4439                 } else {
4440                     if (invert)
4441                         return(-1);
4442                     else
4443                         return(1);
4444                 }
4445             }
4446             x++;
4447             y++;
4448             /*
4449             * Skip contiguous blank chars of the collapsed string.
4450             */
4451             while IS_WSP_BLANK_CH(*y)
4452                 y++;
4453         } else {
4454             if IS_WSP_BLANK_CH(*x) {
4455                 /*
4456                 * The xv character would have been replaced to 0x20.
4457                 */
4458                 if ((0x20 - *y) < 0) {
4459                     if (invert)
4460                         return(1);
4461                     else
4462                         return(-1);
4463                 } else {
4464                     if (invert)
4465                         return(-1);
4466                     else
4467                         return(1);
4468                 }
4469             }
4470             tmp = *x++ - *y++;
4471             if (tmp < 0)
4472                 return(-1);
4473             if (tmp > 0)
4474                 return(1);
4475         }
4476     }
4477     if (*x != 0) {
4478          if (invert)
4479              return(-1);
4480          else
4481              return(1);
4482     }
4483     if (*y != 0) {
4484         /*
4485         * Skip trailing blank chars of the collapsed string.
4486         */
4487         while IS_WSP_BLANK_CH(*y)
4488             y++;
4489         if (*y != 0) {
4490             if (invert)
4491                 return(1);
4492             else
4493                 return(-1);
4494         }
4495     }
4496     return(0);
4497 }
4498
4499
4500 /**
4501  * xmlSchemaCompareReplacedStrings:
4502  * @x:  a first string value
4503  * @y:  a second string value
4504  *
4505  * Compare 2 string for their normalized values.
4506  *
4507  * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
4508  * case of error
4509  */
4510 static int
4511 xmlSchemaCompareReplacedStrings(const xmlChar *x,
4512                                 const xmlChar *y)
4513 {
4514     int tmp;
4515
4516     while ((*x != 0) && (*y != 0)) {
4517         if IS_WSP_BLANK_CH(*y) {
4518             if (! IS_WSP_BLANK_CH(*x)) {
4519                 if ((*x - 0x20) < 0)
4520                     return(-1);
4521                 else
4522                     return(1);
4523             }
4524         } else {
4525             if IS_WSP_BLANK_CH(*x) {
4526                 if ((0x20 - *y) < 0)
4527                     return(-1);
4528                 else
4529                     return(1);
4530             }
4531             tmp = *x - *y;
4532             if (tmp < 0)
4533                 return(-1);
4534             if (tmp > 0)
4535                 return(1);
4536         }
4537         x++;
4538         y++;
4539     }
4540     if (*x != 0)
4541         return(1);
4542     if (*y != 0)
4543         return(-1);
4544     return(0);
4545 }
4546
4547 /**
4548  * xmlSchemaCompareNormStrings:
4549  * @x:  a first string value
4550  * @y:  a second string value
4551  *
4552  * Compare 2 string for their normalized values.
4553  *
4554  * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
4555  * case of error
4556  */
4557 static int
4558 xmlSchemaCompareNormStrings(const xmlChar *x,
4559                             const xmlChar *y) {
4560     int tmp;
4561
4562     while (IS_BLANK_CH(*x)) x++;
4563     while (IS_BLANK_CH(*y)) y++;
4564     while ((*x != 0) && (*y != 0)) {
4565         if (IS_BLANK_CH(*x)) {
4566             if (!IS_BLANK_CH(*y)) {
4567                 tmp = *x - *y;
4568                 return(tmp);
4569             }
4570             while (IS_BLANK_CH(*x)) x++;
4571             while (IS_BLANK_CH(*y)) y++;
4572         } else {
4573             tmp = *x++ - *y++;
4574             if (tmp < 0)
4575                 return(-1);
4576             if (tmp > 0)
4577                 return(1);
4578         }
4579     }
4580     if (*x != 0) {
4581         while (IS_BLANK_CH(*x)) x++;
4582         if (*x != 0)
4583             return(1);
4584     }
4585     if (*y != 0) {
4586         while (IS_BLANK_CH(*y)) y++;
4587         if (*y != 0)
4588             return(-1);
4589     }
4590     return(0);
4591 }
4592
4593 /**
4594  * xmlSchemaCompareFloats:
4595  * @x:  a first float or double value
4596  * @y:  a second float or double value
4597  *
4598  * Compare 2 values
4599  *
4600  * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
4601  * case of error
4602  */
4603 static int
4604 xmlSchemaCompareFloats(xmlSchemaValPtr x, xmlSchemaValPtr y) {
4605     double d1, d2;
4606
4607     if ((x == NULL) || (y == NULL))
4608         return(-2);
4609
4610     /*
4611      * Cast everything to doubles.
4612      */
4613     if (x->type == XML_SCHEMAS_DOUBLE)
4614         d1 = x->value.d;
4615     else if (x->type == XML_SCHEMAS_FLOAT)
4616         d1 = x->value.f;
4617     else
4618         return(-2);
4619
4620     if (y->type == XML_SCHEMAS_DOUBLE)
4621         d2 = y->value.d;
4622     else if (y->type == XML_SCHEMAS_FLOAT)
4623         d2 = y->value.f;
4624     else
4625         return(-2);
4626
4627     /*
4628      * Check for special cases.
4629      */
4630     if (xmlXPathIsNaN(d1)) {
4631         if (xmlXPathIsNaN(d2))
4632             return(0);
4633         return(1);
4634     }
4635     if (xmlXPathIsNaN(d2))
4636         return(-1);
4637     if (d1 == xmlXPathPINF) {
4638         if (d2 == xmlXPathPINF)
4639             return(0);
4640         return(1);
4641     }
4642     if (d2 == xmlXPathPINF)
4643         return(-1);
4644     if (d1 == xmlXPathNINF) {
4645         if (d2 == xmlXPathNINF)
4646             return(0);
4647         return(-1);
4648     }
4649     if (d2 == xmlXPathNINF)
4650         return(1);
4651
4652     /*
4653      * basic tests, the last one we should have equality, but
4654      * portability is more important than speed and handling
4655      * NaN or Inf in a portable way is always a challenge, so ...
4656      */
4657     if (d1 < d2)
4658         return(-1);
4659     if (d1 > d2)
4660         return(1);
4661     if (d1 == d2)
4662         return(0);
4663     return(2);
4664 }
4665
4666 /**
4667  * xmlSchemaCompareValues:
4668  * @x:  a first value
4669  * @xvalue: the first value as a string (optional)
4670  * @xwtsp: the whitespace type
4671  * @y:  a second value
4672  * @xvalue: the second value as a string (optional)
4673  * @ywtsp: the whitespace type
4674  *
4675  * Compare 2 values
4676  *
4677  * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, 3 if not
4678  * comparable and -2 in case of error
4679  */
4680 static int
4681 xmlSchemaCompareValuesInternal(xmlSchemaValType xtype,
4682                                xmlSchemaValPtr x,
4683                                const xmlChar *xvalue,
4684                                xmlSchemaWhitespaceValueType xws,
4685                                xmlSchemaValType ytype,
4686                                xmlSchemaValPtr y,
4687                                const xmlChar *yvalue,
4688                                xmlSchemaWhitespaceValueType yws)
4689 {
4690     switch (xtype) {
4691         case XML_SCHEMAS_UNKNOWN:
4692         case XML_SCHEMAS_ANYTYPE:
4693             return(-2);
4694         case XML_SCHEMAS_INTEGER:
4695         case XML_SCHEMAS_NPINTEGER:
4696         case XML_SCHEMAS_NINTEGER:
4697         case XML_SCHEMAS_NNINTEGER:
4698         case XML_SCHEMAS_PINTEGER:
4699         case XML_SCHEMAS_INT:
4700         case XML_SCHEMAS_UINT:
4701         case XML_SCHEMAS_LONG:
4702         case XML_SCHEMAS_ULONG:
4703         case XML_SCHEMAS_SHORT:
4704         case XML_SCHEMAS_USHORT:
4705         case XML_SCHEMAS_BYTE:
4706         case XML_SCHEMAS_UBYTE:
4707         case XML_SCHEMAS_DECIMAL:
4708             if ((x == NULL) || (y == NULL))
4709                 return(-2);
4710             if (ytype == xtype)
4711                 return(xmlSchemaCompareDecimals(x, y));
4712             if ((ytype == XML_SCHEMAS_DECIMAL) ||
4713                 (ytype == XML_SCHEMAS_INTEGER) ||
4714                 (ytype == XML_SCHEMAS_NPINTEGER) ||
4715                 (ytype == XML_SCHEMAS_NINTEGER) ||
4716                 (ytype == XML_SCHEMAS_NNINTEGER) ||
4717                 (ytype == XML_SCHEMAS_PINTEGER) ||
4718                 (ytype == XML_SCHEMAS_INT) ||
4719                 (ytype == XML_SCHEMAS_UINT) ||
4720                 (ytype == XML_SCHEMAS_LONG) ||
4721                 (ytype == XML_SCHEMAS_ULONG) ||
4722                 (ytype == XML_SCHEMAS_SHORT) ||
4723                 (ytype == XML_SCHEMAS_USHORT) ||
4724                 (ytype == XML_SCHEMAS_BYTE) ||
4725                 (ytype == XML_SCHEMAS_UBYTE))
4726                 return(xmlSchemaCompareDecimals(x, y));
4727             return(-2);
4728         case XML_SCHEMAS_DURATION:
4729             if ((x == NULL) || (y == NULL))
4730                 return(-2);
4731             if (ytype == XML_SCHEMAS_DURATION)
4732                 return(xmlSchemaCompareDurations(x, y));
4733             return(-2);
4734         case XML_SCHEMAS_TIME:
4735         case XML_SCHEMAS_GDAY:
4736         case XML_SCHEMAS_GMONTH:
4737         case XML_SCHEMAS_GMONTHDAY:
4738         case XML_SCHEMAS_GYEAR:
4739         case XML_SCHEMAS_GYEARMONTH:
4740         case XML_SCHEMAS_DATE:
4741         case XML_SCHEMAS_DATETIME:
4742             if ((x == NULL) || (y == NULL))
4743                 return(-2);
4744             if ((ytype == XML_SCHEMAS_DATETIME)  ||
4745                 (ytype == XML_SCHEMAS_TIME)      ||
4746                 (ytype == XML_SCHEMAS_GDAY)      ||
4747                 (ytype == XML_SCHEMAS_GMONTH)    ||
4748                 (ytype == XML_SCHEMAS_GMONTHDAY) ||
4749                 (ytype == XML_SCHEMAS_GYEAR)     ||
4750                 (ytype == XML_SCHEMAS_DATE)      ||
4751                 (ytype == XML_SCHEMAS_GYEARMONTH))
4752                 return (xmlSchemaCompareDates(x, y));
4753             return (-2);
4754         /*
4755         * Note that we will support comparison of string types against
4756         * anySimpleType as well.
4757         */
4758         case XML_SCHEMAS_ANYSIMPLETYPE:
4759         case XML_SCHEMAS_STRING:
4760         case XML_SCHEMAS_NORMSTRING:
4761         case XML_SCHEMAS_TOKEN:
4762         case XML_SCHEMAS_LANGUAGE:
4763         case XML_SCHEMAS_NMTOKEN:
4764         case XML_SCHEMAS_NAME:
4765         case XML_SCHEMAS_NCNAME:
4766         case XML_SCHEMAS_ID:
4767         case XML_SCHEMAS_IDREF:
4768         case XML_SCHEMAS_ENTITY:
4769         case XML_SCHEMAS_ANYURI:
4770         {
4771             const xmlChar *xv, *yv;
4772
4773             if (x == NULL)
4774                 xv = xvalue;
4775             else
4776                 xv = x->value.str;
4777             if (y == NULL)
4778                 yv = yvalue;
4779             else
4780                 yv = y->value.str;
4781             /*
4782             * TODO: Compare those against QName.
4783             */
4784             if (ytype == XML_SCHEMAS_QNAME) {
4785                 TODO
4786                 if (y == NULL)
4787                     return(-2);
4788                 return (-2);
4789             }
4790             if ((ytype == XML_SCHEMAS_ANYSIMPLETYPE) ||
4791                 (ytype == XML_SCHEMAS_STRING) ||
4792                 (ytype == XML_SCHEMAS_NORMSTRING) ||
4793                 (ytype == XML_SCHEMAS_TOKEN) ||
4794                 (ytype == XML_SCHEMAS_LANGUAGE) ||
4795                 (ytype == XML_SCHEMAS_NMTOKEN) ||
4796                 (ytype == XML_SCHEMAS_NAME) ||
4797                 (ytype == XML_SCHEMAS_NCNAME) ||
4798                 (ytype == XML_SCHEMAS_ID) ||
4799                 (ytype == XML_SCHEMAS_IDREF) ||
4800                 (ytype == XML_SCHEMAS_ENTITY) ||
4801                 (ytype == XML_SCHEMAS_ANYURI)) {
4802
4803                 if (xws == XML_SCHEMA_WHITESPACE_PRESERVE) {
4804
4805                     if (yws == XML_SCHEMA_WHITESPACE_PRESERVE) {
4806                         /* TODO: What about x < y or x > y. */
4807                         if (xmlStrEqual(xv, yv))
4808                             return (0);
4809                         else
4810                             return (2);
4811                     } else if (yws == XML_SCHEMA_WHITESPACE_REPLACE)
4812                         return (xmlSchemaComparePreserveReplaceStrings(xv, yv, 0));
4813                     else if (yws == XML_SCHEMA_WHITESPACE_COLLAPSE)
4814                         return (xmlSchemaComparePreserveCollapseStrings(xv, yv, 0));
4815
4816                 } else if (xws == XML_SCHEMA_WHITESPACE_REPLACE) {
4817
4818                     if (yws == XML_SCHEMA_WHITESPACE_PRESERVE)
4819                         return (xmlSchemaComparePreserveReplaceStrings(yv, xv, 1));
4820                     if (yws == XML_SCHEMA_WHITESPACE_REPLACE)
4821                         return (xmlSchemaCompareReplacedStrings(xv, yv));
4822                     if (yws == XML_SCHEMA_WHITESPACE_COLLAPSE)
4823                         return (xmlSchemaCompareReplaceCollapseStrings(xv, yv, 0));
4824
4825                 } else if (xws == XML_SCHEMA_WHITESPACE_COLLAPSE) {
4826
4827                     if (yws == XML_SCHEMA_WHITESPACE_PRESERVE)
4828                         return (xmlSchemaComparePreserveCollapseStrings(yv, xv, 1));
4829                     if (yws == XML_SCHEMA_WHITESPACE_REPLACE)
4830                         return (xmlSchemaCompareReplaceCollapseStrings(yv, xv, 1));
4831                     if (yws == XML_SCHEMA_WHITESPACE_COLLAPSE)
4832                         return (xmlSchemaCompareNormStrings(xv, yv));
4833                 } else
4834                     return (-2);
4835
4836             }
4837             return (-2);
4838         }
4839         case XML_SCHEMAS_QNAME:
4840         case XML_SCHEMAS_NOTATION:
4841             if ((x == NULL) || (y == NULL))
4842                 return(-2);
4843             if ((ytype == XML_SCHEMAS_QNAME) ||
4844                 (ytype == XML_SCHEMAS_NOTATION)) {
4845                 if ((xmlStrEqual(x->value.qname.name, y->value.qname.name)) &&
4846                     (xmlStrEqual(x->value.qname.uri, y->value.qname.uri)))
4847                     return(0);
4848                 return(2);
4849             }
4850             return (-2);
4851         case XML_SCHEMAS_FLOAT:
4852         case XML_SCHEMAS_DOUBLE:
4853             if ((x == NULL) || (y == NULL))
4854                 return(-2);
4855             if ((ytype == XML_SCHEMAS_FLOAT) ||
4856                 (ytype == XML_SCHEMAS_DOUBLE))
4857                 return (xmlSchemaCompareFloats(x, y));
4858             return (-2);
4859         case XML_SCHEMAS_BOOLEAN:
4860             if ((x == NULL) || (y == NULL))
4861                 return(-2);
4862             if (ytype == XML_SCHEMAS_BOOLEAN) {
4863                 if (x->value.b == y->value.b)
4864                     return(0);
4865                 if (x->value.b == 0)
4866                     return(-1);
4867                 return(1);
4868             }
4869             return (-2);
4870         case XML_SCHEMAS_HEXBINARY:
4871             if ((x == NULL) || (y == NULL))
4872                 return(-2);
4873             if (ytype == XML_SCHEMAS_HEXBINARY) {
4874                 if (x->value.hex.total == y->value.hex.total) {
4875                     int ret = xmlStrcmp(x->value.hex.str, y->value.hex.str);
4876                     if (ret > 0)
4877                         return(1);
4878                     else if (ret == 0)
4879                         return(0);
4880                 }
4881                 else if (x->value.hex.total > y->value.hex.total)
4882                     return(1);
4883
4884                 return(-1);
4885             }
4886             return (-2);
4887         case XML_SCHEMAS_BASE64BINARY:
4888             if ((x == NULL) || (y == NULL))
4889                 return(-2);
4890             if (ytype == XML_SCHEMAS_BASE64BINARY) {
4891                 if (x->value.base64.total == y->value.base64.total) {
4892                     int ret = xmlStrcmp(x->value.base64.str,
4893                                         y->value.base64.str);
4894                     if (ret > 0)
4895                         return(1);
4896                     else if (ret == 0)
4897                         return(0);
4898                     else
4899                         return(-1);
4900                 }
4901                 else if (x->value.base64.total > y->value.base64.total)
4902                     return(1);
4903                 else
4904                     return(-1);
4905             }
4906             return (-2);
4907         case XML_SCHEMAS_IDREFS:
4908         case XML_SCHEMAS_ENTITIES:
4909         case XML_SCHEMAS_NMTOKENS:
4910             TODO
4911             break;
4912     }
4913     return -2;
4914 }
4915
4916 /**
4917  * xmlSchemaCompareValues:
4918  * @x:  a first value
4919  * @y:  a second value
4920  *
4921  * Compare 2 values
4922  *
4923  * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
4924  * case of error
4925  */
4926 int
4927 xmlSchemaCompareValues(xmlSchemaValPtr x, xmlSchemaValPtr y) {
4928     xmlSchemaWhitespaceValueType xws, yws;
4929
4930     if ((x == NULL) || (y == NULL))
4931         return(-2);
4932     if (x->type == XML_SCHEMAS_STRING)
4933         xws = XML_SCHEMA_WHITESPACE_PRESERVE;
4934     else if (x->type == XML_SCHEMAS_NORMSTRING)
4935         xws = XML_SCHEMA_WHITESPACE_REPLACE;
4936     else
4937         xws = XML_SCHEMA_WHITESPACE_COLLAPSE;
4938
4939     if (y->type == XML_SCHEMAS_STRING)
4940         yws = XML_SCHEMA_WHITESPACE_PRESERVE;
4941     else if (y->type == XML_SCHEMAS_NORMSTRING)
4942         yws = XML_SCHEMA_WHITESPACE_REPLACE;
4943     else
4944         yws = XML_SCHEMA_WHITESPACE_COLLAPSE;
4945
4946     return(xmlSchemaCompareValuesInternal(x->type, x, NULL, xws, y->type,
4947         y, NULL, yws));
4948 }
4949
4950 /**
4951  * xmlSchemaCompareValuesWhtsp:
4952  * @x:  a first value
4953  * @xws: the whitespace value of x
4954  * @y:  a second value
4955  * @yws: the whitespace value of y
4956  *
4957  * Compare 2 values
4958  *
4959  * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
4960  * case of error
4961  */
4962 int
4963 xmlSchemaCompareValuesWhtsp(xmlSchemaValPtr x,
4964                             xmlSchemaWhitespaceValueType xws,
4965                             xmlSchemaValPtr y,
4966                             xmlSchemaWhitespaceValueType yws)
4967 {
4968     if ((x == NULL) || (y == NULL))
4969         return(-2);
4970     return(xmlSchemaCompareValuesInternal(x->type, x, NULL, xws, y->type,
4971         y, NULL, yws));
4972 }
4973
4974 /**
4975  * xmlSchemaCompareValuesWhtspExt:
4976  * @x:  a first value
4977  * @xws: the whitespace value of x
4978  * @y:  a second value
4979  * @yws: the whitespace value of y
4980  *
4981  * Compare 2 values
4982  *
4983  * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
4984  * case of error
4985  */
4986 static int
4987 xmlSchemaCompareValuesWhtspExt(xmlSchemaValType xtype,
4988                                xmlSchemaValPtr x,
4989                                const xmlChar *xvalue,
4990                                xmlSchemaWhitespaceValueType xws,
4991                                xmlSchemaValType ytype,
4992                                xmlSchemaValPtr y,
4993                                const xmlChar *yvalue,
4994                                xmlSchemaWhitespaceValueType yws)
4995 {
4996     return(xmlSchemaCompareValuesInternal(xtype, x, xvalue, xws, ytype, y,
4997         yvalue, yws));
4998 }
4999
5000 /**
5001  * xmlSchemaNormLen:
5002  * @value:  a string
5003  *
5004  * Computes the UTF8 length of the normalized value of the string
5005  *
5006  * Returns the length or -1 in case of error.
5007  */
5008 static int
5009 xmlSchemaNormLen(const xmlChar *value) {
5010     const xmlChar *utf;
5011     int ret = 0;
5012
5013     if (value == NULL)
5014         return(-1);
5015     utf = value;
5016     while (IS_BLANK_CH(*utf)) utf++;
5017     while (*utf != 0) {
5018         if (utf[0] & 0x80) {
5019             if ((utf[1] & 0xc0) != 0x80)
5020                 return(-1);
5021             if ((utf[0] & 0xe0) == 0xe0) {
5022                 if ((utf[2] & 0xc0) != 0x80)
5023                     return(-1);
5024                 if ((utf[0] & 0xf0) == 0xf0) {
5025                     if ((utf[0] & 0xf8) != 0xf0 || (utf[3] & 0xc0) != 0x80)
5026                         return(-1);
5027                     utf += 4;
5028                 } else {
5029                     utf += 3;
5030                 }
5031             } else {
5032                 utf += 2;
5033             }
5034         } else if (IS_BLANK_CH(*utf)) {
5035             while (IS_BLANK_CH(*utf)) utf++;
5036             if (*utf == 0)
5037                 break;
5038         } else {
5039             utf++;
5040         }
5041         ret++;
5042     }
5043     return(ret);
5044 }
5045
5046 /**
5047  * xmlSchemaGetFacetValueAsULong:
5048  * @facet: an schemas type facet
5049  *
5050  * Extract the value of a facet
5051  *
5052  * Returns the value as a long
5053  */
5054 unsigned long
5055 xmlSchemaGetFacetValueAsULong(xmlSchemaFacetPtr facet)
5056 {
5057     /*
5058     * TODO: Check if this is a decimal.
5059     */
5060     if (facet == NULL)
5061         return 0;
5062     return ((unsigned long) facet->val->value.decimal.lo);
5063 }
5064
5065 /**
5066  * xmlSchemaValidateListSimpleTypeFacet:
5067  * @facet:  the facet to check
5068  * @value:  the lexical repr of the value to validate
5069  * @actualLen:  the number of list items
5070  * @expectedLen: the resulting expected number of list items
5071  *
5072  * Checks the value of a list simple type against a facet.
5073  *
5074  * Returns 0 if the value is valid, a positive error code
5075  * number otherwise and -1 in case of an internal error.
5076  */
5077 int
5078 xmlSchemaValidateListSimpleTypeFacet(xmlSchemaFacetPtr facet,
5079                                      const xmlChar *value,
5080                                      unsigned long actualLen,
5081                                      unsigned long *expectedLen)
5082 {
5083     if (facet == NULL)
5084         return(-1);
5085     /*
5086     * TODO: Check if this will work with large numbers.
5087     * (compare value.decimal.mi and value.decimal.hi as well?).
5088     */
5089     if (facet->type == XML_SCHEMA_FACET_LENGTH) {
5090         if (actualLen != facet->val->value.decimal.lo) {
5091             if (expectedLen != NULL)
5092                 *expectedLen = facet->val->value.decimal.lo;
5093             return (XML_SCHEMAV_CVC_LENGTH_VALID);
5094         }
5095     } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
5096         if (actualLen < facet->val->value.decimal.lo) {
5097             if (expectedLen != NULL)
5098                 *expectedLen = facet->val->value.decimal.lo;
5099             return (XML_SCHEMAV_CVC_MINLENGTH_VALID);
5100         }
5101     } else if (facet->type == XML_SCHEMA_FACET_MAXLENGTH) {
5102         if (actualLen > facet->val->value.decimal.lo) {
5103             if (expectedLen != NULL)
5104                 *expectedLen = facet->val->value.decimal.lo;
5105             return (XML_SCHEMAV_CVC_MAXLENGTH_VALID);
5106         }
5107     } else
5108         /*
5109         * NOTE: That we can pass NULL as xmlSchemaValPtr to
5110         * xmlSchemaValidateFacet, since the remaining facet types
5111         * are: XML_SCHEMA_FACET_PATTERN, XML_SCHEMA_FACET_ENUMERATION.
5112         */
5113         return(xmlSchemaValidateFacet(NULL, facet, value, NULL));
5114     return (0);
5115 }
5116
5117 /**
5118  * xmlSchemaValidateLengthFacet:
5119  * @type:  the built-in type
5120  * @facet:  the facet to check
5121  * @value:  the lexical repr. of the value to be validated
5122  * @val:  the precomputed value
5123  * @ws: the whitespace type of the value
5124  * @length: the actual length of the value
5125  *
5126  * Checka a value against a "length", "minLength" and "maxLength"
5127  * facet; sets @length to the computed length of @value.
5128  *
5129  * Returns 0 if the value is valid, a positive error code
5130  * otherwise and -1 in case of an internal or API error.
5131  */
5132 static int
5133 xmlSchemaValidateLengthFacetInternal(xmlSchemaFacetPtr facet,
5134                                      xmlSchemaValType valType,
5135                                      const xmlChar *value,
5136                                      xmlSchemaValPtr val,
5137                                      unsigned long *length,
5138                                      xmlSchemaWhitespaceValueType ws)
5139 {
5140     unsigned int len = 0;
5141
5142     if ((length == NULL) || (facet == NULL))
5143         return (-1);
5144     *length = 0;
5145     if ((facet->type != XML_SCHEMA_FACET_LENGTH) &&
5146         (facet->type != XML_SCHEMA_FACET_MAXLENGTH) &&
5147         (facet->type != XML_SCHEMA_FACET_MINLENGTH))
5148         return (-1);
5149
5150     /*
5151     * TODO: length, maxLength and minLength must be of type
5152     * nonNegativeInteger only. Check if decimal is used somehow.
5153     */
5154     if ((facet->val == NULL) ||
5155         ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
5156          (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
5157         (facet->val->value.decimal.frac != 0)) {
5158         return(-1);
5159     }
5160     if ((val != NULL) && (val->type == XML_SCHEMAS_HEXBINARY))
5161         len = val->value.hex.total;
5162     else if ((val != NULL) && (val->type == XML_SCHEMAS_BASE64BINARY))
5163         len = val->value.base64.total;
5164     else {
5165         switch (valType) {
5166             case XML_SCHEMAS_STRING:
5167             case XML_SCHEMAS_NORMSTRING:
5168                 if (ws == XML_SCHEMA_WHITESPACE_UNKNOWN) {
5169                     /*
5170                     * This is to ensure API compatibility with the old
5171                     * xmlSchemaValidateLengthFacet(). Anyway, this was and
5172                     * is not the correct handling.
5173                     * TODO: Get rid of this case somehow.
5174                     */
5175                     if (valType == XML_SCHEMAS_STRING)
5176                         len = xmlUTF8Strlen(value);
5177                     else
5178                         len = xmlSchemaNormLen(value);
5179                 } else if (value != NULL) {
5180                     if (ws == XML_SCHEMA_WHITESPACE_COLLAPSE)
5181                         len = xmlSchemaNormLen(value);
5182                     else
5183                     /*
5184                     * Should be OK for "preserve" as well.
5185                     */
5186                     len = xmlUTF8Strlen(value);
5187                 }
5188                 break;
5189             case XML_SCHEMAS_IDREF:
5190             case XML_SCHEMAS_TOKEN:
5191             case XML_SCHEMAS_LANGUAGE:
5192             case XML_SCHEMAS_NMTOKEN:
5193             case XML_SCHEMAS_NAME:
5194             case XML_SCHEMAS_NCNAME:
5195             case XML_SCHEMAS_ID:
5196                 /*
5197                 * FIXME: What exactly to do with anyURI?
5198                 */
5199             case XML_SCHEMAS_ANYURI:
5200                 if (value != NULL)
5201                     len = xmlSchemaNormLen(value);
5202                 break;
5203             case XML_SCHEMAS_QNAME:
5204             case XML_SCHEMAS_NOTATION:
5205                 /*
5206                 * For QName and NOTATION, those facets are
5207                 * deprecated and should be ignored.
5208                 */
5209                 return (0);
5210             default:
5211                 TODO
5212         }
5213     }
5214     *length = (unsigned long) len;
5215     /*
5216     * TODO: Return the whole expected value, i.e. "lo", "mi" and "hi".
5217     */
5218     if (facet->type == XML_SCHEMA_FACET_LENGTH) {
5219         if (len != facet->val->value.decimal.lo)
5220             return(XML_SCHEMAV_CVC_LENGTH_VALID);
5221     } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
5222         if (len < facet->val->value.decimal.lo)
5223             return(XML_SCHEMAV_CVC_MINLENGTH_VALID);
5224     } else {
5225         if (len > facet->val->value.decimal.lo)
5226             return(XML_SCHEMAV_CVC_MAXLENGTH_VALID);
5227     }
5228
5229     return (0);
5230 }
5231
5232 /**
5233  * xmlSchemaValidateLengthFacet:
5234  * @type:  the built-in type
5235  * @facet:  the facet to check
5236  * @value:  the lexical repr. of the value to be validated
5237  * @val:  the precomputed value
5238  * @length: the actual length of the value
5239  *
5240  * Checka a value against a "length", "minLength" and "maxLength"
5241  * facet; sets @length to the computed length of @value.
5242  *
5243  * Returns 0 if the value is valid, a positive error code
5244  * otherwise and -1 in case of an internal or API error.
5245  */
5246 int
5247 xmlSchemaValidateLengthFacet(xmlSchemaTypePtr type,
5248                              xmlSchemaFacetPtr facet,
5249                              const xmlChar *value,
5250                              xmlSchemaValPtr val,
5251                              unsigned long *length)
5252 {
5253     if (type == NULL)
5254         return(-1);
5255     return (xmlSchemaValidateLengthFacetInternal(facet,
5256         type->builtInType, value, val, length,
5257         XML_SCHEMA_WHITESPACE_UNKNOWN));
5258 }
5259
5260 /**
5261  * xmlSchemaValidateLengthFacetWhtsp:
5262  * @facet:  the facet to check
5263  * @valType:  the built-in type
5264  * @value:  the lexical repr. of the value to be validated
5265  * @val:  the precomputed value
5266  * @ws: the whitespace type of the value
5267  * @length: the actual length of the value
5268  *
5269  * Checka a value against a "length", "minLength" and "maxLength"
5270  * facet; sets @length to the computed length of @value.
5271  *
5272  * Returns 0 if the value is valid, a positive error code
5273  * otherwise and -1 in case of an internal or API error.
5274  */
5275 int
5276 xmlSchemaValidateLengthFacetWhtsp(xmlSchemaFacetPtr facet,
5277                                   xmlSchemaValType valType,
5278                                   const xmlChar *value,
5279                                   xmlSchemaValPtr val,
5280                                   unsigned long *length,
5281                                   xmlSchemaWhitespaceValueType ws)
5282 {
5283     return (xmlSchemaValidateLengthFacetInternal(facet, valType, value, val,
5284         length, ws));
5285 }
5286
5287 /**
5288  * xmlSchemaValidateFacetInternal:
5289  * @facet:  the facet to check
5290  * @fws: the whitespace type of the facet's value
5291  * @valType: the built-in type of the value
5292  * @value:  the lexical repr of the value to validate
5293  * @val:  the precomputed value
5294  * @ws: the whitespace type of the value
5295  *
5296  * Check a value against a facet condition
5297  *
5298  * Returns 0 if the element is schemas valid, a positive error code
5299  *     number otherwise and -1 in case of internal or API error.
5300  */
5301 static int
5302 xmlSchemaValidateFacetInternal(xmlSchemaFacetPtr facet,
5303                                xmlSchemaWhitespaceValueType fws,
5304                                xmlSchemaValType valType,
5305                                const xmlChar *value,
5306                                xmlSchemaValPtr val,
5307                                xmlSchemaWhitespaceValueType ws)
5308 {
5309     int ret;
5310     int stringType;
5311
5312     if (facet == NULL)
5313         return(-1);
5314
5315     switch (facet->type) {
5316         case XML_SCHEMA_FACET_PATTERN:
5317             /*
5318             * NOTE that for patterns, the @value needs to be the normalized
5319             * value, *not* the lexical initial value or the canonical value.
5320             */
5321             if (value == NULL)
5322                 return(-1);
5323             /*
5324             * If string-derived type, regexp must be tested on the value space of
5325             * the datatype.
5326             * See https://www.w3.org/TR/xmlschema-2/#rf-pattern
5327             */
5328             stringType = val && ((val->type >= XML_SCHEMAS_STRING && val->type <= XML_SCHEMAS_NORMSTRING)
5329                               || (val->type >= XML_SCHEMAS_TOKEN && val->type <= XML_SCHEMAS_NCNAME));
5330             ret = xmlRegexpExec(facet->regexp,
5331                                 (stringType && val->value.str) ? val->value.str : value);
5332             if (ret == 1)
5333                 return(0);
5334             if (ret == 0)
5335                 return(XML_SCHEMAV_CVC_PATTERN_VALID);
5336             return(ret);
5337         case XML_SCHEMA_FACET_MAXEXCLUSIVE:
5338             ret = xmlSchemaCompareValues(val, facet->val);
5339             if (ret == -2)
5340                 return(-1);
5341             if (ret == -1)
5342                 return(0);
5343             return(XML_SCHEMAV_CVC_MAXEXCLUSIVE_VALID);
5344         case XML_SCHEMA_FACET_MAXINCLUSIVE:
5345             ret = xmlSchemaCompareValues(val, facet->val);
5346             if (ret == -2)
5347                 return(-1);
5348             if ((ret == -1) || (ret == 0))
5349                 return(0);
5350             return(XML_SCHEMAV_CVC_MAXINCLUSIVE_VALID);
5351         case XML_SCHEMA_FACET_MINEXCLUSIVE:
5352             ret = xmlSchemaCompareValues(val, facet->val);
5353             if (ret == -2)
5354                 return(-1);
5355             if (ret == 1)
5356                 return(0);
5357             return(XML_SCHEMAV_CVC_MINEXCLUSIVE_VALID);
5358         case XML_SCHEMA_FACET_MININCLUSIVE:
5359             ret = xmlSchemaCompareValues(val, facet->val);
5360             if (ret == -2)
5361                 return(-1);
5362             if ((ret == 1) || (ret == 0))
5363                 return(0);
5364             return(XML_SCHEMAV_CVC_MININCLUSIVE_VALID);
5365         case XML_SCHEMA_FACET_WHITESPACE:
5366             /* TODO whitespaces */
5367             /*
5368             * NOTE: Whitespace should be handled to normalize
5369             * the value to be validated against a the facets;
5370             * not to normalize the value in-between.
5371             */
5372             return(0);
5373         case  XML_SCHEMA_FACET_ENUMERATION:
5374             if (ws == XML_SCHEMA_WHITESPACE_UNKNOWN) {
5375                 /*
5376                 * This is to ensure API compatibility with the old
5377                 * xmlSchemaValidateFacet().
5378                 * TODO: Get rid of this case.
5379                 */
5380                 if ((facet->value != NULL) &&
5381                     (xmlStrEqual(facet->value, value)))
5382                     return(0);
5383             } else {
5384                 ret = xmlSchemaCompareValuesWhtspExt(facet->val->type,
5385                     facet->val, facet->value, fws, valType, val,
5386                     value, ws);
5387                 if (ret == -2)
5388                     return(-1);
5389                 if (ret == 0)
5390                     return(0);
5391             }
5392             return(XML_SCHEMAV_CVC_ENUMERATION_VALID);
5393         case XML_SCHEMA_FACET_LENGTH:
5394             /*
5395             * SPEC (1.3) "if {primitive type definition} is QName or NOTATION,
5396             * then any {value} is facet-valid."
5397             */
5398             if ((valType == XML_SCHEMAS_QNAME) ||
5399                 (valType == XML_SCHEMAS_NOTATION))
5400                 return (0);
5401             /* No break on purpose. */
5402         case XML_SCHEMA_FACET_MAXLENGTH:
5403         case XML_SCHEMA_FACET_MINLENGTH: {
5404             unsigned int len = 0;
5405
5406             if ((valType == XML_SCHEMAS_QNAME) ||
5407                 (valType == XML_SCHEMAS_NOTATION))
5408                 return (0);
5409             /*
5410             * TODO: length, maxLength and minLength must be of type
5411             * nonNegativeInteger only. Check if decimal is used somehow.
5412             */
5413             if ((facet->val == NULL) ||
5414                 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
5415                  (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
5416                 (facet->val->value.decimal.frac != 0)) {
5417                 return(-1);
5418             }
5419             if ((val != NULL) && (val->type == XML_SCHEMAS_HEXBINARY))
5420                 len = val->value.hex.total;
5421             else if ((val != NULL) && (val->type == XML_SCHEMAS_BASE64BINARY))
5422                 len = val->value.base64.total;
5423             else {
5424                 switch (valType) {
5425                     case XML_SCHEMAS_STRING:
5426                     case XML_SCHEMAS_NORMSTRING:
5427                         if (ws == XML_SCHEMA_WHITESPACE_UNKNOWN) {
5428                             /*
5429                             * This is to ensure API compatibility with the old
5430                             * xmlSchemaValidateFacet(). Anyway, this was and
5431                             * is not the correct handling.
5432                             * TODO: Get rid of this case somehow.
5433                             */
5434                             if (valType == XML_SCHEMAS_STRING)
5435                                 len = xmlUTF8Strlen(value);
5436                             else
5437                                 len = xmlSchemaNormLen(value);
5438                         } else if (value != NULL) {
5439                             if (ws == XML_SCHEMA_WHITESPACE_COLLAPSE)
5440                                 len = xmlSchemaNormLen(value);
5441                             else
5442                                 /*
5443                                 * Should be OK for "preserve" as well.
5444                                 */
5445                                 len = xmlUTF8Strlen(value);
5446                         }
5447                         break;
5448                     case XML_SCHEMAS_IDREF:
5449                     case XML_SCHEMAS_TOKEN:
5450                     case XML_SCHEMAS_LANGUAGE:
5451                     case XML_SCHEMAS_NMTOKEN:
5452                     case XML_SCHEMAS_NAME:
5453                     case XML_SCHEMAS_NCNAME:
5454                     case XML_SCHEMAS_ID:
5455                     case XML_SCHEMAS_ANYURI:
5456                         if (value != NULL)
5457                             len = xmlSchemaNormLen(value);
5458                         break;
5459                     default:
5460                         TODO
5461                 }
5462             }
5463             if (facet->type == XML_SCHEMA_FACET_LENGTH) {
5464                 if (len != facet->val->value.decimal.lo)
5465                     return(XML_SCHEMAV_CVC_LENGTH_VALID);
5466             } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
5467                 if (len < facet->val->value.decimal.lo)
5468                     return(XML_SCHEMAV_CVC_MINLENGTH_VALID);
5469             } else {
5470                 if (len > facet->val->value.decimal.lo)
5471                     return(XML_SCHEMAV_CVC_MAXLENGTH_VALID);
5472             }
5473             break;
5474         }
5475         case XML_SCHEMA_FACET_TOTALDIGITS:
5476         case XML_SCHEMA_FACET_FRACTIONDIGITS:
5477
5478             if ((facet->val == NULL) ||
5479                 ((facet->val->type != XML_SCHEMAS_PINTEGER) &&
5480                  (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
5481                 (facet->val->value.decimal.frac != 0)) {
5482                 return(-1);
5483             }
5484             if ((val == NULL) ||
5485                 ((val->type != XML_SCHEMAS_DECIMAL) &&
5486                  (val->type != XML_SCHEMAS_INTEGER) &&
5487                  (val->type != XML_SCHEMAS_NPINTEGER) &&
5488                  (val->type != XML_SCHEMAS_NINTEGER) &&
5489                  (val->type != XML_SCHEMAS_NNINTEGER) &&
5490                  (val->type != XML_SCHEMAS_PINTEGER) &&
5491                  (val->type != XML_SCHEMAS_INT) &&
5492                  (val->type != XML_SCHEMAS_UINT) &&
5493                  (val->type != XML_SCHEMAS_LONG) &&
5494                  (val->type != XML_SCHEMAS_ULONG) &&
5495                  (val->type != XML_SCHEMAS_SHORT) &&
5496                  (val->type != XML_SCHEMAS_USHORT) &&
5497                  (val->type != XML_SCHEMAS_BYTE) &&
5498                  (val->type != XML_SCHEMAS_UBYTE))) {
5499                 return(-1);
5500             }
5501             if (facet->type == XML_SCHEMA_FACET_TOTALDIGITS) {
5502                 if (val->value.decimal.total > facet->val->value.decimal.lo)
5503                     return(XML_SCHEMAV_CVC_TOTALDIGITS_VALID);
5504
5505             } else if (facet->type == XML_SCHEMA_FACET_FRACTIONDIGITS) {
5506                 if (val->value.decimal.frac > facet->val->value.decimal.lo)
5507                     return(XML_SCHEMAV_CVC_FRACTIONDIGITS_VALID);
5508             }
5509             break;
5510         default:
5511             TODO
5512     }
5513     return(0);
5514
5515 }
5516
5517 /**
5518  * xmlSchemaValidateFacet:
5519  * @base:  the base type
5520  * @facet:  the facet to check
5521  * @value:  the lexical repr of the value to validate
5522  * @val:  the precomputed value
5523  *
5524  * Check a value against a facet condition
5525  *
5526  * Returns 0 if the element is schemas valid, a positive error code
5527  *     number otherwise and -1 in case of internal or API error.
5528  */
5529 int
5530 xmlSchemaValidateFacet(xmlSchemaTypePtr base,
5531                        xmlSchemaFacetPtr facet,
5532                        const xmlChar *value,
5533                        xmlSchemaValPtr val)
5534 {
5535     /*
5536     * This tries to ensure API compatibility regarding the old
5537     * xmlSchemaValidateFacet() and the new xmlSchemaValidateFacetInternal() and
5538     * xmlSchemaValidateFacetWhtsp().
5539     */
5540     if (val != NULL)
5541         return(xmlSchemaValidateFacetInternal(facet,
5542             XML_SCHEMA_WHITESPACE_UNKNOWN, val->type, value, val,
5543             XML_SCHEMA_WHITESPACE_UNKNOWN));
5544     else if (base != NULL)
5545         return(xmlSchemaValidateFacetInternal(facet,
5546             XML_SCHEMA_WHITESPACE_UNKNOWN, base->builtInType, value, val,
5547             XML_SCHEMA_WHITESPACE_UNKNOWN));
5548     return(-1);
5549 }
5550
5551 /**
5552  * xmlSchemaValidateFacetWhtsp:
5553  * @facet:  the facet to check
5554  * @fws: the whitespace type of the facet's value
5555  * @valType: the built-in type of the value
5556  * @value:  the lexical (or normalized for pattern) repr of the value to validate
5557  * @val:  the precomputed value
5558  * @ws: the whitespace type of the value
5559  *
5560  * Check a value against a facet condition. This takes value normalization
5561  * according to the specified whitespace types into account.
5562  * Note that @value needs to be the *normalized* value if the facet
5563  * is of type "pattern".
5564  *
5565  * Returns 0 if the element is schemas valid, a positive error code
5566  *     number otherwise and -1 in case of internal or API error.
5567  */
5568 int
5569 xmlSchemaValidateFacetWhtsp(xmlSchemaFacetPtr facet,
5570                             xmlSchemaWhitespaceValueType fws,
5571                             xmlSchemaValType valType,
5572                             const xmlChar *value,
5573                             xmlSchemaValPtr val,
5574                             xmlSchemaWhitespaceValueType ws)
5575 {
5576      return(xmlSchemaValidateFacetInternal(facet, fws, valType,
5577          value, val, ws));
5578 }
5579
5580 #if 0
5581 #ifndef DBL_DIG
5582 #define DBL_DIG 16
5583 #endif
5584 #ifndef DBL_EPSILON
5585 #define DBL_EPSILON 1E-9
5586 #endif
5587
5588 #define INTEGER_DIGITS DBL_DIG
5589 #define FRACTION_DIGITS (DBL_DIG + 1)
5590 #define EXPONENT_DIGITS (3 + 2)
5591
5592 /**
5593  * xmlXPathFormatNumber:
5594  * @number:     number to format
5595  * @buffer:     output buffer
5596  * @buffersize: size of output buffer
5597  *
5598  * Convert the number into a string representation.
5599  */
5600 static void
5601 xmlSchemaFormatFloat(double number, char buffer[], int buffersize)
5602 {
5603     switch (xmlXPathIsInf(number)) {
5604     case 1:
5605         if (buffersize > (int)sizeof("INF"))
5606             snprintf(buffer, buffersize, "INF");
5607         break;
5608     case -1:
5609         if (buffersize > (int)sizeof("-INF"))
5610             snprintf(buffer, buffersize, "-INF");
5611         break;
5612     default:
5613         if (xmlXPathIsNaN(number)) {
5614             if (buffersize > (int)sizeof("NaN"))
5615                 snprintf(buffer, buffersize, "NaN");
5616         } else if (number == 0) {
5617             snprintf(buffer, buffersize, "0.0E0");
5618         } else {
5619             /* 3 is sign, decimal point, and terminating zero */
5620             char work[DBL_DIG + EXPONENT_DIGITS + 3];
5621             int integer_place, fraction_place;
5622             char *ptr;
5623             char *after_fraction;
5624             double absolute_value;
5625             int size;
5626
5627             absolute_value = fabs(number);
5628
5629             /*
5630              * Result is in work, and after_fraction points
5631              * just past the fractional part.
5632              * Use scientific notation
5633             */
5634             integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
5635             fraction_place = DBL_DIG - 1;
5636             snprintf(work, sizeof(work),"%*.*e",
5637                 integer_place, fraction_place, number);
5638             after_fraction = strchr(work + DBL_DIG, 'e');
5639             /* Remove fractional trailing zeroes */
5640             ptr = after_fraction;
5641             while (*(--ptr) == '0')
5642                 ;
5643             if (*ptr != '.')
5644                 ptr++;
5645             while ((*ptr++ = *after_fraction++) != 0);
5646
5647             /* Finally copy result back to caller */
5648             size = strlen(work) + 1;
5649             if (size > buffersize) {
5650                 work[buffersize - 1] = 0;
5651                 size = buffersize;
5652             }
5653             memmove(buffer, work, size);
5654         }
5655         break;
5656     }
5657 }
5658 #endif
5659
5660 /**
5661  * xmlSchemaGetCanonValue:
5662  * @val: the precomputed value
5663  * @retValue: the returned value
5664  *
5665  * Get the canonical lexical representation of the value.
5666  * The caller has to FREE the returned retValue.
5667  *
5668  * WARNING: Some value types are not supported yet, resulting
5669  * in a @retValue of "???".
5670  *
5671  * TODO: XML Schema 1.0 does not define canonical representations
5672  * for: duration, gYearMonth, gYear, gMonthDay, gMonth, gDay,
5673  * anyURI, QName, NOTATION. This will be fixed in XML Schema 1.1.
5674  *
5675  *
5676  * Returns 0 if the value could be built, 1 if the value type is
5677  * not supported yet and -1 in case of API errors.
5678  */
5679 int
5680 xmlSchemaGetCanonValue(xmlSchemaValPtr val, const xmlChar **retValue)
5681 {
5682     if ((retValue == NULL) || (val == NULL))
5683         return (-1);
5684     *retValue = NULL;
5685     switch (val->type) {
5686         case XML_SCHEMAS_STRING:
5687             if (val->value.str == NULL)
5688                 *retValue = BAD_CAST xmlStrdup(BAD_CAST "");
5689             else
5690                 *retValue =
5691                     BAD_CAST xmlStrdup((const xmlChar *) val->value.str);
5692             break;
5693         case XML_SCHEMAS_NORMSTRING:
5694             if (val->value.str == NULL)
5695                 *retValue = BAD_CAST xmlStrdup(BAD_CAST "");
5696             else {
5697                 *retValue = xmlSchemaWhiteSpaceReplace(
5698                     (const xmlChar *) val->value.str);
5699                 if ((*retValue) == NULL)
5700                     *retValue = BAD_CAST xmlStrdup(
5701                         (const xmlChar *) val->value.str);
5702             }
5703             break;
5704         case XML_SCHEMAS_TOKEN:
5705         case XML_SCHEMAS_LANGUAGE:
5706         case XML_SCHEMAS_NMTOKEN:
5707         case XML_SCHEMAS_NAME:
5708         case XML_SCHEMAS_NCNAME:
5709         case XML_SCHEMAS_ID:
5710         case XML_SCHEMAS_IDREF:
5711         case XML_SCHEMAS_ENTITY:
5712         case XML_SCHEMAS_NOTATION: /* Unclear */
5713         case XML_SCHEMAS_ANYURI:   /* Unclear */
5714             if (val->value.str == NULL)
5715                 return (-1);
5716             *retValue =
5717                 BAD_CAST xmlSchemaCollapseString(BAD_CAST val->value.str);
5718             if (*retValue == NULL)
5719                 *retValue =
5720                     BAD_CAST xmlStrdup((const xmlChar *) val->value.str);
5721             break;
5722         case XML_SCHEMAS_QNAME:
5723             /* TODO: Unclear in XML Schema 1.0. */
5724             if (val->value.qname.uri == NULL) {
5725                 *retValue = BAD_CAST xmlStrdup(BAD_CAST val->value.qname.name);
5726                 return (0);
5727             } else {
5728                 *retValue = BAD_CAST xmlStrdup(BAD_CAST "{");
5729                 *retValue = BAD_CAST xmlStrcat((xmlChar *) (*retValue),
5730                     BAD_CAST val->value.qname.uri);
5731                 *retValue = BAD_CAST xmlStrcat((xmlChar *) (*retValue),
5732                     BAD_CAST "}");
5733                 *retValue = BAD_CAST xmlStrcat((xmlChar *) (*retValue),
5734                     BAD_CAST val->value.qname.uri);
5735             }
5736             break;
5737         case XML_SCHEMAS_DECIMAL:
5738             /*
5739             * TODO: Lookout for a more simple implementation.
5740             */
5741             if ((val->value.decimal.total == 1) &&
5742                 (val->value.decimal.lo == 0)) {
5743                 *retValue = xmlStrdup(BAD_CAST "0.0");
5744             } else {
5745                 xmlSchemaValDecimal dec = val->value.decimal;
5746                 int bufsize;
5747                 char *buf = NULL, *offs;
5748
5749                 /* Add room for the decimal point as well. */
5750                 bufsize = dec.total + 2;
5751                 if (dec.sign)
5752                     bufsize++;
5753                 /* Add room for leading/trailing zero. */
5754                 if ((dec.frac == 0) || (dec.frac == dec.total))
5755                     bufsize++;
5756                 buf = xmlMalloc(bufsize);
5757                 if (buf == NULL)
5758                     return(-1);
5759                 offs = buf;
5760                 if (dec.sign)
5761                     *offs++ = '-';
5762                 if (dec.frac == dec.total) {
5763                     *offs++ = '0';
5764                     *offs++ = '.';
5765                 }
5766                 if (dec.hi != 0)
5767                     snprintf(offs, bufsize - (offs - buf),
5768                         "%lu%lu%lu", dec.hi, dec.mi, dec.lo);
5769                 else if (dec.mi != 0)
5770                     snprintf(offs, bufsize - (offs - buf),
5771                         "%lu%lu", dec.mi, dec.lo);
5772                 else
5773                     snprintf(offs, bufsize - (offs - buf),
5774                         "%lu", dec.lo);
5775
5776                 if (dec.frac != 0) {
5777                     if (dec.frac != dec.total) {
5778                         int diff = dec.total - dec.frac;
5779                         /*
5780                         * Insert the decimal point.
5781                         */
5782                         memmove(offs + diff + 1, offs + diff, dec.frac +1);
5783                         offs[diff] = '.';
5784                     } else {
5785                         unsigned int i = 0;
5786                         /*
5787                         * Insert missing zeroes behind the decimal point.
5788                         */
5789                         while (*(offs + i) != 0)
5790                             i++;
5791                         if (i < dec.total) {
5792                             memmove(offs + (dec.total - i), offs, i +1);
5793                             memset(offs, '0', dec.total - i);
5794                         }
5795                     }
5796                 } else {
5797                     /*
5798                     * Append decimal point and zero.
5799                     */
5800                     offs = buf + bufsize - 1;
5801                     *offs-- = 0;
5802                     *offs-- = '0';
5803                     *offs-- = '.';
5804                 }
5805                 *retValue = BAD_CAST buf;
5806             }
5807             break;
5808         case XML_SCHEMAS_INTEGER:
5809         case XML_SCHEMAS_PINTEGER:
5810         case XML_SCHEMAS_NPINTEGER:
5811         case XML_SCHEMAS_NINTEGER:
5812         case XML_SCHEMAS_NNINTEGER:
5813         case XML_SCHEMAS_LONG:
5814         case XML_SCHEMAS_BYTE:
5815         case XML_SCHEMAS_SHORT:
5816         case XML_SCHEMAS_INT:
5817         case XML_SCHEMAS_UINT:
5818         case XML_SCHEMAS_ULONG:
5819         case XML_SCHEMAS_USHORT:
5820         case XML_SCHEMAS_UBYTE:
5821             if ((val->value.decimal.total == 1) &&
5822                 (val->value.decimal.lo == 0))
5823                 *retValue = xmlStrdup(BAD_CAST "0");
5824             else {
5825                 xmlSchemaValDecimal dec = val->value.decimal;
5826                 int bufsize = dec.total + 1;
5827
5828                 /* Add room for the decimal point as well. */
5829                 if (dec.sign)
5830                     bufsize++;
5831                 *retValue = xmlMalloc(bufsize);
5832                 if (*retValue == NULL)
5833                     return(-1);
5834                 if (dec.hi != 0) {
5835                     if (dec.sign)
5836                         snprintf((char *) *retValue, bufsize,
5837                             "-%lu%lu%lu", dec.hi, dec.mi, dec.lo);
5838                     else
5839                         snprintf((char *) *retValue, bufsize,
5840                             "%lu%lu%lu", dec.hi, dec.mi, dec.lo);
5841                 } else if (dec.mi != 0) {
5842                     if (dec.sign)
5843                         snprintf((char *) *retValue, bufsize,
5844                             "-%lu%lu", dec.mi, dec.lo);
5845                     else
5846                         snprintf((char *) *retValue, bufsize,
5847                             "%lu%lu", dec.mi, dec.lo);
5848                 } else {
5849                     if (dec.sign)
5850                         snprintf((char *) *retValue, bufsize, "-%lu", dec.lo);
5851                     else
5852                         snprintf((char *) *retValue, bufsize, "%lu", dec.lo);
5853                 }
5854             }
5855             break;
5856         case XML_SCHEMAS_BOOLEAN:
5857             if (val->value.b)
5858                 *retValue = BAD_CAST xmlStrdup(BAD_CAST "true");
5859             else
5860                 *retValue = BAD_CAST xmlStrdup(BAD_CAST "false");
5861             break;
5862         case XML_SCHEMAS_DURATION: {
5863                 char buf[100];
5864                 unsigned long year;
5865                 unsigned long mon, day, hour = 0, min = 0;
5866                 double sec = 0, left;
5867
5868                 /* TODO: Unclear in XML Schema 1.0 */
5869                 /*
5870                 * TODO: This results in a normalized output of the value
5871                 * - which is NOT conformant to the spec -
5872                 * since the exact values of each property are not
5873                 * recoverable. Think about extending the structure to
5874                 * provide a field for every property.
5875                 */
5876                 year = (unsigned long) FQUOTIENT(labs(val->value.dur.mon), 12);
5877                 mon = labs(val->value.dur.mon) - 12 * year;
5878
5879                 day = (unsigned long) FQUOTIENT(fabs(val->value.dur.sec), 86400);
5880                 left = fabs(val->value.dur.sec) - day * 86400;
5881                 if (left > 0) {
5882                     hour = (unsigned long) FQUOTIENT(left, 3600);
5883                     left = left - (hour * 3600);
5884                     if (left > 0) {
5885                         min = (unsigned long) FQUOTIENT(left, 60);
5886                         sec = left - (min * 60);
5887                     }
5888                 }
5889                 if ((val->value.dur.mon < 0) || (val->value.dur.sec < 0))
5890                     snprintf(buf, 100, "P%luY%luM%luDT%luH%luM%.14gS",
5891                         year, mon, day, hour, min, sec);
5892                 else
5893                     snprintf(buf, 100, "-P%luY%luM%luDT%luH%luM%.14gS",
5894                         year, mon, day, hour, min, sec);
5895                 *retValue = BAD_CAST xmlStrdup(BAD_CAST buf);
5896             }
5897             break;
5898         case XML_SCHEMAS_GYEAR: {
5899                 char buf[30];
5900                 /* TODO: Unclear in XML Schema 1.0 */
5901                 /* TODO: What to do with the timezone? */
5902                 snprintf(buf, 30, "%04ld", val->value.date.year);
5903                 *retValue = BAD_CAST xmlStrdup(BAD_CAST buf);
5904             }
5905             break;
5906         case XML_SCHEMAS_GMONTH: {
5907                 /* TODO: Unclear in XML Schema 1.0 */
5908                 /* TODO: What to do with the timezone? */
5909                 *retValue = xmlMalloc(6);
5910                 if (*retValue == NULL)
5911                     return(-1);
5912                 snprintf((char *) *retValue, 6, "--%02u",
5913                     val->value.date.mon);
5914             }
5915             break;
5916         case XML_SCHEMAS_GDAY: {
5917                 /* TODO: Unclear in XML Schema 1.0 */
5918                 /* TODO: What to do with the timezone? */
5919                 *retValue = xmlMalloc(6);
5920                 if (*retValue == NULL)
5921                     return(-1);
5922                 snprintf((char *) *retValue, 6, "---%02u",
5923                     val->value.date.day);
5924             }
5925             break;
5926         case XML_SCHEMAS_GMONTHDAY: {
5927                 /* TODO: Unclear in XML Schema 1.0 */
5928                 /* TODO: What to do with the timezone? */
5929                 *retValue = xmlMalloc(8);
5930                 if (*retValue == NULL)
5931                     return(-1);
5932                 snprintf((char *) *retValue, 8, "--%02u-%02u",
5933                     val->value.date.mon, val->value.date.day);
5934             }
5935             break;
5936         case XML_SCHEMAS_GYEARMONTH: {
5937                 char buf[35];
5938                 /* TODO: Unclear in XML Schema 1.0 */
5939                 /* TODO: What to do with the timezone? */
5940                 if (val->value.date.year < 0)
5941                     snprintf(buf, 35, "-%04ld-%02u",
5942                         labs(val->value.date.year),
5943                         val->value.date.mon);
5944                 else
5945                     snprintf(buf, 35, "%04ld-%02u",
5946                         val->value.date.year, val->value.date.mon);
5947                 *retValue = BAD_CAST xmlStrdup(BAD_CAST buf);
5948             }
5949             break;
5950         case XML_SCHEMAS_TIME:
5951             {
5952                 char buf[30];
5953
5954                 if (val->value.date.tz_flag) {
5955                     xmlSchemaValPtr norm;
5956
5957                     norm = xmlSchemaDateNormalize(val, 0);
5958                     if (norm == NULL)
5959                         return (-1);
5960                     /*
5961                     * TODO: Check if "%.14g" is portable.
5962                     */
5963                     snprintf(buf, 30,
5964                         "%02u:%02u:%02.14gZ",
5965                         norm->value.date.hour,
5966                         norm->value.date.min,
5967                         norm->value.date.sec);
5968                     xmlSchemaFreeValue(norm);
5969                 } else {
5970                     snprintf(buf, 30,
5971                         "%02u:%02u:%02.14g",
5972                         val->value.date.hour,
5973                         val->value.date.min,
5974                         val->value.date.sec);
5975                 }
5976                 *retValue = BAD_CAST xmlStrdup(BAD_CAST buf);
5977             }
5978             break;
5979         case XML_SCHEMAS_DATE:
5980             {
5981                 char buf[30];
5982
5983                 if (val->value.date.tz_flag) {
5984                     xmlSchemaValPtr norm;
5985
5986                     norm = xmlSchemaDateNormalize(val, 0);
5987                     if (norm == NULL)
5988                         return (-1);
5989                     /*
5990                     * TODO: Append the canonical value of the
5991                     * recoverable timezone and not "Z".
5992                     */
5993                     snprintf(buf, 30,
5994                         "%04ld:%02u:%02uZ",
5995                         norm->value.date.year, norm->value.date.mon,
5996                         norm->value.date.day);
5997                     xmlSchemaFreeValue(norm);
5998                 } else {
5999                     snprintf(buf, 30,
6000                         "%04ld:%02u:%02u",
6001                         val->value.date.year, val->value.date.mon,
6002                         val->value.date.day);
6003                 }
6004                 *retValue = BAD_CAST xmlStrdup(BAD_CAST buf);
6005             }
6006             break;
6007         case XML_SCHEMAS_DATETIME:
6008             {
6009                 char buf[50];
6010
6011                 if (val->value.date.tz_flag) {
6012                     xmlSchemaValPtr norm;
6013
6014                     norm = xmlSchemaDateNormalize(val, 0);
6015                     if (norm == NULL)
6016                         return (-1);
6017                     /*
6018                     * TODO: Check if "%.14g" is portable.
6019                     */
6020                     snprintf(buf, 50,
6021                         "%04ld:%02u:%02uT%02u:%02u:%02.14gZ",
6022                         norm->value.date.year, norm->value.date.mon,
6023                         norm->value.date.day, norm->value.date.hour,
6024                         norm->value.date.min, norm->value.date.sec);
6025                     xmlSchemaFreeValue(norm);
6026                 } else {
6027                     snprintf(buf, 50,
6028                         "%04ld:%02u:%02uT%02u:%02u:%02.14g",
6029                         val->value.date.year, val->value.date.mon,
6030                         val->value.date.day, val->value.date.hour,
6031                         val->value.date.min, val->value.date.sec);
6032                 }
6033                 *retValue = BAD_CAST xmlStrdup(BAD_CAST buf);
6034             }
6035             break;
6036         case XML_SCHEMAS_HEXBINARY:
6037             *retValue = BAD_CAST xmlStrdup(BAD_CAST val->value.hex.str);
6038             break;
6039         case XML_SCHEMAS_BASE64BINARY:
6040             /*
6041             * TODO: Is the following spec piece implemented?:
6042             * SPEC: "Note: For some values the canonical form defined
6043             * above does not conform to [RFC 2045], which requires breaking
6044             * with linefeeds at appropriate intervals."
6045             */
6046             *retValue = BAD_CAST xmlStrdup(BAD_CAST val->value.base64.str);
6047             break;
6048         case XML_SCHEMAS_FLOAT: {
6049                 char buf[30];
6050                 /*
6051                 * |m| < 16777216, -149 <= e <= 104.
6052                 * TODO: Handle, NaN, INF, -INF. The format is not
6053                 * yet conformant. The c type float does not cover
6054                 * the whole range.
6055                 */
6056                 snprintf(buf, 30, "%01.14e", val->value.f);
6057                 *retValue = BAD_CAST xmlStrdup(BAD_CAST buf);
6058             }
6059             break;
6060         case XML_SCHEMAS_DOUBLE: {
6061                 char buf[40];
6062                 /* |m| < 9007199254740992, -1075 <= e <= 970 */
6063                 /*
6064                 * TODO: Handle, NaN, INF, -INF. The format is not
6065                 * yet conformant. The c type float does not cover
6066                 * the whole range.
6067                 */
6068                 snprintf(buf, 40, "%01.14e", val->value.d);
6069                 *retValue = BAD_CAST xmlStrdup(BAD_CAST buf);
6070             }
6071             break;
6072         default:
6073             *retValue = BAD_CAST xmlStrdup(BAD_CAST "???");
6074             return (1);
6075     }
6076     if (*retValue == NULL)
6077         return(-1);
6078     return (0);
6079 }
6080
6081 /**
6082  * xmlSchemaGetCanonValueWhtsp:
6083  * @val: the precomputed value
6084  * @retValue: the returned value
6085  * @ws: the whitespace type of the value
6086  *
6087  * Get the canonical representation of the value.
6088  * The caller has to free the returned @retValue.
6089  *
6090  * Returns 0 if the value could be built, 1 if the value type is
6091  * not supported yet and -1 in case of API errors.
6092  */
6093 int
6094 xmlSchemaGetCanonValueWhtsp(xmlSchemaValPtr val,
6095                             const xmlChar **retValue,
6096                             xmlSchemaWhitespaceValueType ws)
6097 {
6098     if ((retValue == NULL) || (val == NULL))
6099         return (-1);
6100     if ((ws == XML_SCHEMA_WHITESPACE_UNKNOWN) ||
6101         (ws > XML_SCHEMA_WHITESPACE_COLLAPSE))
6102         return (-1);
6103
6104     *retValue = NULL;
6105     switch (val->type) {
6106         case XML_SCHEMAS_STRING:
6107             if (val->value.str == NULL)
6108                 *retValue = BAD_CAST xmlStrdup(BAD_CAST "");
6109             else if (ws == XML_SCHEMA_WHITESPACE_COLLAPSE)
6110                 *retValue = xmlSchemaCollapseString(val->value.str);
6111             else if (ws == XML_SCHEMA_WHITESPACE_REPLACE)
6112                 *retValue = xmlSchemaWhiteSpaceReplace(val->value.str);
6113             if ((*retValue) == NULL)
6114                 *retValue = BAD_CAST xmlStrdup(val->value.str);
6115             break;
6116         case XML_SCHEMAS_NORMSTRING:
6117             if (val->value.str == NULL)
6118                 *retValue = BAD_CAST xmlStrdup(BAD_CAST "");
6119             else {
6120                 if (ws == XML_SCHEMA_WHITESPACE_COLLAPSE)
6121                     *retValue = xmlSchemaCollapseString(val->value.str);
6122                 else
6123                     *retValue = xmlSchemaWhiteSpaceReplace(val->value.str);
6124                 if ((*retValue) == NULL)
6125                     *retValue = BAD_CAST xmlStrdup(val->value.str);
6126             }
6127             break;
6128         default:
6129             return (xmlSchemaGetCanonValue(val, retValue));
6130     }
6131     return (0);
6132 }
6133
6134 /**
6135  * xmlSchemaGetValType:
6136  * @val: a schemas value
6137  *
6138  * Accessor for the type of a value
6139  *
6140  * Returns the xmlSchemaValType of the value
6141  */
6142 xmlSchemaValType
6143 xmlSchemaGetValType(xmlSchemaValPtr val)
6144 {
6145     if (val == NULL)
6146         return(XML_SCHEMAS_UNKNOWN);
6147     return (val->type);
6148 }
6149
6150 #define bottom_xmlschemastypes
6151 #include "elfgcchack.h"
6152 #endif /* LIBXML_SCHEMAS_ENABLED */