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