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