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