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