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