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