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