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