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