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