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