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