Imported Upstream version 0.18.1.1
[platform/upstream/gettext.git] / gettext-tools / gnulib-lib / libxml / 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
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     while (*cur == '0') {        /* ignore leading zeroes */
2076         cur++;
2077     }
2078     tmp = cur;
2079     while ((*tmp != 0) && (*tmp >= '0') && (*tmp <= '9')) {
2080         i++;tmp++;ret++;
2081     }
2082     if (i > 24) {
2083         *str = tmp;
2084         return(-1);
2085     }
2086     while (i > 16) {
2087         hi = hi * 10 + (*cur++ - '0');
2088         i--;
2089     }
2090     while (i > 8) {
2091         mi = mi * 10 + (*cur++ - '0');
2092         i--;
2093     }
2094     while (i > 0) {
2095         lo = lo * 10 + (*cur++ - '0');
2096         i--;
2097     }
2098
2099     *str = cur;
2100     *llo = lo;
2101     *lmi = mi;
2102     *lhi = hi;
2103     return(ret);
2104 }
2105
2106 /**
2107  * xmlSchemaValAtomicType:
2108  * @type: the predefined type
2109  * @value: the value to check
2110  * @val:  the return computed value
2111  * @node:  the node containing the value
2112  * flags:  flags to control the vlidation
2113  *
2114  * Check that a value conforms to the lexical space of the atomic type.
2115  * if true a value is computed and returned in @val.
2116  * This checks the value space for list types as well (IDREFS, NMTOKENS).
2117  *
2118  * Returns 0 if this validates, a positive error code number otherwise
2119  *         and -1 in case of internal or API error.
2120  */
2121 static int
2122 xmlSchemaValAtomicType(xmlSchemaTypePtr type, const xmlChar * value,
2123                        xmlSchemaValPtr * val, xmlNodePtr node, int flags,
2124                        xmlSchemaWhitespaceValueType ws,
2125                        int normOnTheFly, int applyNorm, int createStringValue)
2126 {
2127     xmlSchemaValPtr v;
2128     xmlChar *norm = NULL;
2129     int ret = 0;
2130
2131     if (xmlSchemaTypesInitialized == 0)
2132         xmlSchemaInitTypes();
2133     if (type == NULL)
2134         return (-1);
2135
2136     /*
2137      * validating a non existant text node is similar to validating
2138      * an empty one.
2139      */
2140     if (value == NULL)
2141         value = BAD_CAST "";
2142
2143     if (val != NULL)
2144         *val = NULL;
2145     if ((flags == 0) && (value != NULL)) {
2146
2147         if ((type->builtInType != XML_SCHEMAS_STRING) &&
2148           (type->builtInType != XML_SCHEMAS_ANYTYPE) && 
2149           (type->builtInType != XML_SCHEMAS_ANYSIMPLETYPE)) {
2150             if (type->builtInType == XML_SCHEMAS_NORMSTRING)
2151                 norm = xmlSchemaWhiteSpaceReplace(value);
2152             else
2153                 norm = xmlSchemaCollapseString(value);
2154             if (norm != NULL)
2155                 value = norm;
2156         }
2157     }
2158
2159     switch (type->builtInType) {
2160         case XML_SCHEMAS_UNKNOWN:            
2161             goto error;
2162         case XML_SCHEMAS_ANYTYPE:
2163         case XML_SCHEMAS_ANYSIMPLETYPE:
2164             if ((createStringValue) && (val != NULL)) {
2165                 v = xmlSchemaNewValue(XML_SCHEMAS_ANYSIMPLETYPE);
2166                 if (v != NULL) {
2167                     v->value.str = xmlStrdup(value);
2168                     *val = v;
2169                 } else {
2170                     goto error;
2171                 }               
2172             }
2173             goto return0;
2174         case XML_SCHEMAS_STRING:                
2175             if (! normOnTheFly) {
2176                 const xmlChar *cur = value;
2177
2178                 if (ws == XML_SCHEMA_WHITESPACE_REPLACE) {
2179                     while (*cur != 0) {
2180                         if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) {
2181                             goto return1;
2182                         } else {
2183                             cur++;
2184                         }
2185                     }
2186                 } else if (ws == XML_SCHEMA_WHITESPACE_COLLAPSE) {
2187                     while (*cur != 0) {
2188                         if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) {
2189                             goto return1;
2190                         } else if IS_WSP_SPACE_CH(*cur) {
2191                             cur++;
2192                             if IS_WSP_SPACE_CH(*cur)
2193                                 goto return1;
2194                         } else {
2195                             cur++;
2196                         }
2197                     }
2198                 }
2199             }
2200             if (createStringValue && (val != NULL)) {
2201                 if (applyNorm) {
2202                     if (ws == XML_SCHEMA_WHITESPACE_COLLAPSE)
2203                         norm = xmlSchemaCollapseString(value);
2204                     else if (ws == XML_SCHEMA_WHITESPACE_REPLACE)
2205                         norm = xmlSchemaWhiteSpaceReplace(value);
2206                     if (norm != NULL)
2207                         value = norm;
2208                 }
2209                 v = xmlSchemaNewValue(XML_SCHEMAS_STRING);
2210                 if (v != NULL) {
2211                     v->value.str = xmlStrdup(value);
2212                     *val = v;
2213                 } else {
2214                     goto error;
2215                 }
2216             }
2217             goto return0;
2218         case XML_SCHEMAS_NORMSTRING:{
2219                 if (normOnTheFly) {
2220                     if (applyNorm) {
2221                         if (ws == XML_SCHEMA_WHITESPACE_COLLAPSE)
2222                             norm = xmlSchemaCollapseString(value);
2223                         else
2224                             norm = xmlSchemaWhiteSpaceReplace(value);
2225                         if (norm != NULL)
2226                             value = norm;
2227                     }
2228                 } else {
2229                     const xmlChar *cur = value;
2230                     while (*cur != 0) {
2231                         if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) {
2232                             goto return1;
2233                         } else {
2234                             cur++;
2235                         }
2236                     }
2237                 }
2238                 if (val != NULL) {
2239                     v = xmlSchemaNewValue(XML_SCHEMAS_NORMSTRING);
2240                     if (v != NULL) {
2241                         v->value.str = xmlStrdup(value);
2242                         *val = v;
2243                     } else {
2244                         goto error;
2245                     }
2246                 }
2247                 goto return0;
2248             }
2249         case XML_SCHEMAS_DECIMAL:{
2250                 const xmlChar *cur = value;
2251                 unsigned int len, neg, integ, hasLeadingZeroes;
2252                 xmlChar cval[25];
2253                 xmlChar *cptr = cval;           
2254
2255                 if ((cur == NULL) || (*cur == 0))
2256                     goto return1;
2257
2258                 /*
2259                 * xs:decimal has a whitespace-facet value of 'collapse'.
2260                 */
2261                 if (normOnTheFly)
2262                     while IS_WSP_BLANK_CH(*cur) cur++;
2263
2264                 /*
2265                 * First we handle an optional sign.
2266                 */
2267                 neg = 0;
2268                 if (*cur == '-') {
2269                     neg = 1;
2270                     cur++;
2271                 } else if (*cur == '+')
2272                     cur++;
2273                 /*
2274                 * Disallow: "", "-", "- "
2275                 */
2276                 if (*cur == 0)
2277                     goto return1;
2278                 /*
2279                  * Next we "pre-parse" the number, in preparation for calling
2280                  * the common routine xmlSchemaParseUInt.  We get rid of any
2281                  * leading zeroes (because we have reserved only 25 chars),
2282                  * and note the position of a decimal point.
2283                  */
2284                 len = 0;
2285                 integ = ~0u;
2286                 hasLeadingZeroes = 0;
2287                 /*
2288                 * Skip leading zeroes.
2289                 */
2290                 while (*cur == '0') {
2291                     cur++;
2292                     hasLeadingZeroes = 1;
2293                 }
2294                 if (*cur != 0) {
2295                     do {
2296                         if ((*cur >= '0') && (*cur <= '9')) {
2297                             *cptr++ = *cur++;
2298                             len++;
2299                         } else if (*cur == '.') {
2300                             cur++;
2301                             integ = len;
2302                             do {
2303                                 if ((*cur >= '0') && (*cur <= '9')) {
2304                                     *cptr++ = *cur++;
2305                                     len++;
2306                                 } else
2307                                     break;
2308                             } while (len < 24);
2309                             /*
2310                             * Disallow "." but allow "00."
2311                             */
2312                             if ((len == 0) && (!hasLeadingZeroes))
2313                                 goto return1;
2314                             break;
2315                         } else
2316                             break;
2317                     } while (len < 24);
2318                 }
2319                 if (normOnTheFly)
2320                     while IS_WSP_BLANK_CH(*cur) cur++;
2321                 if (*cur != 0)
2322                     goto return1; /* error if any extraneous chars */
2323                 if (val != NULL) {
2324                     v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
2325                     if (v != NULL) {
2326                         /*
2327                         * Now evaluate the significant digits of the number
2328                         */
2329                         if (len != 0) {
2330                             
2331                             if (integ != ~0u) {
2332                                 /*
2333                                 * Get rid of trailing zeroes in the
2334                                 * fractional part.
2335                                 */
2336                                 while ((len != integ) && (*(cptr-1) == '0')) {
2337                                     cptr--;
2338                                     len--;
2339                                 }
2340                             }
2341                             /*
2342                             * Terminate the (preparsed) string.
2343                             */
2344                             if (len != 0) {
2345                                 *cptr = 0; 
2346                                 cptr = cval;
2347                                 
2348                                 xmlSchemaParseUInt((const xmlChar **)&cptr,
2349                                     &v->value.decimal.lo,
2350                                     &v->value.decimal.mi,
2351                                     &v->value.decimal.hi);
2352                             }
2353                         }
2354                         /*
2355                         * Set the total digits to 1 if a zero value.
2356                         */
2357                         v->value.decimal.sign = neg;
2358                         if (len == 0) {
2359                             /* Speedup for zero values. */
2360                             v->value.decimal.total = 1;
2361                         } else {
2362                             v->value.decimal.total = len;
2363                             if (integ == ~0u)
2364                                 v->value.decimal.frac = 0;
2365                             else
2366                                 v->value.decimal.frac = len - integ;
2367                         }
2368                         *val = v;
2369                     }
2370                 }
2371                 goto return0;
2372             }
2373         case XML_SCHEMAS_TIME:
2374         case XML_SCHEMAS_GDAY:
2375         case XML_SCHEMAS_GMONTH:
2376         case XML_SCHEMAS_GMONTHDAY:
2377         case XML_SCHEMAS_GYEAR:
2378         case XML_SCHEMAS_GYEARMONTH:
2379         case XML_SCHEMAS_DATE:
2380         case XML_SCHEMAS_DATETIME:
2381             ret = xmlSchemaValidateDates(type->builtInType, value, val,
2382                 normOnTheFly);
2383             break;
2384         case XML_SCHEMAS_DURATION:
2385             ret = xmlSchemaValidateDuration(type, value, val,
2386                 normOnTheFly);
2387             break;
2388         case XML_SCHEMAS_FLOAT:
2389         case XML_SCHEMAS_DOUBLE:{
2390                 const xmlChar *cur = value;
2391                 int neg = 0;
2392
2393                 if (normOnTheFly)
2394                     while IS_WSP_BLANK_CH(*cur) cur++;
2395
2396                 if ((cur[0] == 'N') && (cur[1] == 'a') && (cur[2] == 'N')) {
2397                     cur += 3;
2398                     if (*cur != 0)
2399                         goto return1;
2400                     if (val != NULL) {
2401                         if (type == xmlSchemaTypeFloatDef) {
2402                             v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
2403                             if (v != NULL) {
2404                                 v->value.f = (float) xmlXPathNAN;
2405                             } else {
2406                                 xmlSchemaFreeValue(v);
2407                                 goto error;
2408                             }
2409                         } else {
2410                             v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
2411                             if (v != NULL) {
2412                                 v->value.d = xmlXPathNAN;
2413                             } else {
2414                                 xmlSchemaFreeValue(v);
2415                                 goto error;
2416                             }
2417                         }
2418                         *val = v;
2419                     }
2420                     goto return0;
2421                 }
2422                 if (*cur == '-') {
2423                     neg = 1;
2424                     cur++;
2425                 }
2426                 if ((cur[0] == 'I') && (cur[1] == 'N') && (cur[2] == 'F')) {
2427                     cur += 3;
2428                     if (*cur != 0)
2429                         goto return1;
2430                     if (val != NULL) {
2431                         if (type == xmlSchemaTypeFloatDef) {
2432                             v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
2433                             if (v != NULL) {
2434                                 if (neg)
2435                                     v->value.f = (float) xmlXPathNINF;
2436                                 else
2437                                     v->value.f = (float) xmlXPathPINF;
2438                             } else {
2439                                 xmlSchemaFreeValue(v);
2440                                 goto error;
2441                             }
2442                         } else {
2443                             v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
2444                             if (v != NULL) {
2445                                 if (neg)
2446                                     v->value.d = xmlXPathNINF;
2447                                 else
2448                                     v->value.d = xmlXPathPINF;
2449                             } else {
2450                                 xmlSchemaFreeValue(v);
2451                                 goto error;
2452                             }
2453                         }
2454                         *val = v;
2455                     }
2456                     goto return0;
2457                 }
2458                 if ((neg == 0) && (*cur == '+'))
2459                     cur++;
2460                 if ((cur[0] == 0) || (cur[0] == '+') || (cur[0] == '-'))
2461                     goto return1;
2462                 while ((*cur >= '0') && (*cur <= '9')) {
2463                     cur++;
2464                 }
2465                 if (*cur == '.') {
2466                     cur++;
2467                     while ((*cur >= '0') && (*cur <= '9'))
2468                         cur++;
2469                 }
2470                 if ((*cur == 'e') || (*cur == 'E')) {
2471                     cur++;
2472                     if ((*cur == '-') || (*cur == '+'))
2473                         cur++;
2474                     while ((*cur >= '0') && (*cur <= '9'))
2475                         cur++;
2476                 }
2477                 if (normOnTheFly)
2478                     while IS_WSP_BLANK_CH(*cur) cur++;
2479
2480                 if (*cur != 0)
2481                     goto return1;
2482                 if (val != NULL) {
2483                     if (type == xmlSchemaTypeFloatDef) {
2484                         v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
2485                         if (v != NULL) {
2486                             /*
2487                             * TODO: sscanf seems not to give the correct
2488                             * value for extremely high/low values.
2489                             * E.g. "1E-149" results in zero.
2490                             */
2491                             if (sscanf((const char *) value, "%f",
2492                                  &(v->value.f)) == 1) {
2493                                 *val = v;
2494                             } else {
2495                                 xmlSchemaFreeValue(v);
2496                                 goto return1;
2497                             }
2498                         } else {
2499                             goto error;
2500                         }
2501                     } else {
2502                         v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
2503                         if (v != NULL) {
2504                             /*
2505                             * TODO: sscanf seems not to give the correct
2506                             * value for extremely high/low values.
2507                             */
2508                             if (sscanf((const char *) value, "%lf",
2509                                  &(v->value.d)) == 1) {
2510                                 *val = v;
2511                             } else {
2512                                 xmlSchemaFreeValue(v);
2513                                 goto return1;
2514                             }
2515                         } else {
2516                             goto error;
2517                         }
2518                     }
2519                 }
2520                 goto return0;
2521             }
2522         case XML_SCHEMAS_BOOLEAN:{
2523                 const xmlChar *cur = value;
2524
2525                 if (normOnTheFly) {
2526                     while IS_WSP_BLANK_CH(*cur) cur++;
2527                     if (*cur == '0') {
2528                         ret = 0;
2529                         cur++;
2530                     } else if (*cur == '1') {
2531                         ret = 1;
2532                         cur++;
2533                     } else if (*cur == 't') {
2534                         cur++;
2535                         if ((*cur++ == 'r') && (*cur++ == 'u') &&
2536                             (*cur++ == 'e')) {
2537                             ret = 1;
2538                         } else
2539                             goto return1;
2540                     } else if (*cur == 'f') {
2541                         cur++;
2542                         if ((*cur++ == 'a') && (*cur++ == 'l') &&
2543                             (*cur++ == 's') && (*cur++ == 'e')) {
2544                             ret = 0;
2545                         } else
2546                             goto return1;
2547                     } else
2548                         goto return1;
2549                     if (*cur != 0) {
2550                         while IS_WSP_BLANK_CH(*cur) cur++;
2551                         if (*cur != 0)
2552                             goto return1;
2553                     }
2554                 } else {
2555                     if ((cur[0] == '0') && (cur[1] == 0))
2556                         ret = 0;
2557                     else if ((cur[0] == '1') && (cur[1] == 0))
2558                         ret = 1;
2559                     else if ((cur[0] == 't') && (cur[1] == 'r')
2560                         && (cur[2] == 'u') && (cur[3] == 'e')
2561                         && (cur[4] == 0))
2562                         ret = 1;
2563                     else if ((cur[0] == 'f') && (cur[1] == 'a')
2564                         && (cur[2] == 'l') && (cur[3] == 's')
2565                         && (cur[4] == 'e') && (cur[5] == 0))
2566                         ret = 0;
2567                     else
2568                         goto return1;
2569                 }
2570                 if (val != NULL) {
2571                     v = xmlSchemaNewValue(XML_SCHEMAS_BOOLEAN);
2572                     if (v != NULL) {
2573                         v->value.b = ret;
2574                         *val = v;
2575                     } else {
2576                         goto error;
2577                     }
2578                 }
2579                 goto return0;
2580             }
2581         case XML_SCHEMAS_TOKEN:{
2582                 const xmlChar *cur = value;
2583
2584                 if (! normOnTheFly) {
2585                     while (*cur != 0) {
2586                         if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) {
2587                             goto return1;
2588                         } else if (*cur == ' ') {
2589                             cur++;
2590                             if (*cur == 0)
2591                                 goto return1;
2592                             if (*cur == ' ')
2593                                 goto return1;
2594                         } else {
2595                             cur++;
2596                         }
2597                     }               
2598                 }                
2599                 if (val != NULL) {
2600                     v = xmlSchemaNewValue(XML_SCHEMAS_TOKEN);
2601                     if (v != NULL) {
2602                         v->value.str = xmlStrdup(value);
2603                         *val = v;
2604                     } else {
2605                         goto error;
2606                     }
2607                 }
2608                 goto return0;
2609             }
2610         case XML_SCHEMAS_LANGUAGE:
2611             if (normOnTheFly) {             
2612                 norm = xmlSchemaCollapseString(value);
2613                 if (norm != NULL)
2614                     value = norm;
2615             }
2616             if (xmlCheckLanguageID(value) == 1) {
2617                 if (val != NULL) {
2618                     v = xmlSchemaNewValue(XML_SCHEMAS_LANGUAGE);
2619                     if (v != NULL) {
2620                         v->value.str = xmlStrdup(value);
2621                         *val = v;
2622                     } else {
2623                         goto error;
2624                     }
2625                 }
2626                 goto return0;
2627             }
2628             goto return1;
2629         case XML_SCHEMAS_NMTOKEN:
2630             if (xmlValidateNMToken(value, 1) == 0) {
2631                 if (val != NULL) {
2632                     v = xmlSchemaNewValue(XML_SCHEMAS_NMTOKEN);
2633                     if (v != NULL) {
2634                         v->value.str = xmlStrdup(value);
2635                         *val = v;
2636                     } else {
2637                         goto error;
2638                     }
2639                 }
2640                 goto return0;
2641             }
2642             goto return1;
2643         case XML_SCHEMAS_NMTOKENS:
2644             ret = xmlSchemaValAtomicListNode(xmlSchemaTypeNmtokenDef,
2645                                              value, val, node);
2646             if (ret > 0)
2647                 ret = 0;
2648             else
2649                 ret = 1;
2650             goto done;
2651         case XML_SCHEMAS_NAME:
2652             ret = xmlValidateName(value, 1);
2653             if ((ret == 0) && (val != NULL) && (value != NULL)) {
2654                 v = xmlSchemaNewValue(XML_SCHEMAS_NAME);
2655                 if (v != NULL) {
2656                      const xmlChar *start = value, *end;
2657                      while (IS_BLANK_CH(*start)) start++;
2658                      end = start;
2659                      while ((*end != 0) && (!IS_BLANK_CH(*end))) end++;
2660                      v->value.str = xmlStrndup(start, end - start);
2661                     *val = v;
2662                 } else {
2663                     goto error;
2664                 }
2665             }
2666             goto done;
2667         case XML_SCHEMAS_QNAME:{
2668                 const xmlChar *uri = NULL;
2669                 xmlChar *local = NULL;
2670
2671                 ret = xmlValidateQName(value, 1);
2672                 if (ret != 0)
2673                     goto done;
2674                 if (node != NULL) {
2675                     xmlChar *prefix;
2676                     xmlNsPtr ns;
2677
2678                     local = xmlSplitQName2(value, &prefix);
2679                     ns = xmlSearchNs(node->doc, node, prefix);
2680                     if ((ns == NULL) && (prefix != NULL)) {
2681                         xmlFree(prefix);
2682                         if (local != NULL)
2683                             xmlFree(local);
2684                         goto return1;
2685                     }
2686                     if (ns != NULL)
2687                         uri = ns->href;
2688                     if (prefix != NULL)
2689                         xmlFree(prefix);
2690                 }
2691                 if (val != NULL) {
2692                     v = xmlSchemaNewValue(XML_SCHEMAS_QNAME);
2693                     if (v == NULL) {
2694                         if (local != NULL)
2695                             xmlFree(local);
2696                         goto error;
2697                     }
2698                     if (local != NULL)
2699                         v->value.qname.name = local;
2700                     else
2701                         v->value.qname.name = xmlStrdup(value);
2702                     if (uri != NULL)
2703                         v->value.qname.uri = xmlStrdup(uri);
2704                     *val = v;
2705                 } else
2706                     if (local != NULL)
2707                         xmlFree(local);
2708                 goto done;
2709             }
2710         case XML_SCHEMAS_NCNAME:
2711             ret = xmlValidateNCName(value, 1);
2712             if ((ret == 0) && (val != NULL)) {
2713                 v = xmlSchemaNewValue(XML_SCHEMAS_NCNAME);
2714                 if (v != NULL) {
2715                     v->value.str = xmlStrdup(value);
2716                     *val = v;
2717                 } else {
2718                     goto error;
2719                 }
2720             }
2721             goto done;
2722         case XML_SCHEMAS_ID:
2723             ret = xmlValidateNCName(value, 1);
2724             if ((ret == 0) && (val != NULL)) {
2725                 v = xmlSchemaNewValue(XML_SCHEMAS_ID);
2726                 if (v != NULL) {
2727                     v->value.str = xmlStrdup(value);
2728                     *val = v;
2729                 } else {
2730                     goto error;
2731                 }
2732             }
2733             if ((ret == 0) && (node != NULL) &&
2734                 (node->type == XML_ATTRIBUTE_NODE)) {
2735                 xmlAttrPtr attr = (xmlAttrPtr) node;
2736
2737                 /*
2738                  * NOTE: the IDness might have already be declared in the DTD
2739                  */
2740                 if (attr->atype != XML_ATTRIBUTE_ID) {
2741                     xmlIDPtr res;
2742                     xmlChar *strip;
2743
2744                     strip = xmlSchemaStrip(value);
2745                     if (strip != NULL) {
2746                         res = xmlAddID(NULL, node->doc, strip, attr);
2747                         xmlFree(strip);
2748                     } else
2749                         res = xmlAddID(NULL, node->doc, value, attr);
2750                     if (res == NULL) {
2751                         ret = 2;
2752                     } else {
2753                         attr->atype = XML_ATTRIBUTE_ID;
2754                     }
2755                 }
2756             }
2757             goto done;
2758         case XML_SCHEMAS_IDREF:
2759             ret = xmlValidateNCName(value, 1);
2760             if ((ret == 0) && (val != NULL)) {
2761                 v = xmlSchemaNewValue(XML_SCHEMAS_IDREF);
2762                 if (v == NULL)
2763                     goto error;
2764                 v->value.str = xmlStrdup(value);
2765                 *val = v;
2766             }
2767             if ((ret == 0) && (node != NULL) &&
2768                 (node->type == XML_ATTRIBUTE_NODE)) {
2769                 xmlAttrPtr attr = (xmlAttrPtr) node;
2770                 xmlChar *strip;
2771
2772                 strip = xmlSchemaStrip(value);
2773                 if (strip != NULL) {
2774                     xmlAddRef(NULL, node->doc, strip, attr);
2775                     xmlFree(strip);
2776                 } else
2777                     xmlAddRef(NULL, node->doc, value, attr);
2778                 attr->atype = XML_ATTRIBUTE_IDREF;
2779             }
2780             goto done;
2781         case XML_SCHEMAS_IDREFS:
2782             ret = xmlSchemaValAtomicListNode(xmlSchemaTypeIdrefDef,
2783                                              value, val, node);
2784             if (ret < 0)
2785                 ret = 2;
2786             else
2787                 ret = 0;
2788             if ((ret == 0) && (node != NULL) &&
2789                 (node->type == XML_ATTRIBUTE_NODE)) {
2790                 xmlAttrPtr attr = (xmlAttrPtr) node;
2791
2792                 attr->atype = XML_ATTRIBUTE_IDREFS;
2793             }
2794             goto done;
2795         case XML_SCHEMAS_ENTITY:{
2796                 xmlChar *strip;
2797
2798                 ret = xmlValidateNCName(value, 1);
2799                 if ((node == NULL) || (node->doc == NULL))
2800                     ret = 3;
2801                 if (ret == 0) {
2802                     xmlEntityPtr ent;
2803
2804                     strip = xmlSchemaStrip(value);
2805                     if (strip != NULL) {
2806                         ent = xmlGetDocEntity(node->doc, strip);
2807                         xmlFree(strip);
2808                     } else {
2809                         ent = xmlGetDocEntity(node->doc, value);
2810                     }
2811                     if ((ent == NULL) ||
2812                         (ent->etype !=
2813                          XML_EXTERNAL_GENERAL_UNPARSED_ENTITY))
2814                         ret = 4;
2815                 }
2816                 if ((ret == 0) && (val != NULL)) {
2817                     TODO;
2818                 }
2819                 if ((ret == 0) && (node != NULL) &&
2820                     (node->type == XML_ATTRIBUTE_NODE)) {
2821                     xmlAttrPtr attr = (xmlAttrPtr) node;
2822
2823                     attr->atype = XML_ATTRIBUTE_ENTITY;
2824                 }
2825                 goto done;
2826             }
2827         case XML_SCHEMAS_ENTITIES:
2828             if ((node == NULL) || (node->doc == NULL))
2829                 goto return3;
2830             ret = xmlSchemaValAtomicListNode(xmlSchemaTypeEntityDef,
2831                                              value, val, node);
2832             if (ret <= 0)
2833                 ret = 1;
2834             else
2835                 ret = 0;
2836             if ((ret == 0) && (node != NULL) &&
2837                 (node->type == XML_ATTRIBUTE_NODE)) {
2838                 xmlAttrPtr attr = (xmlAttrPtr) node;
2839
2840                 attr->atype = XML_ATTRIBUTE_ENTITIES;
2841             }
2842             goto done;
2843         case XML_SCHEMAS_NOTATION:{
2844                 xmlChar *uri = NULL;
2845                 xmlChar *local = NULL;
2846
2847                 ret = xmlValidateQName(value, 1);
2848                 if ((ret == 0) && (node != NULL)) {
2849                     xmlChar *prefix;
2850
2851                     local = xmlSplitQName2(value, &prefix);
2852                     if (prefix != NULL) {
2853                         xmlNsPtr ns;
2854
2855                         ns = xmlSearchNs(node->doc, node, prefix);
2856                         if (ns == NULL)
2857                             ret = 1;
2858                         else if (val != NULL)
2859                             uri = xmlStrdup(ns->href);
2860                     }
2861                     if ((local != NULL) && ((val == NULL) || (ret != 0)))
2862                         xmlFree(local);
2863                     if (prefix != NULL)
2864                         xmlFree(prefix);
2865                 }
2866                 if ((node == NULL) || (node->doc == NULL))
2867                     ret = 3;
2868                 if (ret == 0) {
2869                     ret = xmlValidateNotationUse(NULL, node->doc, value);
2870                     if (ret == 1)
2871                         ret = 0;
2872                     else
2873                         ret = 1;
2874                 }
2875                 if ((ret == 0) && (val != NULL)) {
2876                     v = xmlSchemaNewValue(XML_SCHEMAS_NOTATION);
2877                     if (v != NULL) {
2878                         if (local != NULL)
2879                             v->value.qname.name = local;
2880                         else
2881                             v->value.qname.name = xmlStrdup(value);
2882                         if (uri != NULL)
2883                             v->value.qname.uri = uri;
2884
2885                         *val = v;
2886                     } else {
2887                         if (local != NULL)
2888                             xmlFree(local);
2889                         if (uri != NULL)
2890                             xmlFree(uri);
2891                         goto error;
2892                     }
2893                 }
2894                 goto done;
2895             }
2896         case XML_SCHEMAS_ANYURI:{               
2897                 if (*value != 0) {
2898                     xmlURIPtr uri;
2899                     if (normOnTheFly) {             
2900                         norm = xmlSchemaCollapseString(value);
2901                         if (norm != NULL)
2902                             value = norm;
2903                     }
2904                     uri = xmlParseURI((const char *) value);
2905                     if (uri == NULL)
2906                         goto return1;
2907                     xmlFreeURI(uri);
2908                 }
2909
2910                 if (val != NULL) {
2911                     v = xmlSchemaNewValue(XML_SCHEMAS_ANYURI);
2912                     if (v == NULL)
2913                         goto error;
2914                     v->value.str = xmlStrdup(value);
2915                     *val = v;
2916                 }
2917                 goto return0;
2918             }
2919         case XML_SCHEMAS_HEXBINARY:{
2920                 const xmlChar *cur = value, *start;
2921                 xmlChar *base;
2922                 int total, i = 0;
2923
2924                 if (cur == NULL)
2925                     goto return1;
2926
2927                 if (normOnTheFly)
2928                     while IS_WSP_BLANK_CH(*cur) cur++;
2929
2930                 start = cur;
2931                 while (((*cur >= '0') && (*cur <= '9')) ||
2932                        ((*cur >= 'A') && (*cur <= 'F')) ||
2933                        ((*cur >= 'a') && (*cur <= 'f'))) {
2934                     i++;
2935                     cur++;
2936                 }
2937                 if (normOnTheFly)
2938                     while IS_WSP_BLANK_CH(*cur) cur++;
2939
2940                 if (*cur != 0)
2941                     goto return1;
2942                 if ((i % 2) != 0)
2943                     goto return1;
2944
2945                 if (val != NULL) {
2946
2947                     v = xmlSchemaNewValue(XML_SCHEMAS_HEXBINARY);
2948                     if (v == NULL)
2949                         goto error;
2950                     /*
2951                     * Copy only the normalized piece.
2952                     * CRITICAL TODO: Check this.
2953                     */
2954                     cur = xmlStrndup(start, i);
2955                     if (cur == NULL) {
2956                         xmlSchemaTypeErrMemory(node, "allocating hexbin data");
2957                         xmlFree(v);
2958                         goto return1;
2959                     }
2960
2961                     total = i / 2;      /* number of octets */
2962
2963                     base = (xmlChar *) cur;
2964                     while (i-- > 0) {
2965                         if (*base >= 'a')
2966                             *base = *base - ('a' - 'A');
2967                         base++;
2968                     }
2969
2970                     v->value.hex.str = (xmlChar *) cur;
2971                     v->value.hex.total = total;
2972                     *val = v;
2973                 }
2974                 goto return0;
2975             }
2976         case XML_SCHEMAS_BASE64BINARY:{
2977                 /* ISSUE:
2978                  * 
2979                  * Ignore all stray characters? (yes, currently)
2980                  * Worry about long lines? (no, currently)
2981                  * 
2982                  * rfc2045.txt:
2983                  * 
2984                  * "The encoded output stream must be represented in lines of
2985                  * no more than 76 characters each.  All line breaks or other
2986                  * characters not found in Table 1 must be ignored by decoding
2987                  * software.  In base64 data, characters other than those in
2988                  * Table 1, line breaks, and other white space probably
2989                  * indicate a transmission error, about which a warning
2990                  * message or even a message rejection might be appropriate
2991                  * under some circumstances." */
2992                 const xmlChar *cur = value;
2993                 xmlChar *base;
2994                 int total, i = 0, pad = 0;
2995
2996                 if (cur == NULL)
2997                     goto return1;
2998
2999                 for (; *cur; ++cur) {
3000                     int decc;
3001
3002                     decc = _xmlSchemaBase64Decode(*cur);
3003                     if (decc < 0) ;
3004                     else if (decc < 64)
3005                         i++;
3006                     else
3007                         break;
3008                 }
3009                 for (; *cur; ++cur) {
3010                     int decc;
3011
3012                     decc = _xmlSchemaBase64Decode(*cur);
3013                     if (decc < 0) ;
3014                     else if (decc < 64)
3015                         goto return1;
3016                     if (decc == 64)
3017                         pad++;
3018                 }
3019
3020                 /* rfc2045.txt: "Special processing is performed if fewer than
3021                  * 24 bits are available at the end of the data being encoded.
3022                  * A full encoding quantum is always completed at the end of a
3023                  * body.  When fewer than 24 input bits are available in an
3024                  * input group, zero bits are added (on the right) to form an
3025                  * integral number of 6-bit groups.  Padding at the end of the
3026                  * data is performed using the "=" character.  Since all
3027                  * base64 input is an integral number of octets, only the
3028                  * following cases can arise: (1) the final quantum of
3029                  * encoding input is an integral multiple of 24 bits; here,
3030                  * the final unit of encoded output will be an integral
3031                  * multiple ofindent: Standard input:701: Warning:old style
3032                  * assignment ambiguity in "=*".  Assuming "= *" 4 characters
3033                  * with no "=" padding, (2) the final
3034                  * quantum of encoding input is exactly 8 bits; here, the
3035                  * final unit of encoded output will be two characters
3036                  * followed by two "=" padding characters, or (3) the final
3037                  * quantum of encoding input is exactly 16 bits; here, the
3038                  * final unit of encoded output will be three characters
3039                  * followed by one "=" padding character." */
3040
3041                 total = 3 * (i / 4);
3042                 if (pad == 0) {
3043                     if (i % 4 != 0)
3044                         goto return1;
3045                 } else if (pad == 1) {
3046                     int decc;
3047
3048                     if (i % 4 != 3)
3049                         goto return1;
3050                     for (decc = _xmlSchemaBase64Decode(*cur);
3051                          (decc < 0) || (decc > 63);
3052                          decc = _xmlSchemaBase64Decode(*cur))
3053                         --cur;
3054                     /* 16bits in 24bits means 2 pad bits: nnnnnn nnmmmm mmmm00*/
3055                     /* 00111100 -> 0x3c */
3056                     if (decc & ~0x3c)
3057                         goto return1;
3058                     total += 2;
3059                 } else if (pad == 2) {
3060                     int decc;
3061
3062                     if (i % 4 != 2)
3063                         goto return1;
3064                     for (decc = _xmlSchemaBase64Decode(*cur);
3065                          (decc < 0) || (decc > 63);
3066                          decc = _xmlSchemaBase64Decode(*cur))
3067                         --cur;
3068                     /* 8bits in 12bits means 4 pad bits: nnnnnn nn0000 */
3069                     /* 00110000 -> 0x30 */
3070                     if (decc & ~0x30)
3071                         goto return1;
3072                     total += 1;
3073                 } else
3074                     goto return1;
3075
3076                 if (val != NULL) {
3077                     v = xmlSchemaNewValue(XML_SCHEMAS_BASE64BINARY);
3078                     if (v == NULL)
3079                         goto error;
3080                     base =
3081                         (xmlChar *) xmlMallocAtomic((i + pad + 1) *
3082                                                     sizeof(xmlChar));
3083                     if (base == NULL) {
3084                         xmlSchemaTypeErrMemory(node, "allocating base64 data");
3085                         xmlFree(v);
3086                         goto return1;
3087                     }
3088                     v->value.base64.str = base;
3089                     for (cur = value; *cur; ++cur)
3090                         if (_xmlSchemaBase64Decode(*cur) >= 0) {
3091                             *base = *cur;
3092                             ++base;
3093                         }
3094                     *base = 0;
3095                     v->value.base64.total = total;
3096                     *val = v;
3097                 }
3098                 goto return0;
3099             }
3100         case XML_SCHEMAS_INTEGER:
3101         case XML_SCHEMAS_PINTEGER:
3102         case XML_SCHEMAS_NPINTEGER:
3103         case XML_SCHEMAS_NINTEGER:
3104         case XML_SCHEMAS_NNINTEGER:{
3105                 const xmlChar *cur = value;
3106                 unsigned long lo, mi, hi;
3107                 int sign = 0;
3108
3109                 if (cur == NULL)
3110                     goto return1;
3111                 if (normOnTheFly)
3112                     while IS_WSP_BLANK_CH(*cur) cur++;
3113                 if (*cur == '-') {
3114                     sign = 1;
3115                     cur++;
3116                 } else if (*cur == '+')
3117                     cur++;
3118                 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
3119                 if (ret == -1)
3120                     goto return1;
3121                 if (normOnTheFly)
3122                     while IS_WSP_BLANK_CH(*cur) cur++;
3123                 if (*cur != 0)
3124                     goto return1;
3125                 if (type->builtInType == XML_SCHEMAS_NPINTEGER) {
3126                     if ((sign == 0) &&
3127                         ((hi != 0) || (mi != 0) || (lo != 0)))
3128                         goto return1;
3129                 } else if (type->builtInType == XML_SCHEMAS_PINTEGER) {
3130                     if (sign == 1)
3131                         goto return1;
3132                     if ((hi == 0) && (mi == 0) && (lo == 0))
3133                         goto return1;
3134                 } else if (type->builtInType == XML_SCHEMAS_NINTEGER) {
3135                     if (sign == 0)
3136                         goto return1;
3137                     if ((hi == 0) && (mi == 0) && (lo == 0))
3138                         goto return1;
3139                 } else if (type->builtInType == XML_SCHEMAS_NNINTEGER) {
3140                     if ((sign == 1) &&
3141                         ((hi != 0) || (mi != 0) || (lo != 0)))
3142                         goto return1;
3143                 }
3144                 if (val != NULL) {
3145                     v = xmlSchemaNewValue(type->builtInType);
3146                     if (v != NULL) {
3147                         if (ret == 0)
3148                             ret++;
3149                         v->value.decimal.lo = lo;
3150                         v->value.decimal.mi = mi;
3151                         v->value.decimal.hi = hi;
3152                         v->value.decimal.sign = sign;
3153                         v->value.decimal.frac = 0;
3154                         v->value.decimal.total = ret;
3155                         *val = v;
3156                     }
3157                 }
3158                 goto return0;
3159             }
3160         case XML_SCHEMAS_LONG:
3161         case XML_SCHEMAS_BYTE:
3162         case XML_SCHEMAS_SHORT:
3163         case XML_SCHEMAS_INT:{
3164                  const xmlChar *cur = value;
3165                 unsigned long lo, mi, hi;
3166                 int sign = 0;
3167
3168                 if (cur == NULL)
3169                     goto return1;
3170                 if (*cur == '-') {
3171                     sign = 1;
3172                     cur++;
3173                 } else if (*cur == '+')
3174                     cur++;
3175                 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
3176                 if (ret < 0)
3177                     goto return1;
3178                 if (*cur != 0)
3179                     goto return1;
3180                 if (type->builtInType == XML_SCHEMAS_LONG) {
3181                     if (hi >= 922) {
3182                         if (hi > 922)
3183                             goto return1;
3184                         if (mi >= 33720368) {
3185                             if (mi > 33720368)
3186                                 goto return1;
3187                             if ((sign == 0) && (lo > 54775807))
3188                                 goto return1;
3189                             if ((sign == 1) && (lo > 54775808))
3190                                 goto return1;
3191                         }
3192                     }
3193                 } else if (type->builtInType == XML_SCHEMAS_INT) {
3194                     if (hi != 0)
3195                         goto return1;
3196                     if (mi >= 21) {
3197                         if (mi > 21)
3198                             goto return1;
3199                         if ((sign == 0) && (lo > 47483647))
3200                             goto return1;
3201                         if ((sign == 1) && (lo > 47483648))
3202                             goto return1;
3203                     }
3204                 } else if (type->builtInType == XML_SCHEMAS_SHORT) {
3205                     if ((mi != 0) || (hi != 0))
3206                         goto return1;
3207                     if ((sign == 1) && (lo > 32768))
3208                         goto return1;
3209                     if ((sign == 0) && (lo > 32767))
3210                         goto return1;
3211                 } else if (type->builtInType == XML_SCHEMAS_BYTE) {
3212                     if ((mi != 0) || (hi != 0))
3213                         goto return1;
3214                     if ((sign == 1) && (lo > 128))
3215                         goto return1;
3216                     if ((sign == 0) && (lo > 127))
3217                         goto return1;
3218                 }
3219                 if (val != NULL) {
3220                     v = xmlSchemaNewValue(type->builtInType);
3221                     if (v != NULL) {
3222                         v->value.decimal.lo = lo;
3223                         v->value.decimal.mi = mi;
3224                         v->value.decimal.hi = hi;
3225                         v->value.decimal.sign = sign;
3226                         v->value.decimal.frac = 0;
3227                         v->value.decimal.total = ret;
3228                         *val = v;
3229                     }
3230                 }
3231                 goto return0;
3232             }
3233         case XML_SCHEMAS_UINT:
3234         case XML_SCHEMAS_ULONG:
3235         case XML_SCHEMAS_USHORT:
3236         case XML_SCHEMAS_UBYTE:{
3237                 const xmlChar *cur = value;
3238                 unsigned long lo, mi, hi;
3239
3240                 if (cur == NULL)
3241                     goto return1;
3242                 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
3243                 if (ret < 0)
3244                     goto return1;
3245                 if (*cur != 0)
3246                     goto return1;
3247                 if (type->builtInType == XML_SCHEMAS_ULONG) {
3248                     if (hi >= 1844) {
3249                         if (hi > 1844)
3250                             goto return1;
3251                         if (mi >= 67440737) {
3252                             if (mi > 67440737)
3253                                 goto return1;
3254                             if (lo > 9551615)
3255                                 goto return1;
3256                         }
3257                     }
3258                 } else if (type->builtInType == XML_SCHEMAS_UINT) {
3259                     if (hi != 0)
3260                         goto return1;
3261                     if (mi >= 42) {
3262                         if (mi > 42)
3263                             goto return1;
3264                         if (lo > 94967295)
3265                             goto return1;
3266                     }
3267                 } else if (type->builtInType == XML_SCHEMAS_USHORT) {
3268                     if ((mi != 0) || (hi != 0))
3269                         goto return1;
3270                     if (lo > 65535)
3271                         goto return1;
3272                 } else if (type->builtInType == XML_SCHEMAS_UBYTE) {
3273                     if ((mi != 0) || (hi != 0))
3274                         goto return1;
3275                     if (lo > 255)
3276                         goto return1;
3277                 }
3278                 if (val != NULL) {
3279                     v = xmlSchemaNewValue(type->builtInType);
3280                     if (v != NULL) {
3281                         v->value.decimal.lo = lo;
3282                         v->value.decimal.mi = mi;
3283                         v->value.decimal.hi = hi;
3284                         v->value.decimal.sign = 0;
3285                         v->value.decimal.frac = 0;
3286                         v->value.decimal.total = ret;
3287                         *val = v;
3288                     }
3289                 }
3290                 goto return0;
3291             }
3292     }
3293
3294   done:
3295     if (norm != NULL)
3296         xmlFree(norm);
3297     return (ret);
3298   return3:
3299     if (norm != NULL)
3300         xmlFree(norm);
3301     return (3);
3302   return1:
3303     if (norm != NULL)
3304         xmlFree(norm);
3305     return (1);
3306   return0:
3307     if (norm != NULL)
3308         xmlFree(norm);
3309     return (0);
3310   error:
3311     if (norm != NULL)
3312         xmlFree(norm);
3313     return (-1);
3314 }
3315
3316 /**
3317  * xmlSchemaValPredefTypeNode:
3318  * @type: the predefined type
3319  * @value: the value to check
3320  * @val:  the return computed value
3321  * @node:  the node containing the value
3322  *
3323  * Check that a value conforms to the lexical space of the predefined type.
3324  * if true a value is computed and returned in @val.
3325  *
3326  * Returns 0 if this validates, a positive error code number otherwise
3327  *         and -1 in case of internal or API error.
3328  */
3329 int
3330 xmlSchemaValPredefTypeNode(xmlSchemaTypePtr type, const xmlChar *value,
3331                            xmlSchemaValPtr *val, xmlNodePtr node) {
3332     return(xmlSchemaValAtomicType(type, value, val, node, 0,
3333         XML_SCHEMA_WHITESPACE_UNKNOWN, 1, 1, 0));
3334 }
3335
3336 /**
3337  * xmlSchemaValPredefTypeNodeNoNorm:
3338  * @type: the predefined type
3339  * @value: the value to check
3340  * @val:  the return computed value
3341  * @node:  the node containing the value
3342  *
3343  * Check that a value conforms to the lexical space of the predefined type.
3344  * if true a value is computed and returned in @val.
3345  * This one does apply any normalization to the value.
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 xmlSchemaValPredefTypeNodeNoNorm(xmlSchemaTypePtr type, const xmlChar *value,
3352                                  xmlSchemaValPtr *val, xmlNodePtr node) {
3353     return(xmlSchemaValAtomicType(type, value, val, node, 1,
3354         XML_SCHEMA_WHITESPACE_UNKNOWN, 1, 0, 1));
3355 }
3356
3357 /**
3358  * xmlSchemaValidatePredefinedType:
3359  * @type: the predefined type
3360  * @value: the value to check
3361  * @val:  the return computed value
3362  *
3363  * Check that a value conforms to the lexical space of the predefined type.
3364  * if true a value is computed and returned in @val.
3365  *
3366  * Returns 0 if this validates, a positive error code number otherwise
3367  *         and -1 in case of internal or API error.
3368  */
3369 int
3370 xmlSchemaValidatePredefinedType(xmlSchemaTypePtr type, const xmlChar *value,
3371                                 xmlSchemaValPtr *val) {
3372     return(xmlSchemaValPredefTypeNode(type, value, val, NULL));
3373 }
3374
3375 /**
3376  * xmlSchemaCompareDecimals:
3377  * @x:  a first decimal value
3378  * @y:  a second decimal value
3379  *
3380  * Compare 2 decimals
3381  *
3382  * Returns -1 if x < y, 0 if x == y, 1 if x > y and -2 in case of error
3383  */
3384 static int
3385 xmlSchemaCompareDecimals(xmlSchemaValPtr x, xmlSchemaValPtr y)
3386 {
3387     xmlSchemaValPtr swp;
3388     int order = 1, integx, integy, dlen;
3389     unsigned long hi, mi, lo;
3390
3391     /*
3392      * First test: If x is -ve and not zero
3393      */
3394     if ((x->value.decimal.sign) && 
3395         ((x->value.decimal.lo != 0) ||
3396          (x->value.decimal.mi != 0) ||
3397          (x->value.decimal.hi != 0))) {
3398         /*
3399          * Then if y is -ve and not zero reverse the compare
3400          */
3401         if ((y->value.decimal.sign) &&
3402             ((y->value.decimal.lo != 0) ||
3403              (y->value.decimal.mi != 0) ||
3404              (y->value.decimal.hi != 0)))
3405             order = -1;
3406         /*
3407          * Otherwise (y >= 0) we have the answer
3408          */
3409         else
3410             return (-1);
3411     /*
3412      * If x is not -ve and y is -ve we have the answer
3413      */
3414     } else if ((y->value.decimal.sign) &&
3415                ((y->value.decimal.lo != 0) ||
3416                 (y->value.decimal.mi != 0) ||
3417                 (y->value.decimal.hi != 0))) {
3418         return (1);
3419     }
3420     /*
3421      * If it's not simply determined by a difference in sign,
3422      * then we need to compare the actual values of the two nums.
3423      * To do this, we start by looking at the integral parts.
3424      * If the number of integral digits differ, then we have our
3425      * answer.
3426      */
3427     integx = x->value.decimal.total - x->value.decimal.frac;
3428     integy = y->value.decimal.total - y->value.decimal.frac;
3429     /*
3430     * NOTE: We changed the "total" for values like "0.1"
3431     *   (or "-0.1" or ".1") to be 1, which was 2 previously.
3432     *   Therefore the special case, when such values are
3433     *   compared with 0, needs to be handled separately;
3434     *   otherwise a zero would be recognized incorrectly as
3435     *   greater than those values. This has the nice side effect
3436     *   that we gain an overall optimized comparison with zeroes.
3437     * Note that a "0" has a "total" of 1 already.
3438     */
3439     if (integx == 1) {
3440         if (x->value.decimal.lo == 0) {
3441             if (integy != 1)
3442                 return -order;
3443             else if (y->value.decimal.lo != 0)
3444                 return -order;
3445             else
3446                 return(0);
3447         }
3448     }
3449     if (integy == 1) {
3450         if (y->value.decimal.lo == 0) {
3451             if (integx != 1)
3452                 return order;
3453             else if (x->value.decimal.lo != 0)
3454                 return order;
3455             else
3456                 return(0);
3457         }
3458     }
3459
3460     if (integx > integy)
3461         return order;
3462     else if (integy > integx)
3463         return -order;
3464
3465     /*
3466      * If the number of integral digits is the same for both numbers,
3467      * then things get a little more complicated.  We need to "normalize"
3468      * the numbers in order to properly compare them.  To do this, we
3469      * look at the total length of each number (length => number of
3470      * significant digits), and divide the "shorter" by 10 (decreasing
3471      * the length) until they are of equal length.
3472      */
3473     dlen = x->value.decimal.total - y->value.decimal.total;
3474     if (dlen < 0) {     /* y has more digits than x */
3475         swp = x;
3476         hi = y->value.decimal.hi;
3477         mi = y->value.decimal.mi;
3478         lo = y->value.decimal.lo;
3479         dlen = -dlen;
3480         order = -order;
3481     } else {            /* x has more digits than y */
3482         swp = y;
3483         hi = x->value.decimal.hi;
3484         mi = x->value.decimal.mi;
3485         lo = x->value.decimal.lo;
3486     }
3487     while (dlen > 8) {  /* in effect, right shift by 10**8 */
3488         lo = mi;
3489         mi = hi;
3490         hi = 0;
3491         dlen -= 8;
3492     }
3493     while (dlen > 0) {
3494         unsigned long rem1, rem2;
3495         rem1 = (hi % 10) * 100000000L;
3496         hi = hi / 10;
3497         rem2 = (mi % 10) * 100000000L;
3498         mi = (mi + rem1) / 10;
3499         lo = (lo + rem2) / 10;
3500         dlen--;
3501     }
3502     if (hi > swp->value.decimal.hi) {
3503         return order;
3504     } else if (hi == swp->value.decimal.hi) {
3505         if (mi > swp->value.decimal.mi) {
3506             return order;
3507         } else if (mi == swp->value.decimal.mi) {
3508             if (lo > swp->value.decimal.lo) {
3509                 return order;
3510             } else if (lo == swp->value.decimal.lo) {
3511                 if (x->value.decimal.total == y->value.decimal.total) {
3512                     return 0;
3513                 } else {
3514                     return order;
3515                 }
3516             }
3517         }
3518     }
3519     return -order;
3520 }
3521
3522 /**
3523  * xmlSchemaCompareDurations:
3524  * @x:  a first duration value
3525  * @y:  a second duration value
3526  *
3527  * Compare 2 durations
3528  *
3529  * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3530  * case of error
3531  */
3532 static int
3533 xmlSchemaCompareDurations(xmlSchemaValPtr x, xmlSchemaValPtr y)
3534 {
3535     long carry, mon, day;
3536     double sec;
3537     int invert = 1;
3538     long xmon, xday, myear, minday, maxday;
3539     static const long dayRange [2][12] = {
3540         { 0, 28, 59, 89, 120, 150, 181, 212, 242, 273, 303, 334, },
3541         { 0, 31, 62, 92, 123, 153, 184, 215, 245, 276, 306, 337} };
3542
3543     if ((x == NULL) || (y == NULL))
3544         return -2;
3545
3546     /* months */
3547     mon = x->value.dur.mon - y->value.dur.mon;
3548
3549     /* seconds */
3550     sec = x->value.dur.sec - y->value.dur.sec;
3551     carry = (long)sec / SECS_PER_DAY;
3552     sec -= (double)(carry * SECS_PER_DAY);
3553
3554     /* days */
3555     day = x->value.dur.day - y->value.dur.day + carry;
3556
3557     /* easy test */
3558     if (mon == 0) {
3559         if (day == 0)
3560             if (sec == 0.0)
3561                 return 0;
3562             else if (sec < 0.0)
3563                 return -1;
3564             else
3565                 return 1;
3566         else if (day < 0)
3567             return -1;
3568         else
3569             return 1;
3570     }
3571
3572     if (mon > 0) {
3573         if ((day >= 0) && (sec >= 0.0))
3574             return 1;
3575         else {
3576             xmon = mon;
3577             xday = -day;
3578         }
3579     } else if ((day <= 0) && (sec <= 0.0)) {
3580         return -1;
3581     } else {
3582         invert = -1;
3583         xmon = -mon;
3584         xday = day;
3585     }
3586
3587     myear = xmon / 12;
3588     if (myear == 0) {
3589         minday = 0;
3590         maxday = 0;
3591     } else {
3592         maxday = 366 * ((myear + 3) / 4) +
3593                  365 * ((myear - 1) % 4);
3594         minday = maxday - 1;
3595     }
3596
3597     xmon = xmon % 12;
3598     minday += dayRange[0][xmon];
3599     maxday += dayRange[1][xmon];
3600
3601     if ((maxday == minday) && (maxday == xday))
3602         return(0); /* can this really happen ? */
3603     if (maxday < xday)
3604         return(-invert);
3605     if (minday > xday)
3606         return(invert);
3607
3608     /* indeterminate */
3609     return 2;
3610 }
3611
3612 /*
3613  * macros for adding date/times and durations
3614  */
3615 #define FQUOTIENT(a,b)                  (floor(((double)a/(double)b)))
3616 #define MODULO(a,b)                     (a - FQUOTIENT(a,b) * b)
3617 #define FQUOTIENT_RANGE(a,low,high)     (FQUOTIENT((a-low),(high-low)))
3618 #define MODULO_RANGE(a,low,high)        ((MODULO((a-low),(high-low)))+low)
3619
3620 /**
3621  * xmlSchemaDupVal:
3622  * @v: the #xmlSchemaValPtr value to duplicate
3623  *
3624  * Makes a copy of @v. The calling program is responsible for freeing
3625  * the returned value.
3626  *
3627  * returns a pointer to a duplicated #xmlSchemaValPtr or NULL if error.
3628  */
3629 static xmlSchemaValPtr
3630 xmlSchemaDupVal (xmlSchemaValPtr v)
3631 {
3632     xmlSchemaValPtr ret = xmlSchemaNewValue(v->type);
3633     if (ret == NULL)
3634         return NULL;
3635     
3636     memcpy(ret, v, sizeof(xmlSchemaVal));
3637     ret->next = NULL;
3638     return ret;
3639 }
3640
3641 /**
3642  * xmlSchemaCopyValue:
3643  * @val:  the precomputed value to be copied
3644  *
3645  * Copies the precomputed value. This duplicates any string within.
3646  *
3647  * Returns the copy or NULL if a copy for a data-type is not implemented.
3648  */
3649 xmlSchemaValPtr
3650 xmlSchemaCopyValue(xmlSchemaValPtr val)
3651 {
3652     xmlSchemaValPtr ret = NULL, prev = NULL, cur;
3653
3654     /*
3655     * Copy the string values.
3656     */
3657     while (val != NULL) {
3658         switch (val->type) {
3659             case XML_SCHEMAS_ANYTYPE:
3660             case XML_SCHEMAS_IDREFS:
3661             case XML_SCHEMAS_ENTITIES:
3662             case XML_SCHEMAS_NMTOKENS:
3663                 xmlSchemaFreeValue(ret);
3664                 return (NULL);
3665             case XML_SCHEMAS_ANYSIMPLETYPE:
3666             case XML_SCHEMAS_STRING:
3667             case XML_SCHEMAS_NORMSTRING:
3668             case XML_SCHEMAS_TOKEN:
3669             case XML_SCHEMAS_LANGUAGE:
3670             case XML_SCHEMAS_NAME:
3671             case XML_SCHEMAS_NCNAME:
3672             case XML_SCHEMAS_ID:
3673             case XML_SCHEMAS_IDREF:
3674             case XML_SCHEMAS_ENTITY:
3675             case XML_SCHEMAS_NMTOKEN:
3676             case XML_SCHEMAS_ANYURI:
3677                 cur = xmlSchemaDupVal(val);
3678                 if (val->value.str != NULL)
3679                     cur->value.str = xmlStrdup(BAD_CAST val->value.str);
3680                 break;
3681             case XML_SCHEMAS_QNAME:        
3682             case XML_SCHEMAS_NOTATION:
3683                 cur = xmlSchemaDupVal(val);
3684                 if (val->value.qname.name != NULL)
3685                     cur->value.qname.name =
3686                     xmlStrdup(BAD_CAST val->value.qname.name);
3687                 if (val->value.qname.uri != NULL)
3688                     cur->value.qname.uri =
3689                     xmlStrdup(BAD_CAST val->value.qname.uri);
3690                 break;
3691             case XML_SCHEMAS_HEXBINARY:
3692                 cur = xmlSchemaDupVal(val);
3693                 if (val->value.hex.str != NULL)
3694                     cur->value.hex.str = xmlStrdup(BAD_CAST val->value.hex.str);
3695                 break;
3696             case XML_SCHEMAS_BASE64BINARY:
3697                 cur = xmlSchemaDupVal(val);
3698                 if (val->value.base64.str != NULL)
3699                     cur->value.base64.str =
3700                     xmlStrdup(BAD_CAST val->value.base64.str);
3701                 break;
3702             default:
3703                 cur = xmlSchemaDupVal(val);
3704                 break;
3705         }
3706         if (ret == NULL)
3707             ret = cur;
3708         else
3709             prev->next = cur;
3710         prev = cur;
3711         val = val->next;
3712     }
3713     return (ret);
3714 }
3715
3716 /**
3717  * _xmlSchemaDateAdd:
3718  * @dt: an #xmlSchemaValPtr
3719  * @dur: an #xmlSchemaValPtr of type #XS_DURATION
3720  *
3721  * Compute a new date/time from @dt and @dur. This function assumes @dt
3722  * is either #XML_SCHEMAS_DATETIME, #XML_SCHEMAS_DATE, #XML_SCHEMAS_GYEARMONTH,
3723  * or #XML_SCHEMAS_GYEAR. The returned #xmlSchemaVal is the same type as
3724  * @dt. The calling program is responsible for freeing the returned value.
3725  *
3726  * Returns a pointer to a new #xmlSchemaVal or NULL if error.
3727  */
3728 static xmlSchemaValPtr
3729 _xmlSchemaDateAdd (xmlSchemaValPtr dt, xmlSchemaValPtr dur)
3730 {
3731     xmlSchemaValPtr ret, tmp;
3732     long carry, tempdays, temp;
3733     xmlSchemaValDatePtr r, d;
3734     xmlSchemaValDurationPtr u;
3735
3736     if ((dt == NULL) || (dur == NULL))
3737         return NULL;
3738
3739     ret = xmlSchemaNewValue(dt->type);
3740     if (ret == NULL)
3741         return NULL;
3742
3743     /* make a copy so we don't alter the original value */
3744     tmp = xmlSchemaDupVal(dt);
3745     if (tmp == NULL) {
3746         xmlSchemaFreeValue(ret);
3747         return NULL;
3748     }
3749
3750     r = &(ret->value.date);
3751     d = &(tmp->value.date);
3752     u = &(dur->value.dur);
3753
3754     /* normalization */
3755     if (d->mon == 0)
3756         d->mon = 1;
3757
3758     /* normalize for time zone offset */
3759     u->sec -= (d->tzo * 60);
3760     d->tzo = 0;
3761
3762     /* normalization */
3763     if (d->day == 0)
3764         d->day = 1;
3765
3766     /* month */
3767     carry  = d->mon + u->mon;
3768     r->mon = (unsigned int) MODULO_RANGE(carry, 1, 13);
3769     carry  = (long) FQUOTIENT_RANGE(carry, 1, 13);
3770
3771     /* year (may be modified later) */
3772     r->year = d->year + carry;
3773     if (r->year == 0) {
3774         if (d->year > 0)
3775             r->year--;
3776         else
3777             r->year++;
3778     }
3779
3780     /* time zone */
3781     r->tzo     = d->tzo;
3782     r->tz_flag = d->tz_flag;
3783
3784     /* seconds */
3785     r->sec = d->sec + u->sec;
3786     carry  = (long) FQUOTIENT((long)r->sec, 60);
3787     if (r->sec != 0.0) {
3788         r->sec = MODULO(r->sec, 60.0);
3789     }
3790
3791     /* minute */
3792     carry += d->min;
3793     r->min = (unsigned int) MODULO(carry, 60);
3794     carry  = (long) FQUOTIENT(carry, 60);
3795
3796     /* hours */
3797     carry  += d->hour;
3798     r->hour = (unsigned int) MODULO(carry, 24);
3799     carry   = (long)FQUOTIENT(carry, 24);
3800
3801     /*
3802      * days
3803      * Note we use tempdays because the temporary values may need more
3804      * than 5 bits
3805      */
3806     if ((VALID_YEAR(r->year)) && (VALID_MONTH(r->mon)) &&
3807                   (d->day > MAX_DAYINMONTH(r->year, r->mon)))
3808         tempdays = MAX_DAYINMONTH(r->year, r->mon);
3809     else if (d->day < 1)
3810         tempdays = 1;
3811     else
3812         tempdays = d->day;
3813
3814     tempdays += u->day + carry;
3815
3816     while (1) {
3817         if (tempdays < 1) {
3818             long tmon = (long) MODULO_RANGE((int)r->mon-1, 1, 13);
3819             long tyr  = r->year + (long)FQUOTIENT_RANGE((int)r->mon-1, 1, 13);
3820             if (tyr == 0)
3821                 tyr--;
3822             /*
3823              * Coverity detected an overrun in daysInMonth 
3824              * of size 12 at position 12 with index variable "((r)->mon - 1)"
3825              */
3826             if (tmon < 0)
3827                 tmon = 0;
3828             if (tmon > 12)
3829                 tmon = 12;
3830             tempdays += MAX_DAYINMONTH(tyr, tmon);
3831             carry = -1;
3832         } else if (tempdays > (long) MAX_DAYINMONTH(r->year, r->mon)) {
3833             tempdays = tempdays - MAX_DAYINMONTH(r->year, r->mon);
3834             carry = 1;
3835         } else
3836             break;
3837
3838         temp = r->mon + carry;
3839         r->mon = (unsigned int) MODULO_RANGE(temp, 1, 13);
3840         r->year = r->year + (unsigned int) FQUOTIENT_RANGE(temp, 1, 13);
3841         if (r->year == 0) {
3842             if (temp < 1)
3843                 r->year--;
3844             else
3845                 r->year++;
3846         }
3847     }
3848     
3849     r->day = tempdays;
3850
3851     /*
3852      * adjust the date/time type to the date values
3853      */
3854     if (ret->type != XML_SCHEMAS_DATETIME) {
3855         if ((r->hour) || (r->min) || (r->sec))
3856             ret->type = XML_SCHEMAS_DATETIME;
3857         else if (ret->type != XML_SCHEMAS_DATE) {
3858             if ((r->mon != 1) && (r->day != 1))
3859                 ret->type = XML_SCHEMAS_DATE;
3860             else if ((ret->type != XML_SCHEMAS_GYEARMONTH) && (r->mon != 1))
3861                 ret->type = XML_SCHEMAS_GYEARMONTH;
3862         }
3863     }
3864
3865     xmlSchemaFreeValue(tmp);
3866
3867     return ret;
3868 }
3869
3870 /**
3871  * xmlSchemaDateNormalize:
3872  * @dt: an #xmlSchemaValPtr of a date/time type value.
3873  * @offset: number of seconds to adjust @dt by.
3874  *
3875  * Normalize @dt to GMT time. The @offset parameter is subtracted from
3876  * the return value is a time-zone offset is present on @dt.
3877  *
3878  * Returns a normalized copy of @dt or NULL if error.
3879  */
3880 static xmlSchemaValPtr
3881 xmlSchemaDateNormalize (xmlSchemaValPtr dt, double offset)
3882 {
3883     xmlSchemaValPtr dur, ret;
3884
3885     if (dt == NULL)
3886         return NULL;
3887
3888     if (((dt->type != XML_SCHEMAS_TIME) &&
3889          (dt->type != XML_SCHEMAS_DATETIME) &&
3890          (dt->type != XML_SCHEMAS_DATE)) || (dt->value.date.tzo == 0))
3891         return xmlSchemaDupVal(dt);
3892
3893     dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
3894     if (dur == NULL)
3895         return NULL;
3896
3897     dur->value.date.sec -= offset;
3898
3899     ret = _xmlSchemaDateAdd(dt, dur);
3900     if (ret == NULL)
3901         return NULL;
3902
3903     xmlSchemaFreeValue(dur);
3904
3905     /* ret->value.date.tzo = 0; */
3906     return ret;
3907 }
3908
3909 /**
3910  * _xmlSchemaDateCastYMToDays:
3911  * @dt: an #xmlSchemaValPtr
3912  *
3913  * Convert mon and year of @dt to total number of days. Take the 
3914  * number of years since (or before) 1 AD and add the number of leap
3915  * years. This is a function  because negative
3916  * years must be handled a little differently and there is no zero year.
3917  *
3918  * Returns number of days.
3919  */
3920 static long
3921 _xmlSchemaDateCastYMToDays (const xmlSchemaValPtr dt)
3922 {
3923     long ret;
3924     int mon;
3925
3926     mon = dt->value.date.mon;
3927     if (mon <= 0) mon = 1; /* normalization */
3928
3929     if (dt->value.date.year <= 0)
3930         ret = (dt->value.date.year * 365) +
3931               (((dt->value.date.year+1)/4)-((dt->value.date.year+1)/100)+
3932                ((dt->value.date.year+1)/400)) +
3933               DAY_IN_YEAR(0, mon, dt->value.date.year);
3934     else
3935         ret = ((dt->value.date.year-1) * 365) +
3936               (((dt->value.date.year-1)/4)-((dt->value.date.year-1)/100)+
3937                ((dt->value.date.year-1)/400)) +
3938               DAY_IN_YEAR(0, mon, dt->value.date.year);
3939
3940     return ret;
3941 }
3942
3943 /**
3944  * TIME_TO_NUMBER:
3945  * @dt:  an #xmlSchemaValPtr
3946  *
3947  * Calculates the number of seconds in the time portion of @dt.
3948  *
3949  * Returns seconds.
3950  */
3951 #define TIME_TO_NUMBER(dt)                              \
3952     ((double)((dt->value.date.hour * SECS_PER_HOUR) +   \
3953               (dt->value.date.min * SECS_PER_MIN) +     \
3954               (dt->value.date.tzo * SECS_PER_MIN)) +    \
3955                dt->value.date.sec)
3956
3957 /**
3958  * xmlSchemaCompareDates:
3959  * @x:  a first date/time value
3960  * @y:  a second date/time value
3961  *
3962  * Compare 2 date/times
3963  *
3964  * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
3965  * case of error
3966  */
3967 static int
3968 xmlSchemaCompareDates (xmlSchemaValPtr x, xmlSchemaValPtr y)
3969 {
3970     unsigned char xmask, ymask, xor_mask, and_mask;
3971     xmlSchemaValPtr p1, p2, q1, q2;
3972     long p1d, p2d, q1d, q2d;
3973
3974     if ((x == NULL) || (y == NULL))
3975         return -2;
3976
3977     if (x->value.date.tz_flag) {
3978
3979         if (!y->value.date.tz_flag) {
3980             p1 = xmlSchemaDateNormalize(x, 0);
3981             p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
3982             /* normalize y + 14:00 */
3983             q1 = xmlSchemaDateNormalize(y, (14 * SECS_PER_HOUR));
3984
3985             q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
3986             if (p1d < q1d) {
3987                 xmlSchemaFreeValue(p1);
3988                 xmlSchemaFreeValue(q1);
3989                 return -1;
3990             } else if (p1d == q1d) {
3991                 double sec;
3992
3993                 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
3994                 if (sec < 0.0) {
3995                     xmlSchemaFreeValue(p1);
3996                     xmlSchemaFreeValue(q1);
3997                     return -1;
3998                 } else {
3999                     int ret = 0;
4000                     /* normalize y - 14:00 */
4001                     q2 = xmlSchemaDateNormalize(y, -(14 * SECS_PER_HOUR));
4002                     q2d = _xmlSchemaDateCastYMToDays(q2) + q2->value.date.day;
4003                     if (p1d > q2d)
4004                         ret = 1;
4005                     else if (p1d == q2d) {
4006                         sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q2);
4007                         if (sec > 0.0)
4008                             ret = 1;
4009                         else
4010                             ret = 2; /* indeterminate */
4011                     }
4012                     xmlSchemaFreeValue(p1);
4013                     xmlSchemaFreeValue(q1);
4014                     xmlSchemaFreeValue(q2);
4015                     if (ret != 0)
4016                         return(ret);
4017                 }
4018             } else {
4019                 xmlSchemaFreeValue(p1);
4020                 xmlSchemaFreeValue(q1);
4021             }
4022         }
4023     } else if (y->value.date.tz_flag) {
4024         q1 = xmlSchemaDateNormalize(y, 0);
4025         q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
4026
4027         /* normalize x - 14:00 */
4028         p1 = xmlSchemaDateNormalize(x, -(14 * SECS_PER_HOUR));
4029         p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
4030
4031         if (p1d < q1d) {
4032             xmlSchemaFreeValue(p1);
4033             xmlSchemaFreeValue(q1);
4034             return -1;
4035         } else if (p1d == q1d) {
4036             double sec;
4037
4038             sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
4039             if (sec < 0.0) {
4040                 xmlSchemaFreeValue(p1);
4041                 xmlSchemaFreeValue(q1);
4042                 return -1;
4043             } else {
4044                 int ret = 0;
4045                 /* normalize x + 14:00 */
4046                 p2 = xmlSchemaDateNormalize(x, (14 * SECS_PER_HOUR));
4047                 p2d = _xmlSchemaDateCastYMToDays(p2) + p2->value.date.day;
4048
4049                 if (p2d > q1d) {
4050                     ret = 1;
4051                 } else if (p2d == q1d) {
4052                     sec = TIME_TO_NUMBER(p2) - TIME_TO_NUMBER(q1);
4053                     if (sec > 0.0)
4054                         ret = 1;
4055                     else
4056                         ret = 2; /* indeterminate */
4057                 }
4058                 xmlSchemaFreeValue(p1);
4059                 xmlSchemaFreeValue(q1);
4060                 xmlSchemaFreeValue(p2);
4061                 if (ret != 0)
4062                     return(ret);
4063             }
4064         } else {
4065             xmlSchemaFreeValue(p1);
4066             xmlSchemaFreeValue(q1);
4067         }
4068     }
4069
4070     /*
4071      * if the same type then calculate the difference
4072      */
4073     if (x->type == y->type) {
4074         int ret = 0;
4075         q1 = xmlSchemaDateNormalize(y, 0);
4076         q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
4077
4078         p1 = xmlSchemaDateNormalize(x, 0);
4079         p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
4080
4081         if (p1d < q1d) {
4082             ret = -1;
4083         } else if (p1d > q1d) {
4084             ret = 1;
4085         } else {
4086             double sec;
4087
4088             sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
4089             if (sec < 0.0)
4090                 ret = -1;
4091             else if (sec > 0.0)
4092                 ret = 1;
4093             
4094         }
4095         xmlSchemaFreeValue(p1);
4096         xmlSchemaFreeValue(q1);
4097         return(ret);
4098     }
4099
4100     switch (x->type) {
4101         case XML_SCHEMAS_DATETIME:
4102             xmask = 0xf;
4103             break;
4104         case XML_SCHEMAS_DATE:
4105             xmask = 0x7;
4106             break;
4107         case XML_SCHEMAS_GYEAR:
4108             xmask = 0x1;
4109             break;
4110         case XML_SCHEMAS_GMONTH:
4111             xmask = 0x2;
4112             break;
4113         case XML_SCHEMAS_GDAY:
4114             xmask = 0x3;
4115             break;
4116         case XML_SCHEMAS_GYEARMONTH:
4117             xmask = 0x3;
4118             break;
4119         case XML_SCHEMAS_GMONTHDAY:
4120             xmask = 0x6;
4121             break;
4122         case XML_SCHEMAS_TIME:
4123             xmask = 0x8;
4124             break;
4125         default:
4126             xmask = 0;
4127             break;
4128     }
4129
4130     switch (y->type) {
4131         case XML_SCHEMAS_DATETIME:
4132             ymask = 0xf;
4133             break;
4134         case XML_SCHEMAS_DATE:
4135             ymask = 0x7;
4136             break;
4137         case XML_SCHEMAS_GYEAR:
4138             ymask = 0x1;
4139             break;
4140         case XML_SCHEMAS_GMONTH:
4141             ymask = 0x2;
4142             break;
4143         case XML_SCHEMAS_GDAY:
4144             ymask = 0x3;
4145             break;
4146         case XML_SCHEMAS_GYEARMONTH:
4147             ymask = 0x3;
4148             break;
4149         case XML_SCHEMAS_GMONTHDAY:
4150             ymask = 0x6;
4151             break;
4152         case XML_SCHEMAS_TIME:
4153             ymask = 0x8;
4154             break;
4155         default:
4156             ymask = 0;
4157             break;
4158     }
4159
4160     xor_mask = xmask ^ ymask;           /* mark type differences */
4161     and_mask = xmask & ymask;           /* mark field specification */
4162
4163     /* year */
4164     if (xor_mask & 1)
4165         return 2; /* indeterminate */
4166     else if (and_mask & 1) {
4167         if (x->value.date.year < y->value.date.year)
4168             return -1;
4169         else if (x->value.date.year > y->value.date.year)
4170             return 1;
4171     }
4172
4173     /* month */
4174     if (xor_mask & 2)
4175         return 2; /* indeterminate */
4176     else if (and_mask & 2) {
4177         if (x->value.date.mon < y->value.date.mon)
4178             return -1;
4179         else if (x->value.date.mon > y->value.date.mon)
4180             return 1;
4181     }
4182
4183     /* day */
4184     if (xor_mask & 4)
4185         return 2; /* indeterminate */
4186     else if (and_mask & 4) {
4187         if (x->value.date.day < y->value.date.day)
4188             return -1;
4189         else if (x->value.date.day > y->value.date.day)
4190             return 1;
4191     }
4192
4193     /* time */
4194     if (xor_mask & 8)
4195         return 2; /* indeterminate */
4196     else if (and_mask & 8) {
4197         if (x->value.date.hour < y->value.date.hour)
4198             return -1;
4199         else if (x->value.date.hour > y->value.date.hour)
4200             return 1;
4201         else if (x->value.date.min < y->value.date.min)
4202             return -1;
4203         else if (x->value.date.min > y->value.date.min)
4204             return 1;
4205         else if (x->value.date.sec < y->value.date.sec)
4206             return -1;
4207         else if (x->value.date.sec > y->value.date.sec)
4208             return 1;
4209     }
4210
4211     return 0;
4212 }
4213
4214 /**
4215  * xmlSchemaComparePreserveReplaceStrings:
4216  * @x:  a first string value
4217  * @y:  a second string value
4218  * @invert: inverts the result if x < y or x > y.
4219  *
4220  * Compare 2 string for their normalized values.
4221  * @x is a string with whitespace of "preserve", @y is
4222  * a string with a whitespace of "replace". I.e. @x could
4223  * be an "xsd:string" and @y an "xsd:normalizedString".
4224  *
4225  * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
4226  * case of error
4227  */
4228 static int
4229 xmlSchemaComparePreserveReplaceStrings(const xmlChar *x,
4230                                        const xmlChar *y,
4231                                        int invert)
4232 {
4233     int tmp;
4234     
4235     while ((*x != 0) && (*y != 0)) {
4236         if (IS_WSP_REPLACE_CH(*y)) {
4237             if (! IS_WSP_SPACE_CH(*x)) {
4238                 if ((*x - 0x20) < 0) {
4239                     if (invert)
4240                         return(1);
4241                     else
4242                         return(-1);
4243                 } else {
4244                     if (invert)
4245                         return(-1);
4246                     else
4247                         return(1);
4248                 }
4249             }       
4250         } else {
4251             tmp = *x - *y;
4252             if (tmp < 0) {
4253                 if (invert)
4254                     return(1);
4255                 else
4256                     return(-1);
4257             }
4258             if (tmp > 0) {
4259                 if (invert)
4260                     return(-1);
4261                 else
4262                     return(1);
4263             }
4264         }
4265         x++;
4266         y++;
4267     }
4268     if (*x != 0) {
4269         if (invert)
4270             return(-1);
4271         else
4272             return(1);
4273     }
4274     if (*y != 0) {
4275         if (invert)
4276             return(1);
4277         else
4278             return(-1);
4279     }
4280     return(0);
4281 }
4282
4283 /**
4284  * xmlSchemaComparePreserveCollapseStrings:
4285  * @x:  a first string value
4286  * @y:  a second string value
4287  *
4288  * Compare 2 string for their normalized values.
4289  * @x is a string with whitespace of "preserve", @y is
4290  * a string with a whitespace of "collapse". I.e. @x could
4291  * be an "xsd:string" and @y an "xsd:normalizedString".
4292  *
4293  * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
4294  * case of error
4295  */
4296 static int
4297 xmlSchemaComparePreserveCollapseStrings(const xmlChar *x,
4298                                         const xmlChar *y,
4299                                         int invert)
4300 {
4301     int tmp;
4302
4303     /* 
4304     * Skip leading blank chars of the collapsed string.
4305     */
4306     while IS_WSP_BLANK_CH(*y)
4307         y++;
4308
4309     while ((*x != 0) && (*y != 0)) {
4310         if IS_WSP_BLANK_CH(*y) {
4311             if (! IS_WSP_SPACE_CH(*x)) {
4312                 /*
4313                 * The yv character would have been replaced to 0x20.
4314                 */
4315                 if ((*x - 0x20) < 0) {
4316                     if (invert)
4317                         return(1);
4318                     else
4319                         return(-1);
4320                 } else {
4321                     if (invert)
4322                         return(-1);
4323                     else
4324                         return(1);
4325                 }
4326             }
4327             x++;
4328             y++;
4329             /*
4330             * Skip contiguous blank chars of the collapsed string.
4331             */
4332             while IS_WSP_BLANK_CH(*y)
4333                 y++;
4334         } else {
4335             tmp = *x++ - *y++;
4336             if (tmp < 0) {
4337                 if (invert)
4338                     return(1);
4339                 else
4340                     return(-1);
4341             }
4342             if (tmp > 0) {
4343                 if (invert)
4344                     return(-1);
4345                 else
4346                     return(1);
4347             }
4348         }
4349     }
4350     if (*x != 0) {
4351          if (invert)
4352              return(-1);
4353          else
4354              return(1);
4355     }
4356     if (*y != 0) {
4357         /*
4358         * Skip trailing blank chars of the collapsed string.
4359         */
4360         while IS_WSP_BLANK_CH(*y)
4361             y++;
4362         if (*y != 0) {
4363             if (invert)
4364                 return(1);
4365             else
4366                 return(-1);
4367         }
4368     }
4369     return(0);
4370 }
4371
4372 /**
4373  * xmlSchemaComparePreserveCollapseStrings:
4374  * @x:  a first string value
4375  * @y:  a second string value
4376  *
4377  * Compare 2 string for their normalized values.
4378  * @x is a string with whitespace of "preserve", @y is
4379  * a string with a whitespace of "collapse". I.e. @x could
4380  * be an "xsd:string" and @y an "xsd:normalizedString".
4381  *
4382  * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
4383  * case of error
4384  */
4385 static int
4386 xmlSchemaCompareReplaceCollapseStrings(const xmlChar *x,
4387                                        const xmlChar *y,
4388                                        int invert)
4389 {
4390     int tmp;
4391
4392     /* 
4393     * Skip leading blank chars of the collapsed string.
4394     */
4395     while IS_WSP_BLANK_CH(*y)
4396         y++;
4397     
4398     while ((*x != 0) && (*y != 0)) {
4399         if IS_WSP_BLANK_CH(*y) {
4400             if (! IS_WSP_BLANK_CH(*x)) {
4401                 /*
4402                 * The yv character would have been replaced to 0x20.
4403                 */
4404                 if ((*x - 0x20) < 0) {
4405                     if (invert)
4406                         return(1);
4407                     else
4408                         return(-1);
4409                 } else {
4410                     if (invert)
4411                         return(-1);
4412                     else
4413                         return(1);
4414                 }
4415             }
4416             x++;
4417             y++;            
4418             /* 
4419             * Skip contiguous blank chars of the collapsed string.
4420             */
4421             while IS_WSP_BLANK_CH(*y)
4422                 y++;
4423         } else {
4424             if IS_WSP_BLANK_CH(*x) {
4425                 /*
4426                 * The xv character would have been replaced to 0x20.
4427                 */
4428                 if ((0x20 - *y) < 0) {
4429                     if (invert)
4430                         return(1);
4431                     else
4432                         return(-1);
4433                 } else {
4434                     if (invert)
4435                         return(-1);
4436                     else
4437                         return(1);
4438                 }
4439             }
4440             tmp = *x++ - *y++;
4441             if (tmp < 0)
4442                 return(-1);
4443             if (tmp > 0)
4444                 return(1);
4445         }
4446     }
4447     if (*x != 0) {
4448          if (invert)
4449              return(-1);
4450          else
4451              return(1);
4452     }   
4453     if (*y != 0) {
4454         /*
4455         * Skip trailing blank chars of the collapsed string.
4456         */
4457         while IS_WSP_BLANK_CH(*y)
4458             y++;
4459         if (*y != 0) {
4460             if (invert)
4461                 return(1);
4462             else
4463                 return(-1);
4464         }
4465     }
4466     return(0);
4467 }
4468
4469
4470 /**
4471  * xmlSchemaCompareReplacedStrings:
4472  * @x:  a first string value
4473  * @y:  a second string value
4474  *
4475  * Compare 2 string for their normalized values.
4476  *
4477  * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
4478  * case of error
4479  */
4480 static int
4481 xmlSchemaCompareReplacedStrings(const xmlChar *x,
4482                                 const xmlChar *y)
4483 {
4484     int tmp;
4485    
4486     while ((*x != 0) && (*y != 0)) {
4487         if IS_WSP_BLANK_CH(*y) {
4488             if (! IS_WSP_BLANK_CH(*x)) {
4489                 if ((*x - 0x20) < 0)
4490                     return(-1);
4491                 else
4492                     return(1);
4493             }       
4494         } else {
4495             if IS_WSP_BLANK_CH(*x) {
4496                 if ((0x20 - *y) < 0)
4497                     return(-1);
4498                 else
4499                     return(1);
4500             }
4501             tmp = *x - *y;
4502             if (tmp < 0)
4503                 return(-1);
4504             if (tmp > 0)
4505                 return(1);
4506         }
4507         x++;
4508         y++;
4509     }
4510     if (*x != 0)
4511         return(1);
4512     if (*y != 0)
4513         return(-1);
4514     return(0);
4515 }
4516
4517 /**
4518  * xmlSchemaCompareNormStrings:
4519  * @x:  a first string value
4520  * @y:  a second string value
4521  *
4522  * Compare 2 string for their normalized values.
4523  *
4524  * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
4525  * case of error
4526  */
4527 static int
4528 xmlSchemaCompareNormStrings(const xmlChar *x,
4529                             const xmlChar *y) {
4530     int tmp;
4531     
4532     while (IS_BLANK_CH(*x)) x++;
4533     while (IS_BLANK_CH(*y)) y++;
4534     while ((*x != 0) && (*y != 0)) {
4535         if (IS_BLANK_CH(*x)) {
4536             if (!IS_BLANK_CH(*y)) {
4537                 tmp = *x - *y;
4538                 return(tmp);
4539             }
4540             while (IS_BLANK_CH(*x)) x++;
4541             while (IS_BLANK_CH(*y)) y++;
4542         } else {
4543             tmp = *x++ - *y++;
4544             if (tmp < 0)
4545                 return(-1);
4546             if (tmp > 0)
4547                 return(1);
4548         }
4549     }
4550     if (*x != 0) {
4551         while (IS_BLANK_CH(*x)) x++;
4552         if (*x != 0)
4553             return(1);
4554     }
4555     if (*y != 0) {
4556         while (IS_BLANK_CH(*y)) y++;
4557         if (*y != 0)
4558             return(-1);
4559     }
4560     return(0);
4561 }
4562
4563 /**
4564  * xmlSchemaCompareFloats:
4565  * @x:  a first float or double value
4566  * @y:  a second float or double value
4567  *
4568  * Compare 2 values
4569  *
4570  * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
4571  * case of error
4572  */
4573 static int
4574 xmlSchemaCompareFloats(xmlSchemaValPtr x, xmlSchemaValPtr y) {
4575     double d1, d2;
4576
4577     if ((x == NULL) || (y == NULL))
4578         return(-2);
4579
4580     /*
4581      * Cast everything to doubles.
4582      */
4583     if (x->type == XML_SCHEMAS_DOUBLE)
4584         d1 = x->value.d;
4585     else if (x->type == XML_SCHEMAS_FLOAT)
4586         d1 = x->value.f;
4587     else
4588         return(-2);
4589
4590     if (y->type == XML_SCHEMAS_DOUBLE)
4591         d2 = y->value.d;
4592     else if (y->type == XML_SCHEMAS_FLOAT)
4593         d2 = y->value.f;
4594     else
4595         return(-2);
4596
4597     /*
4598      * Check for special cases.
4599      */
4600     if (xmlXPathIsNaN(d1)) {
4601         if (xmlXPathIsNaN(d2))
4602             return(0);
4603         return(1);
4604     }
4605     if (xmlXPathIsNaN(d2))
4606         return(-1);
4607     if (d1 == xmlXPathPINF) {
4608         if (d2 == xmlXPathPINF)
4609             return(0);
4610         return(1);
4611     }
4612     if (d2 == xmlXPathPINF)
4613         return(-1);
4614     if (d1 == xmlXPathNINF) {
4615         if (d2 == xmlXPathNINF)
4616             return(0);
4617         return(-1);
4618     }
4619     if (d2 == xmlXPathNINF)
4620         return(1);
4621
4622     /*
4623      * basic tests, the last one we should have equality, but
4624      * portability is more important than speed and handling
4625      * NaN or Inf in a portable way is always a challenge, so ...
4626      */
4627     if (d1 < d2)
4628         return(-1);
4629     if (d1 > d2)
4630         return(1);
4631     if (d1 == d2)
4632         return(0);
4633     return(2);
4634 }
4635
4636 /**
4637  * xmlSchemaCompareValues:
4638  * @x:  a first value
4639  * @xvalue: the first value as a string (optional)
4640  * @xwtsp: the whitespace type
4641  * @y:  a second value
4642  * @xvalue: the second value as a string (optional)
4643  * @ywtsp: the whitespace type
4644  *
4645  * Compare 2 values
4646  *
4647  * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, 3 if not
4648  * comparable and -2 in case of error
4649  */
4650 static int
4651 xmlSchemaCompareValuesInternal(xmlSchemaValType xtype,
4652                                xmlSchemaValPtr x,
4653                                const xmlChar *xvalue,
4654                                xmlSchemaWhitespaceValueType xws,
4655                                xmlSchemaValType ytype,
4656                                xmlSchemaValPtr y,
4657                                const xmlChar *yvalue,
4658                                xmlSchemaWhitespaceValueType yws)
4659 {
4660     switch (xtype) {
4661         case XML_SCHEMAS_UNKNOWN:
4662         case XML_SCHEMAS_ANYTYPE:
4663             return(-2);
4664         case XML_SCHEMAS_INTEGER:
4665         case XML_SCHEMAS_NPINTEGER:
4666         case XML_SCHEMAS_NINTEGER:
4667         case XML_SCHEMAS_NNINTEGER:
4668         case XML_SCHEMAS_PINTEGER:
4669         case XML_SCHEMAS_INT:
4670         case XML_SCHEMAS_UINT:
4671         case XML_SCHEMAS_LONG:
4672         case XML_SCHEMAS_ULONG:
4673         case XML_SCHEMAS_SHORT:
4674         case XML_SCHEMAS_USHORT:
4675         case XML_SCHEMAS_BYTE:
4676         case XML_SCHEMAS_UBYTE:
4677         case XML_SCHEMAS_DECIMAL:
4678             if ((x == NULL) || (y == NULL))
4679                 return(-2);
4680             if (ytype == xtype)
4681                 return(xmlSchemaCompareDecimals(x, y));
4682             if ((ytype == XML_SCHEMAS_DECIMAL) ||
4683                 (ytype == XML_SCHEMAS_INTEGER) ||
4684                 (ytype == XML_SCHEMAS_NPINTEGER) ||
4685                 (ytype == XML_SCHEMAS_NINTEGER) ||
4686                 (ytype == XML_SCHEMAS_NNINTEGER) ||
4687                 (ytype == XML_SCHEMAS_PINTEGER) ||
4688                 (ytype == XML_SCHEMAS_INT) ||
4689                 (ytype == XML_SCHEMAS_UINT) ||
4690                 (ytype == XML_SCHEMAS_LONG) ||
4691                 (ytype == XML_SCHEMAS_ULONG) ||
4692                 (ytype == XML_SCHEMAS_SHORT) ||
4693                 (ytype == XML_SCHEMAS_USHORT) ||
4694                 (ytype == XML_SCHEMAS_BYTE) ||
4695                 (ytype == XML_SCHEMAS_UBYTE))
4696                 return(xmlSchemaCompareDecimals(x, y));
4697             return(-2);
4698         case XML_SCHEMAS_DURATION:
4699             if ((x == NULL) || (y == NULL))
4700                 return(-2);
4701             if (ytype == XML_SCHEMAS_DURATION)
4702                 return(xmlSchemaCompareDurations(x, y));
4703             return(-2);
4704         case XML_SCHEMAS_TIME:
4705         case XML_SCHEMAS_GDAY:
4706         case XML_SCHEMAS_GMONTH:
4707         case XML_SCHEMAS_GMONTHDAY:
4708         case XML_SCHEMAS_GYEAR:
4709         case XML_SCHEMAS_GYEARMONTH:
4710         case XML_SCHEMAS_DATE:
4711         case XML_SCHEMAS_DATETIME:
4712             if ((x == NULL) || (y == NULL))
4713                 return(-2);
4714             if ((ytype == XML_SCHEMAS_DATETIME)  ||
4715                 (ytype == XML_SCHEMAS_TIME)      ||
4716                 (ytype == XML_SCHEMAS_GDAY)      ||
4717                 (ytype == XML_SCHEMAS_GMONTH)    ||
4718                 (ytype == XML_SCHEMAS_GMONTHDAY) ||
4719                 (ytype == XML_SCHEMAS_GYEAR)     ||
4720                 (ytype == XML_SCHEMAS_DATE)      ||
4721                 (ytype == XML_SCHEMAS_GYEARMONTH))
4722                 return (xmlSchemaCompareDates(x, y));
4723             return (-2);
4724         /* 
4725         * Note that we will support comparison of string types against
4726         * anySimpleType as well.
4727         */
4728         case XML_SCHEMAS_ANYSIMPLETYPE:
4729         case XML_SCHEMAS_STRING:
4730         case XML_SCHEMAS_NORMSTRING:            
4731         case XML_SCHEMAS_TOKEN:
4732         case XML_SCHEMAS_LANGUAGE:
4733         case XML_SCHEMAS_NMTOKEN:
4734         case XML_SCHEMAS_NAME:
4735         case XML_SCHEMAS_NCNAME:
4736         case XML_SCHEMAS_ID:
4737         case XML_SCHEMAS_IDREF:
4738         case XML_SCHEMAS_ENTITY:
4739         case XML_SCHEMAS_ANYURI:
4740         {
4741             const xmlChar *xv, *yv;
4742
4743             if (x == NULL)
4744                 xv = xvalue;
4745             else
4746                 xv = x->value.str;
4747             if (y == NULL)
4748                 yv = yvalue;
4749             else
4750                 yv = y->value.str;
4751             /*
4752             * TODO: Compare those against QName.
4753             */
4754             if (ytype == XML_SCHEMAS_QNAME) {           
4755                 TODO
4756                 if (y == NULL)
4757                     return(-2);    
4758                 return (-2);
4759             }
4760             if ((ytype == XML_SCHEMAS_ANYSIMPLETYPE) ||
4761                 (ytype == XML_SCHEMAS_STRING) ||
4762                 (ytype == XML_SCHEMAS_NORMSTRING) ||
4763                 (ytype == XML_SCHEMAS_TOKEN) ||
4764                 (ytype == XML_SCHEMAS_LANGUAGE) ||
4765                 (ytype == XML_SCHEMAS_NMTOKEN) ||
4766                 (ytype == XML_SCHEMAS_NAME) ||
4767                 (ytype == XML_SCHEMAS_NCNAME) ||
4768                 (ytype == XML_SCHEMAS_ID) ||
4769                 (ytype == XML_SCHEMAS_IDREF) ||
4770                 (ytype == XML_SCHEMAS_ENTITY) ||
4771                 (ytype == XML_SCHEMAS_ANYURI)) {
4772
4773                 if (xws == XML_SCHEMA_WHITESPACE_PRESERVE) {
4774
4775                     if (yws == XML_SCHEMA_WHITESPACE_PRESERVE) {
4776                         /* TODO: What about x < y or x > y. */
4777                         if (xmlStrEqual(xv, yv))
4778                             return (0);
4779                         else 
4780                             return (2);
4781                     } else if (yws == XML_SCHEMA_WHITESPACE_REPLACE)
4782                         return (xmlSchemaComparePreserveReplaceStrings(xv, yv, 0));
4783                     else if (yws == XML_SCHEMA_WHITESPACE_COLLAPSE)
4784                         return (xmlSchemaComparePreserveCollapseStrings(xv, yv, 0));
4785
4786                 } else if (xws == XML_SCHEMA_WHITESPACE_REPLACE) {
4787
4788                     if (yws == XML_SCHEMA_WHITESPACE_PRESERVE)
4789                         return (xmlSchemaComparePreserveReplaceStrings(yv, xv, 1));
4790                     if (yws == XML_SCHEMA_WHITESPACE_REPLACE)
4791                         return (xmlSchemaCompareReplacedStrings(xv, yv));
4792                     if (yws == XML_SCHEMA_WHITESPACE_COLLAPSE)
4793                         return (xmlSchemaCompareReplaceCollapseStrings(xv, yv, 0));
4794
4795                 } else if (xws == XML_SCHEMA_WHITESPACE_COLLAPSE) {
4796
4797                     if (yws == XML_SCHEMA_WHITESPACE_PRESERVE)
4798                         return (xmlSchemaComparePreserveCollapseStrings(yv, xv, 1));
4799                     if (yws == XML_SCHEMA_WHITESPACE_REPLACE)
4800                         return (xmlSchemaCompareReplaceCollapseStrings(yv, xv, 1));
4801                     if (yws == XML_SCHEMA_WHITESPACE_COLLAPSE)
4802                         return (xmlSchemaCompareNormStrings(xv, yv));
4803                 } else
4804                     return (-2);
4805                 
4806             }
4807             return (-2);
4808         }
4809         case XML_SCHEMAS_QNAME:
4810         case XML_SCHEMAS_NOTATION:
4811             if ((x == NULL) || (y == NULL))
4812                 return(-2);
4813             if ((ytype == XML_SCHEMAS_QNAME) ||
4814                 (ytype == XML_SCHEMAS_NOTATION)) {
4815                 if ((xmlStrEqual(x->value.qname.name, y->value.qname.name)) &&
4816                     (xmlStrEqual(x->value.qname.uri, y->value.qname.uri)))
4817                     return(0);
4818                 return(2);
4819             }
4820             return (-2);
4821         case XML_SCHEMAS_FLOAT:
4822         case XML_SCHEMAS_DOUBLE:
4823             if ((x == NULL) || (y == NULL))
4824                 return(-2);
4825             if ((ytype == XML_SCHEMAS_FLOAT) ||
4826                 (ytype == XML_SCHEMAS_DOUBLE))
4827                 return (xmlSchemaCompareFloats(x, y));
4828             return (-2);
4829         case XML_SCHEMAS_BOOLEAN:
4830             if ((x == NULL) || (y == NULL))
4831                 return(-2);
4832             if (ytype == XML_SCHEMAS_BOOLEAN) {
4833                 if (x->value.b == y->value.b)
4834                     return(0);
4835                 if (x->value.b == 0)
4836                     return(-1);
4837                 return(1);
4838             }
4839             return (-2);
4840         case XML_SCHEMAS_HEXBINARY:
4841             if ((x == NULL) || (y == NULL))
4842                 return(-2);
4843             if (ytype == XML_SCHEMAS_HEXBINARY) {
4844                 if (x->value.hex.total == y->value.hex.total) {
4845                     int ret = xmlStrcmp(x->value.hex.str, y->value.hex.str);
4846                     if (ret > 0)
4847                         return(1);
4848                     else if (ret == 0)
4849                         return(0);
4850                 }
4851                 else if (x->value.hex.total > y->value.hex.total)
4852                     return(1);
4853
4854                 return(-1);
4855             }
4856             return (-2);
4857         case XML_SCHEMAS_BASE64BINARY:
4858             if ((x == NULL) || (y == NULL))
4859                 return(-2);
4860             if (ytype == XML_SCHEMAS_BASE64BINARY) {
4861                 if (x->value.base64.total == y->value.base64.total) {
4862                     int ret = xmlStrcmp(x->value.base64.str,
4863                                         y->value.base64.str);
4864                     if (ret > 0)
4865                         return(1);
4866                     else if (ret == 0)
4867                         return(0);
4868                     else
4869                         return(-1);
4870                 }
4871                 else if (x->value.base64.total > y->value.base64.total)
4872                     return(1);
4873                 else
4874                     return(-1);
4875             }
4876             return (-2);    
4877         case XML_SCHEMAS_IDREFS:
4878         case XML_SCHEMAS_ENTITIES:
4879         case XML_SCHEMAS_NMTOKENS:
4880             TODO
4881             break;
4882     }
4883     return -2;
4884 }
4885
4886 /**
4887  * xmlSchemaCompareValues:
4888  * @x:  a first value
4889  * @y:  a second value
4890  *
4891  * Compare 2 values
4892  *
4893  * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
4894  * case of error
4895  */
4896 int
4897 xmlSchemaCompareValues(xmlSchemaValPtr x, xmlSchemaValPtr y) {
4898     xmlSchemaWhitespaceValueType xws, yws;
4899
4900     if ((x == NULL) || (y == NULL))
4901         return(-2);
4902     if (x->type == XML_SCHEMAS_STRING)
4903         xws = XML_SCHEMA_WHITESPACE_PRESERVE;
4904     else if (x->type == XML_SCHEMAS_NORMSTRING)
4905         xws = XML_SCHEMA_WHITESPACE_REPLACE;
4906     else
4907         xws = XML_SCHEMA_WHITESPACE_COLLAPSE;
4908
4909     if (y->type == XML_SCHEMAS_STRING)
4910         yws = XML_SCHEMA_WHITESPACE_PRESERVE;
4911     else if (x->type == XML_SCHEMAS_NORMSTRING)
4912         yws = XML_SCHEMA_WHITESPACE_REPLACE;
4913     else
4914         yws = XML_SCHEMA_WHITESPACE_COLLAPSE;
4915
4916     return(xmlSchemaCompareValuesInternal(x->type, x, NULL, xws, y->type,
4917         y, NULL, yws));
4918 }
4919
4920 /**
4921  * xmlSchemaCompareValuesWhtsp:
4922  * @x:  a first value
4923  * @xws: the whitespace value of x
4924  * @y:  a second value
4925  * @yws: the whitespace value of y
4926  *
4927  * Compare 2 values
4928  *
4929  * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
4930  * case of error
4931  */
4932 int
4933 xmlSchemaCompareValuesWhtsp(xmlSchemaValPtr x,
4934                             xmlSchemaWhitespaceValueType xws,
4935                             xmlSchemaValPtr y,
4936                             xmlSchemaWhitespaceValueType yws)
4937 {
4938     if ((x == NULL) || (y == NULL))
4939         return(-2);
4940     return(xmlSchemaCompareValuesInternal(x->type, x, NULL, xws, y->type,
4941         y, NULL, yws));
4942 }
4943
4944 /**
4945  * xmlSchemaCompareValuesWhtspExt:
4946  * @x:  a first value
4947  * @xws: the whitespace value of x
4948  * @y:  a second value
4949  * @yws: the whitespace value of y
4950  *
4951  * Compare 2 values
4952  *
4953  * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
4954  * case of error
4955  */
4956 static int
4957 xmlSchemaCompareValuesWhtspExt(xmlSchemaValType xtype,
4958                                xmlSchemaValPtr x,
4959                                const xmlChar *xvalue,
4960                                xmlSchemaWhitespaceValueType xws,
4961                                xmlSchemaValType ytype,
4962                                xmlSchemaValPtr y,
4963                                const xmlChar *yvalue,
4964                                xmlSchemaWhitespaceValueType yws)
4965 {
4966     return(xmlSchemaCompareValuesInternal(xtype, x, xvalue, xws, ytype, y,
4967         yvalue, yws));
4968 }
4969
4970 /**
4971  * xmlSchemaNormLen:
4972  * @value:  a string
4973  *
4974  * Computes the UTF8 length of the normalized value of the string
4975  *
4976  * Returns the length or -1 in case of error.
4977  */
4978 static int
4979 xmlSchemaNormLen(const xmlChar *value) {
4980     const xmlChar *utf;
4981     int ret = 0;
4982
4983     if (value == NULL)
4984         return(-1);
4985     utf = value;
4986     while (IS_BLANK_CH(*utf)) utf++;
4987     while (*utf != 0) {
4988         if (utf[0] & 0x80) {
4989             if ((utf[1] & 0xc0) != 0x80)
4990                 return(-1);
4991             if ((utf[0] & 0xe0) == 0xe0) {
4992                 if ((utf[2] & 0xc0) != 0x80)
4993                     return(-1);
4994                 if ((utf[0] & 0xf0) == 0xf0) {
4995                     if ((utf[0] & 0xf8) != 0xf0 || (utf[3] & 0xc0) != 0x80)
4996                         return(-1);
4997                     utf += 4;
4998                 } else {
4999                     utf += 3;
5000                 }
5001             } else {
5002                 utf += 2;
5003             }
5004         } else if (IS_BLANK_CH(*utf)) {
5005             while (IS_BLANK_CH(*utf)) utf++;
5006             if (*utf == 0)
5007                 break;
5008         } else {
5009             utf++;
5010         }
5011         ret++;
5012     }
5013     return(ret);
5014 }
5015
5016 /**
5017  * xmlSchemaGetFacetValueAsULong:
5018  * @facet: an schemas type facet
5019  *
5020  * Extract the value of a facet
5021  *
5022  * Returns the value as a long
5023  */
5024 unsigned long
5025 xmlSchemaGetFacetValueAsULong(xmlSchemaFacetPtr facet)
5026 {
5027     /*
5028     * TODO: Check if this is a decimal.
5029     */
5030     if (facet == NULL)
5031         return 0;
5032     return ((unsigned long) facet->val->value.decimal.lo);
5033 }
5034
5035 /**
5036  * xmlSchemaValidateListSimpleTypeFacet:
5037  * @facet:  the facet to check
5038  * @value:  the lexical repr of the value to validate
5039  * @actualLen:  the number of list items
5040  * @expectedLen: the resulting expected number of list items
5041  *
5042  * Checks the value of a list simple type against a facet.
5043  *
5044  * Returns 0 if the value is valid, a positive error code
5045  * number otherwise and -1 in case of an internal error.
5046  */
5047 int
5048 xmlSchemaValidateListSimpleTypeFacet(xmlSchemaFacetPtr facet,
5049                                      const xmlChar *value,
5050                                      unsigned long actualLen,
5051                                      unsigned long *expectedLen)
5052 {
5053     if (facet == NULL)
5054         return(-1);
5055     /*
5056     * TODO: Check if this will work with large numbers.
5057     * (compare value.decimal.mi and value.decimal.hi as well?).
5058     */
5059     if (facet->type == XML_SCHEMA_FACET_LENGTH) {
5060         if (actualLen != facet->val->value.decimal.lo) {
5061             if (expectedLen != NULL)
5062                 *expectedLen = facet->val->value.decimal.lo;
5063             return (XML_SCHEMAV_CVC_LENGTH_VALID);
5064         }       
5065     } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
5066         if (actualLen < facet->val->value.decimal.lo) {
5067             if (expectedLen != NULL)
5068                 *expectedLen = facet->val->value.decimal.lo;
5069             return (XML_SCHEMAV_CVC_MINLENGTH_VALID);
5070         }
5071     } else if (facet->type == XML_SCHEMA_FACET_MAXLENGTH) {
5072         if (actualLen > facet->val->value.decimal.lo) {
5073             if (expectedLen != NULL)
5074                 *expectedLen = facet->val->value.decimal.lo;
5075             return (XML_SCHEMAV_CVC_MAXLENGTH_VALID);
5076         }
5077     } else
5078         /* 
5079         * NOTE: That we can pass NULL as xmlSchemaValPtr to 
5080         * xmlSchemaValidateFacet, since the remaining facet types
5081         * are: XML_SCHEMA_FACET_PATTERN, XML_SCHEMA_FACET_ENUMERATION. 
5082         */
5083         return(xmlSchemaValidateFacet(NULL, facet, value, NULL));   
5084     return (0);
5085 }
5086
5087 /**
5088  * xmlSchemaValidateLengthFacet:
5089  * @type:  the built-in type
5090  * @facet:  the facet to check
5091  * @value:  the lexical repr. of the value to be validated
5092  * @val:  the precomputed value
5093  * @ws: the whitespace type of the value
5094  * @length: the actual length of the value
5095  *
5096  * Checka a value against a "length", "minLength" and "maxLength" 
5097  * facet; sets @length to the computed length of @value.
5098  *
5099  * Returns 0 if the value is valid, a positive error code
5100  * otherwise and -1 in case of an internal or API error.
5101  */
5102 static int
5103 xmlSchemaValidateLengthFacetInternal(xmlSchemaFacetPtr facet,
5104                                      xmlSchemaTypeType valType,
5105                                      const xmlChar *value,
5106                                      xmlSchemaValPtr val,                                    
5107                                      unsigned long *length,
5108                                      xmlSchemaWhitespaceValueType ws)  
5109 {
5110     unsigned int len = 0;
5111
5112     if ((length == NULL) || (facet == NULL))
5113         return (-1);
5114     *length = 0;
5115     if ((facet->type != XML_SCHEMA_FACET_LENGTH) &&
5116         (facet->type != XML_SCHEMA_FACET_MAXLENGTH) &&
5117         (facet->type != XML_SCHEMA_FACET_MINLENGTH))
5118         return (-1);
5119         
5120     /*
5121     * TODO: length, maxLength and minLength must be of type
5122     * nonNegativeInteger only. Check if decimal is used somehow.
5123     */
5124     if ((facet->val == NULL) ||
5125         ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
5126          (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
5127         (facet->val->value.decimal.frac != 0)) {
5128         return(-1);
5129     }
5130     if ((val != NULL) && (val->type == XML_SCHEMAS_HEXBINARY))
5131         len = val->value.hex.total;
5132     else if ((val != NULL) && (val->type == XML_SCHEMAS_BASE64BINARY))
5133         len = val->value.base64.total;
5134     else {
5135         switch (valType) {
5136             case XML_SCHEMAS_STRING:
5137             case XML_SCHEMAS_NORMSTRING:
5138                 if (ws == XML_SCHEMA_WHITESPACE_UNKNOWN) {
5139                     /*
5140                     * This is to ensure API compatibility with the old
5141                     * xmlSchemaValidateLengthFacet(). Anyway, this was and
5142                     * is not the correct handling.
5143                     * TODO: Get rid of this case somehow.
5144                     */
5145                     if (valType == XML_SCHEMAS_STRING)
5146                         len = xmlUTF8Strlen(value);
5147                     else
5148                         len = xmlSchemaNormLen(value);
5149                 } else if (value != NULL) {
5150                     if (ws == XML_SCHEMA_WHITESPACE_COLLAPSE)
5151                         len = xmlSchemaNormLen(value);
5152                     else
5153                     /* 
5154                     * Should be OK for "preserve" as well.
5155                     */
5156                     len = xmlUTF8Strlen(value);
5157                 }
5158                 break;
5159             case XML_SCHEMAS_IDREF:
5160             case XML_SCHEMAS_TOKEN:
5161             case XML_SCHEMAS_LANGUAGE:
5162             case XML_SCHEMAS_NMTOKEN:
5163             case XML_SCHEMAS_NAME:
5164             case XML_SCHEMAS_NCNAME:
5165             case XML_SCHEMAS_ID:                
5166                 /*
5167                 * FIXME: What exactly to do with anyURI?
5168                 */
5169             case XML_SCHEMAS_ANYURI:
5170                 if (value != NULL)
5171                     len = xmlSchemaNormLen(value);
5172                 break;
5173             case XML_SCHEMAS_QNAME:
5174             case XML_SCHEMAS_NOTATION:
5175                 /*
5176                 * For QName and NOTATION, those facets are
5177                 * deprecated and should be ignored.
5178                 */
5179                 return (0);
5180             default:
5181                 TODO
5182         }
5183     }
5184     *length = (unsigned long) len;
5185     /*
5186     * TODO: Return the whole expected value, i.e. "lo", "mi" and "hi".
5187     */
5188     if (facet->type == XML_SCHEMA_FACET_LENGTH) {
5189         if (len != facet->val->value.decimal.lo)
5190             return(XML_SCHEMAV_CVC_LENGTH_VALID);
5191     } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
5192         if (len < facet->val->value.decimal.lo)
5193             return(XML_SCHEMAV_CVC_MINLENGTH_VALID);
5194     } else {
5195         if (len > facet->val->value.decimal.lo)
5196             return(XML_SCHEMAV_CVC_MAXLENGTH_VALID);
5197     }
5198     
5199     return (0);
5200 }
5201
5202 /**
5203  * xmlSchemaValidateLengthFacet:
5204  * @type:  the built-in type
5205  * @facet:  the facet to check
5206  * @value:  the lexical repr. of the value to be validated
5207  * @val:  the precomputed value
5208  * @length: the actual length of the value
5209  *
5210  * Checka a value against a "length", "minLength" and "maxLength" 
5211  * facet; sets @length to the computed length of @value.
5212  *
5213  * Returns 0 if the value is valid, a positive error code
5214  * otherwise and -1 in case of an internal or API error.
5215  */
5216 int
5217 xmlSchemaValidateLengthFacet(xmlSchemaTypePtr type, 
5218                              xmlSchemaFacetPtr facet,
5219                              const xmlChar *value,
5220                              xmlSchemaValPtr val,
5221                              unsigned long *length)  
5222 {
5223     if (type == NULL)
5224         return(-1);
5225     return (xmlSchemaValidateLengthFacetInternal(facet,
5226         type->builtInType, value, val, length,
5227         XML_SCHEMA_WHITESPACE_UNKNOWN));
5228 }
5229
5230 /**
5231  * xmlSchemaValidateLengthFacetWhtsp: 
5232  * @facet:  the facet to check
5233  * @valType:  the built-in type
5234  * @value:  the lexical repr. of the value to be validated
5235  * @val:  the precomputed value
5236  * @ws: the whitespace type of the value
5237  * @length: the actual length of the value
5238  *
5239  * Checka a value against a "length", "minLength" and "maxLength" 
5240  * facet; sets @length to the computed length of @value.
5241  *
5242  * Returns 0 if the value is valid, a positive error code
5243  * otherwise and -1 in case of an internal or API error.
5244  */
5245 int
5246 xmlSchemaValidateLengthFacetWhtsp(xmlSchemaFacetPtr facet,
5247                                   xmlSchemaValType valType,
5248                                   const xmlChar *value,
5249                                   xmlSchemaValPtr val,
5250                                   unsigned long *length,
5251                                   xmlSchemaWhitespaceValueType ws)
5252 {
5253     return (xmlSchemaValidateLengthFacetInternal(facet, valType, value, val,
5254         length, ws));
5255 }
5256
5257 /**
5258  * xmlSchemaValidateFacetInternal:
5259  * @facet:  the facet to check
5260  * @fws: the whitespace type of the facet's value
5261  * @valType: the built-in type of the value
5262  * @value:  the lexical repr of the value to validate
5263  * @val:  the precomputed value
5264  * @ws: the whitespace type of the value
5265  *
5266  * Check a value against a facet condition
5267  *
5268  * Returns 0 if the element is schemas valid, a positive error code
5269  *     number otherwise and -1 in case of internal or API error.
5270  */
5271 static int
5272 xmlSchemaValidateFacetInternal(xmlSchemaFacetPtr facet,
5273                                xmlSchemaWhitespaceValueType fws,
5274                                xmlSchemaValType valType,                               
5275                                const xmlChar *value,
5276                                xmlSchemaValPtr val,
5277                                xmlSchemaWhitespaceValueType ws)
5278 {
5279     int ret;
5280
5281     if (facet == NULL)
5282         return(-1);
5283
5284     switch (facet->type) {
5285         case XML_SCHEMA_FACET_PATTERN:
5286             /* 
5287             * NOTE that for patterns, the @value needs to be the normalized
5288             * value, *not* the lexical initial value or the canonical value.
5289             */
5290             if (value == NULL)
5291                 return(-1);
5292             ret = xmlRegexpExec(facet->regexp, value);
5293             if (ret == 1)
5294                 return(0);
5295             if (ret == 0)
5296                 return(XML_SCHEMAV_CVC_PATTERN_VALID);
5297             return(ret);
5298         case XML_SCHEMA_FACET_MAXEXCLUSIVE:
5299             ret = xmlSchemaCompareValues(val, facet->val);
5300             if (ret == -2)
5301                 return(-1);
5302             if (ret == -1)
5303                 return(0);
5304             return(XML_SCHEMAV_CVC_MAXEXCLUSIVE_VALID);
5305         case XML_SCHEMA_FACET_MAXINCLUSIVE:
5306             ret = xmlSchemaCompareValues(val, facet->val);
5307             if (ret == -2)
5308                 return(-1);
5309             if ((ret == -1) || (ret == 0))
5310                 return(0);
5311             return(XML_SCHEMAV_CVC_MAXINCLUSIVE_VALID);
5312         case XML_SCHEMA_FACET_MINEXCLUSIVE:
5313             ret = xmlSchemaCompareValues(val, facet->val);
5314             if (ret == -2)
5315                 return(-1);
5316             if (ret == 1)
5317                 return(0);
5318             return(XML_SCHEMAV_CVC_MINEXCLUSIVE_VALID);
5319         case XML_SCHEMA_FACET_MININCLUSIVE:
5320             ret = xmlSchemaCompareValues(val, facet->val);
5321             if (ret == -2)
5322                 return(-1);
5323             if ((ret == 1) || (ret == 0))
5324                 return(0);
5325             return(XML_SCHEMAV_CVC_MININCLUSIVE_VALID);
5326         case XML_SCHEMA_FACET_WHITESPACE:
5327             /* TODO whitespaces */
5328             /*
5329             * NOTE: Whitespace should be handled to normalize
5330             * the value to be validated against a the facets;
5331             * not to normalize the value in-between.
5332             */
5333             return(0);
5334         case  XML_SCHEMA_FACET_ENUMERATION:
5335             if (ws == XML_SCHEMA_WHITESPACE_UNKNOWN) {
5336                 /*
5337                 * This is to ensure API compatibility with the old
5338                 * xmlSchemaValidateFacet().
5339                 * TODO: Get rid of this case.
5340                 */
5341                 if ((facet->value != NULL) &&
5342                     (xmlStrEqual(facet->value, value)))
5343                     return(0);
5344             } else {
5345                 ret = xmlSchemaCompareValuesWhtspExt(facet->val->type,
5346                     facet->val, facet->value, fws, valType, val,
5347                     value, ws);
5348                 if (ret == -2)
5349                     return(-1);
5350                 if (ret == 0)
5351                     return(0);
5352             }
5353             return(XML_SCHEMAV_CVC_ENUMERATION_VALID);
5354         case XML_SCHEMA_FACET_LENGTH:
5355             /*
5356             * SPEC (1.3) "if {primitive type definition} is QName or NOTATION,
5357             * then any {value} is facet-valid."
5358             */
5359             if ((valType == XML_SCHEMAS_QNAME) ||
5360                 (valType == XML_SCHEMAS_NOTATION))
5361                 return (0);
5362             /* No break on purpose. */
5363         case XML_SCHEMA_FACET_MAXLENGTH:
5364         case XML_SCHEMA_FACET_MINLENGTH: {
5365             unsigned int len = 0;
5366
5367             if ((valType == XML_SCHEMAS_QNAME) ||
5368                 (valType == XML_SCHEMAS_NOTATION))
5369                 return (0);
5370             /*
5371             * TODO: length, maxLength and minLength must be of type
5372             * nonNegativeInteger only. Check if decimal is used somehow.
5373             */
5374             if ((facet->val == NULL) ||
5375                 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
5376                  (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
5377                 (facet->val->value.decimal.frac != 0)) {
5378                 return(-1);
5379             }
5380             if ((val != NULL) && (val->type == XML_SCHEMAS_HEXBINARY))
5381                 len = val->value.hex.total;
5382             else if ((val != NULL) && (val->type == XML_SCHEMAS_BASE64BINARY))
5383                 len = val->value.base64.total;
5384             else {
5385                 switch (valType) {
5386                     case XML_SCHEMAS_STRING:
5387                     case XML_SCHEMAS_NORMSTRING:                        
5388                         if (ws == XML_SCHEMA_WHITESPACE_UNKNOWN) {
5389                             /*
5390                             * This is to ensure API compatibility with the old
5391                             * xmlSchemaValidateFacet(). Anyway, this was and
5392                             * is not the correct handling.
5393                             * TODO: Get rid of this case somehow.
5394                             */
5395                             if (valType == XML_SCHEMAS_STRING)
5396                                 len = xmlUTF8Strlen(value);
5397                             else
5398                                 len = xmlSchemaNormLen(value);
5399                         } else if (value != NULL) {
5400                             if (ws == XML_SCHEMA_WHITESPACE_COLLAPSE)
5401                                 len = xmlSchemaNormLen(value);
5402                             else
5403                                 /* 
5404                                 * Should be OK for "preserve" as well.
5405                                 */
5406                                 len = xmlUTF8Strlen(value);
5407                         }
5408                         break;
5409                     case XML_SCHEMAS_IDREF:                 
5410                     case XML_SCHEMAS_TOKEN:
5411                     case XML_SCHEMAS_LANGUAGE:
5412                     case XML_SCHEMAS_NMTOKEN:
5413                     case XML_SCHEMAS_NAME:
5414                     case XML_SCHEMAS_NCNAME:
5415                     case XML_SCHEMAS_ID:
5416                     case XML_SCHEMAS_ANYURI:
5417                         if (value != NULL)
5418                             len = xmlSchemaNormLen(value);
5419                         break;             
5420                     default:
5421                         TODO
5422                 }
5423             }
5424             if (facet->type == XML_SCHEMA_FACET_LENGTH) {
5425                 if (len != facet->val->value.decimal.lo)
5426                     return(XML_SCHEMAV_CVC_LENGTH_VALID);
5427             } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
5428                 if (len < facet->val->value.decimal.lo)
5429                     return(XML_SCHEMAV_CVC_MINLENGTH_VALID);
5430             } else {
5431                 if (len > facet->val->value.decimal.lo)
5432                     return(XML_SCHEMAV_CVC_MAXLENGTH_VALID);
5433             }
5434             break;
5435         }
5436         case XML_SCHEMA_FACET_TOTALDIGITS:
5437         case XML_SCHEMA_FACET_FRACTIONDIGITS:
5438
5439             if ((facet->val == NULL) ||
5440                 ((facet->val->type != XML_SCHEMAS_PINTEGER) &&
5441                  (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
5442                 (facet->val->value.decimal.frac != 0)) {
5443                 return(-1);
5444             }
5445             if ((val == NULL) ||
5446                 ((val->type != XML_SCHEMAS_DECIMAL) &&
5447                  (val->type != XML_SCHEMAS_INTEGER) &&
5448                  (val->type != XML_SCHEMAS_NPINTEGER) &&
5449                  (val->type != XML_SCHEMAS_NINTEGER) &&
5450                  (val->type != XML_SCHEMAS_NNINTEGER) &&
5451                  (val->type != XML_SCHEMAS_PINTEGER) &&
5452                  (val->type != XML_SCHEMAS_INT) &&
5453                  (val->type != XML_SCHEMAS_UINT) &&
5454                  (val->type != XML_SCHEMAS_LONG) &&
5455                  (val->type != XML_SCHEMAS_ULONG) &&
5456                  (val->type != XML_SCHEMAS_SHORT) &&
5457                  (val->type != XML_SCHEMAS_USHORT) &&
5458                  (val->type != XML_SCHEMAS_BYTE) &&
5459                  (val->type != XML_SCHEMAS_UBYTE))) {
5460                 return(-1);
5461             }
5462             if (facet->type == XML_SCHEMA_FACET_TOTALDIGITS) {
5463                 if (val->value.decimal.total > facet->val->value.decimal.lo)
5464                     return(XML_SCHEMAV_CVC_TOTALDIGITS_VALID);
5465
5466             } else if (facet->type == XML_SCHEMA_FACET_FRACTIONDIGITS) {
5467                 if (val->value.decimal.frac > facet->val->value.decimal.lo)
5468                     return(XML_SCHEMAV_CVC_FRACTIONDIGITS_VALID);
5469             }
5470             break;
5471         default:
5472             TODO
5473     }
5474     return(0);
5475
5476 }
5477
5478 /**
5479  * xmlSchemaValidateFacet:
5480  * @base:  the base type
5481  * @facet:  the facet to check
5482  * @value:  the lexical repr of the value to validate
5483  * @val:  the precomputed value
5484  *
5485  * Check a value against a facet condition
5486  *
5487  * Returns 0 if the element is schemas valid, a positive error code
5488  *     number otherwise and -1 in case of internal or API error.
5489  */
5490 int
5491 xmlSchemaValidateFacet(xmlSchemaTypePtr base,
5492                        xmlSchemaFacetPtr facet,
5493                        const xmlChar *value,
5494                        xmlSchemaValPtr val)
5495 {
5496     /*
5497     * This tries to ensure API compatibility regarding the old
5498     * xmlSchemaValidateFacet() and the new xmlSchemaValidateFacetInternal() and
5499     * xmlSchemaValidateFacetWhtsp().
5500     */
5501     if (val != NULL)
5502         return(xmlSchemaValidateFacetInternal(facet,
5503             XML_SCHEMA_WHITESPACE_UNKNOWN, val->type, value, val,
5504             XML_SCHEMA_WHITESPACE_UNKNOWN));
5505     else if (base != NULL)
5506         return(xmlSchemaValidateFacetInternal(facet,
5507             XML_SCHEMA_WHITESPACE_UNKNOWN, base->builtInType, value, val,
5508             XML_SCHEMA_WHITESPACE_UNKNOWN));
5509     return(-1);
5510 }
5511
5512 /**
5513  * xmlSchemaValidateFacetWhtsp:
5514  * @facet:  the facet to check
5515  * @fws: the whitespace type of the facet's value
5516  * @valType: the built-in type of the value
5517  * @value:  the lexical (or normalized for pattern) repr of the value to validate
5518  * @val:  the precomputed value
5519  * @ws: the whitespace type of the value
5520  *
5521  * Check a value against a facet condition. This takes value normalization
5522  * according to the specified whitespace types into account.
5523  * Note that @value needs to be the *normalized* value if the facet
5524  * is of type "pattern".
5525  *
5526  * Returns 0 if the element is schemas valid, a positive error code
5527  *     number otherwise and -1 in case of internal or API error.
5528  */
5529 int
5530 xmlSchemaValidateFacetWhtsp(xmlSchemaFacetPtr facet,
5531                             xmlSchemaWhitespaceValueType fws,
5532                             xmlSchemaValType valType,                       
5533                             const xmlChar *value,
5534                             xmlSchemaValPtr val,
5535                             xmlSchemaWhitespaceValueType ws)
5536 {
5537      return(xmlSchemaValidateFacetInternal(facet, fws, valType,
5538          value, val, ws));
5539 }
5540
5541 #if 0
5542 #ifndef DBL_DIG
5543 #define DBL_DIG 16
5544 #endif
5545 #ifndef DBL_EPSILON
5546 #define DBL_EPSILON 1E-9
5547 #endif
5548
5549 #define INTEGER_DIGITS DBL_DIG
5550 #define FRACTION_DIGITS (DBL_DIG + 1)
5551 #define EXPONENT_DIGITS (3 + 2)
5552
5553 /**
5554  * xmlXPathFormatNumber:
5555  * @number:     number to format
5556  * @buffer:     output buffer
5557  * @buffersize: size of output buffer
5558  *
5559  * Convert the number into a string representation.
5560  */
5561 static void
5562 xmlSchemaFormatFloat(double number, char buffer[], int buffersize)
5563 {
5564     switch (xmlXPathIsInf(number)) {
5565     case 1:
5566         if (buffersize > (int)sizeof("INF"))
5567             snprintf(buffer, buffersize, "INF");
5568         break;
5569     case -1:
5570         if (buffersize > (int)sizeof("-INF"))
5571             snprintf(buffer, buffersize, "-INF");
5572         break;
5573     default:
5574         if (xmlXPathIsNaN(number)) {
5575             if (buffersize > (int)sizeof("NaN"))
5576                 snprintf(buffer, buffersize, "NaN");
5577         } else if (number == 0) {
5578             snprintf(buffer, buffersize, "0.0E0");
5579         } else {
5580             /* 3 is sign, decimal point, and terminating zero */
5581             char work[DBL_DIG + EXPONENT_DIGITS + 3];
5582             int integer_place, fraction_place;
5583             char *ptr;
5584             char *after_fraction;
5585             double absolute_value;
5586             int size;
5587
5588             absolute_value = fabs(number);
5589
5590             /*
5591              * Result is in work, and after_fraction points
5592              * just past the fractional part.
5593              * Use scientific notation 
5594             */
5595             integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
5596             fraction_place = DBL_DIG - 1;
5597             snprintf(work, sizeof(work),"%*.*e",
5598                 integer_place, fraction_place, number);
5599             after_fraction = strchr(work + DBL_DIG, 'e');           
5600             /* Remove fractional trailing zeroes */
5601             ptr = after_fraction;
5602             while (*(--ptr) == '0')
5603                 ;
5604             if (*ptr != '.')
5605                 ptr++;
5606             while ((*ptr++ = *after_fraction++) != 0);
5607
5608             /* Finally copy result back to caller */
5609             size = strlen(work) + 1;
5610             if (size > buffersize) {
5611                 work[buffersize - 1] = 0;
5612                 size = buffersize;
5613             }
5614             memmove(buffer, work, size);
5615         }
5616         break;
5617     }
5618 }
5619 #endif
5620
5621 /**
5622  * xmlSchemaGetCanonValue:
5623  * @val: the precomputed value
5624  * @retValue: the returned value
5625  *
5626  * Get a the cononical lexical representation of the value.
5627  * The caller has to FREE the returned retValue.
5628  *
5629  * WARNING: Some value types are not supported yet, resulting
5630  * in a @retValue of "???".
5631  * 
5632  * TODO: XML Schema 1.0 does not define canonical representations
5633  * for: duration, gYearMonth, gYear, gMonthDay, gMonth, gDay,
5634  * anyURI, QName, NOTATION. This will be fixed in XML Schema 1.1.
5635  *
5636  *
5637  * Returns 0 if the value could be built, 1 if the value type is
5638  * not supported yet and -1 in case of API errors.
5639  */
5640 int
5641 xmlSchemaGetCanonValue(xmlSchemaValPtr val, const xmlChar **retValue)
5642 {
5643     if ((retValue == NULL) || (val == NULL))
5644         return (-1);
5645     *retValue = NULL;
5646     switch (val->type) {
5647         case XML_SCHEMAS_STRING:
5648             if (val->value.str == NULL)
5649                 *retValue = BAD_CAST xmlStrdup(BAD_CAST "");
5650             else
5651                 *retValue = 
5652                     BAD_CAST xmlStrdup((const xmlChar *) val->value.str);
5653             break;
5654         case XML_SCHEMAS_NORMSTRING:
5655             if (val->value.str == NULL)
5656                 *retValue = BAD_CAST xmlStrdup(BAD_CAST "");
5657             else {
5658                 *retValue = xmlSchemaWhiteSpaceReplace(
5659                     (const xmlChar *) val->value.str);
5660                 if ((*retValue) == NULL)
5661                     *retValue = BAD_CAST xmlStrdup(
5662                         (const xmlChar *) val->value.str);
5663             }
5664             break;
5665         case XML_SCHEMAS_TOKEN:
5666         case XML_SCHEMAS_LANGUAGE:
5667         case XML_SCHEMAS_NMTOKEN:
5668         case XML_SCHEMAS_NAME:  
5669         case XML_SCHEMAS_NCNAME:
5670         case XML_SCHEMAS_ID:
5671         case XML_SCHEMAS_IDREF:
5672         case XML_SCHEMAS_ENTITY:
5673         case XML_SCHEMAS_NOTATION: /* Unclear */
5674         case XML_SCHEMAS_ANYURI:   /* Unclear */
5675             if (val->value.str == NULL)
5676                 return (-1);
5677             *retValue = 
5678                 BAD_CAST xmlSchemaCollapseString(BAD_CAST val->value.str);
5679             if (*retValue == NULL)
5680                 *retValue = 
5681                     BAD_CAST xmlStrdup((const xmlChar *) val->value.str);
5682             break;
5683         case XML_SCHEMAS_QNAME:
5684             /* TODO: Unclear in XML Schema 1.0. */
5685             if (val->value.qname.uri == NULL) {
5686                 *retValue = BAD_CAST xmlStrdup(BAD_CAST val->value.qname.name);
5687                 return (0);
5688             } else {
5689                 *retValue = BAD_CAST xmlStrdup(BAD_CAST "{");
5690                 *retValue = BAD_CAST xmlStrcat((xmlChar *) (*retValue),
5691                     BAD_CAST val->value.qname.uri);
5692                 *retValue = BAD_CAST xmlStrcat((xmlChar *) (*retValue),
5693                     BAD_CAST "}");
5694                 *retValue = BAD_CAST xmlStrcat((xmlChar *) (*retValue),
5695                     BAD_CAST val->value.qname.uri);
5696             }
5697             break;
5698         case XML_SCHEMAS_DECIMAL:
5699             /*
5700             * TODO: Lookout for a more simple implementation.
5701             */
5702             if ((val->value.decimal.total == 1) && 
5703                 (val->value.decimal.lo == 0)) {
5704                 *retValue = xmlStrdup(BAD_CAST "0.0");
5705             } else {
5706                 xmlSchemaValDecimal dec = val->value.decimal;
5707                 int bufsize;
5708                 char *buf = NULL, *offs;
5709
5710                 /* Add room for the decimal point as well. */
5711                 bufsize = dec.total + 2;
5712                 if (dec.sign)
5713                     bufsize++;
5714                 /* Add room for leading/trailing zero. */
5715                 if ((dec.frac == 0) || (dec.frac == dec.total))
5716                     bufsize++;
5717                 buf = xmlMalloc(bufsize);
5718                 if (buf == NULL)
5719                     return(-1);
5720                 offs = buf;
5721                 if (dec.sign)
5722                     *offs++ = '-';
5723                 if (dec.frac == dec.total) {
5724                     *offs++ = '0';
5725                     *offs++ = '.';
5726                 }
5727                 if (dec.hi != 0)
5728                     snprintf(offs, bufsize - (offs - buf),
5729                         "%lu%lu%lu", dec.hi, dec.mi, dec.lo);
5730                 else if (dec.mi != 0)
5731                     snprintf(offs, bufsize - (offs - buf),
5732                         "%lu%lu", dec.mi, dec.lo);
5733                 else
5734                     snprintf(offs, bufsize - (offs - buf),
5735                         "%lu", dec.lo);
5736                         
5737                 if (dec.frac != 0) {
5738                     if (dec.frac != dec.total) {
5739                         int diff = dec.total - dec.frac;
5740                         /*
5741                         * Insert the decimal point.
5742                         */
5743                         memmove(offs + diff + 1, offs + diff, dec.frac +1);
5744                         offs[diff] = '.';
5745                     } else {
5746                         unsigned int i = 0;
5747                         /*
5748                         * Insert missing zeroes behind the decimal point.
5749                         */                      
5750                         while (*(offs + i) != 0)
5751                             i++;
5752                         if (i < dec.total) {
5753                             memmove(offs + (dec.total - i), offs, i +1);
5754                             memset(offs, '0', dec.total - i);
5755                         }
5756                     }
5757                 } else {
5758                     /*
5759                     * Append decimal point and zero.
5760                     */
5761                     offs = buf + bufsize - 1;
5762                     *offs-- = 0;
5763                     *offs-- = '0';
5764                     *offs-- = '.';
5765                 }
5766                 *retValue = BAD_CAST buf;
5767             }
5768             break;
5769         case XML_SCHEMAS_INTEGER:
5770         case XML_SCHEMAS_PINTEGER:
5771         case XML_SCHEMAS_NPINTEGER:
5772         case XML_SCHEMAS_NINTEGER:
5773         case XML_SCHEMAS_NNINTEGER:
5774         case XML_SCHEMAS_LONG:
5775         case XML_SCHEMAS_BYTE:
5776         case XML_SCHEMAS_SHORT:
5777         case XML_SCHEMAS_INT:
5778         case XML_SCHEMAS_UINT:
5779         case XML_SCHEMAS_ULONG:
5780         case XML_SCHEMAS_USHORT:
5781         case XML_SCHEMAS_UBYTE:
5782             if ((val->value.decimal.total == 1) &&
5783                 (val->value.decimal.lo == 0))
5784                 *retValue = xmlStrdup(BAD_CAST "0");
5785             else {
5786                 xmlSchemaValDecimal dec = val->value.decimal;
5787                 int bufsize = dec.total + 1;
5788
5789                 /* Add room for the decimal point as well. */
5790                 if (dec.sign)
5791                     bufsize++;
5792                 *retValue = xmlMalloc(bufsize);
5793                 if (*retValue == NULL)
5794                     return(-1);
5795                 if (dec.hi != 0) {
5796                     if (dec.sign)
5797                         snprintf((char *) *retValue, bufsize,
5798                             "-%lu%lu%lu", dec.hi, dec.mi, dec.lo);
5799                     else
5800                         snprintf((char *) *retValue, bufsize,
5801                             "%lu%lu%lu", dec.hi, dec.mi, dec.lo);
5802                 } else if (dec.mi != 0) {
5803                     if (dec.sign)
5804                         snprintf((char *) *retValue, bufsize,
5805                             "-%lu%lu", dec.mi, dec.lo);
5806                     else
5807                         snprintf((char *) *retValue, bufsize,
5808                             "%lu%lu", dec.mi, dec.lo);
5809                 } else {
5810                     if (dec.sign)
5811                         snprintf((char *) *retValue, bufsize, "-%lu", dec.lo);
5812                     else
5813                         snprintf((char *) *retValue, bufsize, "%lu", dec.lo);
5814                 }
5815             }
5816             break;
5817         case XML_SCHEMAS_BOOLEAN:
5818             if (val->value.b)
5819                 *retValue = BAD_CAST xmlStrdup(BAD_CAST "true");
5820             else
5821                 *retValue = BAD_CAST xmlStrdup(BAD_CAST "false");
5822             break;
5823         case XML_SCHEMAS_DURATION: {
5824                 char buf[100];
5825                 unsigned long year;
5826                 unsigned long mon, day, hour = 0, min = 0;
5827                 double sec = 0, left;
5828
5829                 /* TODO: Unclear in XML Schema 1.0 */
5830                 /*
5831                 * TODO: This results in a normalized output of the value
5832                 * - which is NOT conformant to the spec -
5833                 * since the exact values of each property are not
5834                 * recoverable. Think about extending the structure to
5835                 * provide a field for every property.
5836                 */
5837                 year = (unsigned long) FQUOTIENT(labs(val->value.dur.mon), 12);
5838                 mon = labs(val->value.dur.mon) - 12 * year;
5839
5840                 day = (unsigned long) FQUOTIENT(fabs(val->value.dur.sec), 86400);
5841                 left = fabs(val->value.dur.sec) - day * 86400;
5842                 if (left > 0) {
5843                     hour = (unsigned long) FQUOTIENT(left, 3600);
5844                     left = left - (hour * 3600);
5845                     if (left > 0) {
5846                         min = (unsigned long) FQUOTIENT(left, 60);
5847                         sec = left - (min * 60);
5848                     }
5849                 }
5850                 if ((val->value.dur.mon < 0) || (val->value.dur.sec < 0))
5851                     snprintf(buf, 100, "P%luY%luM%luDT%luH%luM%.14gS",
5852                         year, mon, day, hour, min, sec);
5853                 else
5854                     snprintf(buf, 100, "-P%luY%luM%luDT%luH%luM%.14gS",
5855                         year, mon, day, hour, min, sec);
5856                 *retValue = BAD_CAST xmlStrdup(BAD_CAST buf);
5857             }
5858             break;
5859         case XML_SCHEMAS_GYEAR: {
5860                 char buf[30];
5861                 /* TODO: Unclear in XML Schema 1.0 */
5862                 /* TODO: What to do with the timezone? */
5863                 snprintf(buf, 30, "%04ld", val->value.date.year);
5864                 *retValue = BAD_CAST xmlStrdup(BAD_CAST buf);
5865             }
5866             break;
5867         case XML_SCHEMAS_GMONTH: {
5868                 /* TODO: Unclear in XML Schema 1.0 */
5869                 /* TODO: What to do with the timezone? */
5870                 *retValue = xmlMalloc(6);
5871                 if (*retValue == NULL)
5872                     return(-1);
5873                 snprintf((char *) *retValue, 6, "--%02u",
5874                     val->value.date.mon);
5875             }
5876             break;
5877         case XML_SCHEMAS_GDAY: {
5878                 /* TODO: Unclear in XML Schema 1.0 */
5879                 /* TODO: What to do with the timezone? */
5880                 *retValue = xmlMalloc(6);
5881                 if (*retValue == NULL)
5882                     return(-1);
5883                 snprintf((char *) *retValue, 6, "---%02u",
5884                     val->value.date.day);
5885             }
5886             break;        
5887         case XML_SCHEMAS_GMONTHDAY: {
5888                 /* TODO: Unclear in XML Schema 1.0 */
5889                 /* TODO: What to do with the timezone? */
5890                 *retValue = xmlMalloc(8);
5891                 if (*retValue == NULL)
5892                     return(-1);
5893                 snprintf((char *) *retValue, 8, "--%02u-%02u",
5894                     val->value.date.mon, val->value.date.day);
5895             }
5896             break;
5897         case XML_SCHEMAS_GYEARMONTH: {
5898                 char buf[35];
5899                 /* TODO: Unclear in XML Schema 1.0 */
5900                 /* TODO: What to do with the timezone? */
5901                 if (val->value.date.year < 0)
5902                     snprintf(buf, 35, "-%04ld-%02u",
5903                         labs(val->value.date.year), 
5904                         val->value.date.mon);
5905                 else
5906                     snprintf(buf, 35, "%04ld-%02u",
5907                         val->value.date.year, val->value.date.mon);
5908                 *retValue = BAD_CAST xmlStrdup(BAD_CAST buf);
5909             }
5910             break;              
5911         case XML_SCHEMAS_TIME:
5912             {
5913                 char buf[30];
5914
5915                 if (val->value.date.tz_flag) {
5916                     xmlSchemaValPtr norm;
5917
5918                     norm = xmlSchemaDateNormalize(val, 0);
5919                     if (norm == NULL)
5920                         return (-1);
5921                     /* 
5922                     * TODO: Check if "%.14g" is portable.                   
5923                     */
5924                     snprintf(buf, 30,
5925                         "%02u:%02u:%02.14gZ",
5926                         norm->value.date.hour,
5927                         norm->value.date.min,
5928                         norm->value.date.sec);
5929                     xmlSchemaFreeValue(norm);
5930                 } else {
5931                     snprintf(buf, 30,
5932                         "%02u:%02u:%02.14g",
5933                         val->value.date.hour,
5934                         val->value.date.min,
5935                         val->value.date.sec);
5936                 }
5937                 *retValue = BAD_CAST xmlStrdup(BAD_CAST buf);
5938             }       
5939             break;
5940         case XML_SCHEMAS_DATE:
5941             {
5942                 char buf[30];
5943
5944                 if (val->value.date.tz_flag) {
5945                     xmlSchemaValPtr norm;
5946
5947                     norm = xmlSchemaDateNormalize(val, 0);
5948                     if (norm == NULL)
5949                         return (-1);
5950                     /*
5951                     * TODO: Append the canonical value of the
5952                     * recoverable timezone and not "Z".
5953                     */
5954                     snprintf(buf, 30,
5955                         "%04ld:%02u:%02uZ",
5956                         norm->value.date.year, norm->value.date.mon,
5957                         norm->value.date.day);
5958                     xmlSchemaFreeValue(norm);
5959                 } else {
5960                     snprintf(buf, 30,
5961                         "%04ld:%02u:%02u",
5962                         val->value.date.year, val->value.date.mon,
5963                         val->value.date.day);
5964                 }
5965                 *retValue = BAD_CAST xmlStrdup(BAD_CAST buf);
5966             }       
5967             break;
5968         case XML_SCHEMAS_DATETIME:
5969             {
5970                 char buf[50];
5971
5972                 if (val->value.date.tz_flag) {
5973                     xmlSchemaValPtr norm;
5974
5975                     norm = xmlSchemaDateNormalize(val, 0);
5976                     if (norm == NULL)
5977                         return (-1);
5978                     /*
5979                     * TODO: Check if "%.14g" is portable.
5980                     */
5981                     snprintf(buf, 50,
5982                         "%04ld:%02u:%02uT%02u:%02u:%02.14gZ",
5983                         norm->value.date.year, norm->value.date.mon,
5984                         norm->value.date.day, norm->value.date.hour,
5985                         norm->value.date.min, norm->value.date.sec);
5986                     xmlSchemaFreeValue(norm);
5987                 } else {
5988                     snprintf(buf, 50,
5989                         "%04ld:%02u:%02uT%02u:%02u:%02.14g",
5990                         val->value.date.year, val->value.date.mon,
5991                         val->value.date.day, val->value.date.hour,
5992                         val->value.date.min, val->value.date.sec);
5993                 }
5994                 *retValue = BAD_CAST xmlStrdup(BAD_CAST buf);
5995             }
5996             break;
5997         case XML_SCHEMAS_HEXBINARY:
5998             *retValue = BAD_CAST xmlStrdup(BAD_CAST val->value.hex.str);
5999             break;
6000         case XML_SCHEMAS_BASE64BINARY:
6001             /*
6002             * TODO: Is the following spec piece implemented?:
6003             * SPEC: "Note: For some values the canonical form defined
6004             * above does not conform to [RFC 2045], which requires breaking
6005             * with linefeeds at appropriate intervals."
6006             */
6007             *retValue = BAD_CAST xmlStrdup(BAD_CAST val->value.base64.str);
6008             break;
6009         case XML_SCHEMAS_FLOAT: {
6010                 char buf[30];           
6011                 /* 
6012                 * |m| < 16777216, -149 <= e <= 104.
6013                 * TODO: Handle, NaN, INF, -INF. The format is not
6014                 * yet conformant. The c type float does not cover
6015                 * the whole range.
6016                 */
6017                 snprintf(buf, 30, "%01.14e", val->value.f);
6018                 *retValue = BAD_CAST xmlStrdup(BAD_CAST buf);
6019             }
6020             break;
6021         case XML_SCHEMAS_DOUBLE: {
6022                 char buf[40];
6023                 /* |m| < 9007199254740992, -1075 <= e <= 970 */
6024                 /*
6025                 * TODO: Handle, NaN, INF, -INF. The format is not
6026                 * yet conformant. The c type float does not cover
6027                 * the whole range.
6028                 */
6029                 snprintf(buf, 40, "%01.14e", val->value.d);
6030                 *retValue = BAD_CAST xmlStrdup(BAD_CAST buf);
6031             }
6032             break;      
6033         default:
6034             *retValue = BAD_CAST xmlStrdup(BAD_CAST "???");
6035             return (1);
6036     }
6037     if (*retValue == NULL)
6038         return(-1);
6039     return (0);
6040 }
6041
6042 /**
6043  * xmlSchemaGetCanonValueWhtsp:
6044  * @val: the precomputed value
6045  * @retValue: the returned value
6046  * @ws: the whitespace type of the value
6047  *
6048  * Get a the cononical representation of the value.
6049  * The caller has to free the returned @retValue.
6050  *
6051  * Returns 0 if the value could be built, 1 if the value type is
6052  * not supported yet and -1 in case of API errors.
6053  */
6054 int
6055 xmlSchemaGetCanonValueWhtsp(xmlSchemaValPtr val,
6056                             const xmlChar **retValue,
6057                             xmlSchemaWhitespaceValueType ws)
6058 {
6059     if ((retValue == NULL) || (val == NULL))
6060         return (-1);
6061     if ((ws == XML_SCHEMA_WHITESPACE_UNKNOWN) ||
6062         (ws > XML_SCHEMA_WHITESPACE_COLLAPSE))
6063         return (-1);
6064
6065     *retValue = NULL;
6066     switch (val->type) {
6067         case XML_SCHEMAS_STRING:
6068             if (val->value.str == NULL)
6069                 *retValue = BAD_CAST xmlStrdup(BAD_CAST "");
6070             else if (ws == XML_SCHEMA_WHITESPACE_COLLAPSE)
6071                 *retValue = xmlSchemaCollapseString(val->value.str);
6072             else if (ws == XML_SCHEMA_WHITESPACE_REPLACE)
6073                 *retValue = xmlSchemaWhiteSpaceReplace(val->value.str);
6074             if ((*retValue) == NULL)
6075                 *retValue = BAD_CAST xmlStrdup(val->value.str);
6076             break;
6077         case XML_SCHEMAS_NORMSTRING:
6078             if (val->value.str == NULL)
6079                 *retValue = BAD_CAST xmlStrdup(BAD_CAST "");
6080             else {
6081                 if (ws == XML_SCHEMA_WHITESPACE_COLLAPSE)
6082                     *retValue = xmlSchemaCollapseString(val->value.str);
6083                 else
6084                     *retValue = xmlSchemaWhiteSpaceReplace(val->value.str);
6085                 if ((*retValue) == NULL)
6086                     *retValue = BAD_CAST xmlStrdup(val->value.str);
6087             }
6088             break;
6089         default:
6090             return (xmlSchemaGetCanonValue(val, retValue));
6091     }    
6092     return (0);
6093 }
6094
6095 /**
6096  * xmlSchemaGetValType:
6097  * @val: a schemas value
6098  *
6099  * Accessor for the type of a value
6100  *
6101  * Returns the xmlSchemaValType of the value
6102  */
6103 xmlSchemaValType
6104 xmlSchemaGetValType(xmlSchemaValPtr val)
6105 {
6106     if (val == NULL)
6107         return(XML_SCHEMAS_UNKNOWN);
6108     return (val->type);
6109 }
6110
6111 #define bottom_xmlschemastypes
6112 #include "elfgcchack.h"
6113 #endif /* LIBXML_SCHEMAS_ENABLED */