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