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