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 if (normOnTheFly) { 2903 norm = xmlSchemaCollapseString(value); 2904 if (norm != NULL) 2905 value = norm; 2906 } 2907 uri = xmlParseURI((const char *) value); 2908 if (uri == NULL) 2909 goto return1; 2910 xmlFreeURI(uri); 2911 } 2912 2913 if (val != NULL) { 2914 v = xmlSchemaNewValue(XML_SCHEMAS_ANYURI); 2915 if (v == NULL) 2916 goto error; 2917 v->value.str = xmlStrdup(value); 2918 *val = v; 2919 } 2920 goto return0; 2921 } 2922 case XML_SCHEMAS_HEXBINARY:{ 2923 const xmlChar *cur = value, *start; 2924 xmlChar *base; 2925 int total, i = 0; 2926 2927 if (cur == NULL) 2928 goto return1; 2929 2930 if (normOnTheFly) 2931 while IS_WSP_BLANK_CH(*cur) cur++; 2932 2933 start = cur; 2934 while (((*cur >= '0') && (*cur <= '9')) || 2935 ((*cur >= 'A') && (*cur <= 'F')) || 2936 ((*cur >= 'a') && (*cur <= 'f'))) { 2937 i++; 2938 cur++; 2939 } 2940 if (normOnTheFly) 2941 while IS_WSP_BLANK_CH(*cur) cur++; 2942 2943 if (*cur != 0) 2944 goto return1; 2945 if ((i % 2) != 0) 2946 goto return1; 2947 2948 if (val != NULL) { 2949 2950 v = xmlSchemaNewValue(XML_SCHEMAS_HEXBINARY); 2951 if (v == NULL) 2952 goto error; 2953 /* 2954 * Copy only the normalized piece. 2955 * CRITICAL TODO: Check this. 2956 */ 2957 cur = xmlStrndup(start, i); 2958 if (cur == NULL) { 2959 xmlSchemaTypeErrMemory(node, "allocating hexbin data"); 2960 xmlFree(v); 2961 goto return1; 2962 } 2963 2964 total = i / 2; /* number of octets */ 2965 2966 base = (xmlChar *) cur; 2967 while (i-- > 0) { 2968 if (*base >= 'a') 2969 *base = *base - ('a' - 'A'); 2970 base++; 2971 } 2972 2973 v->value.hex.str = (xmlChar *) cur; 2974 v->value.hex.total = total; 2975 *val = v; 2976 } 2977 goto return0; 2978 } 2979 case XML_SCHEMAS_BASE64BINARY:{ 2980 /* ISSUE: 2981 * 2982 * Ignore all stray characters? (yes, currently) 2983 * Worry about long lines? (no, currently) 2984 * 2985 * rfc2045.txt: 2986 * 2987 * "The encoded output stream must be represented in lines of 2988 * no more than 76 characters each. All line breaks or other 2989 * characters not found in Table 1 must be ignored by decoding 2990 * software. In base64 data, characters other than those in 2991 * Table 1, line breaks, and other white space probably 2992 * indicate a transmission error, about which a warning 2993 * message or even a message rejection might be appropriate 2994 * under some circumstances." */ 2995 const xmlChar *cur = value; 2996 xmlChar *base; 2997 int total, i = 0, pad = 0; 2998 2999 if (cur == NULL) 3000 goto return1; 3001 3002 for (; *cur; ++cur) { 3003 int decc; 3004 3005 decc = _xmlSchemaBase64Decode(*cur); 3006 if (decc < 0) ; 3007 else if (decc < 64) 3008 i++; 3009 else 3010 break; 3011 } 3012 for (; *cur; ++cur) { 3013 int decc; 3014 3015 decc = _xmlSchemaBase64Decode(*cur); 3016 if (decc < 0) ; 3017 else if (decc < 64) 3018 goto return1; 3019 if (decc == 64) 3020 pad++; 3021 } 3022 3023 /* rfc2045.txt: "Special processing is performed if fewer than 3024 * 24 bits are available at the end of the data being encoded. 3025 * A full encoding quantum is always completed at the end of a 3026 * body. When fewer than 24 input bits are available in an 3027 * input group, zero bits are added (on the right) to form an 3028 * integral number of 6-bit groups. Padding at the end of the 3029 * data is performed using the "=" character. Since all 3030 * base64 input is an integral number of octets, only the 3031 * following cases can arise: (1) the final quantum of 3032 * encoding input is an integral multiple of 24 bits; here, 3033 * the final unit of encoded output will be an integral 3034 * multiple ofindent: Standard input:701: Warning:old style 3035 * assignment ambiguity in "=*". Assuming "= *" 4 characters 3036 * with no "=" padding, (2) the final 3037 * quantum of encoding input is exactly 8 bits; here, the 3038 * final unit of encoded output will be two characters 3039 * followed by two "=" padding characters, or (3) the final 3040 * quantum of encoding input is exactly 16 bits; here, the 3041 * final unit of encoded output will be three characters 3042 * followed by one "=" padding character." */ 3043 3044 total = 3 * (i / 4); 3045 if (pad == 0) { 3046 if (i % 4 != 0) 3047 goto return1; 3048 } else if (pad == 1) { 3049 int decc; 3050 3051 if (i % 4 != 3) 3052 goto return1; 3053 for (decc = _xmlSchemaBase64Decode(*cur); 3054 (decc < 0) || (decc > 63); 3055 decc = _xmlSchemaBase64Decode(*cur)) 3056 --cur; 3057 /* 16bits in 24bits means 2 pad bits: nnnnnn nnmmmm mmmm00*/ 3058 /* 00111100 -> 0x3c */ 3059 if (decc & ~0x3c) 3060 goto return1; 3061 total += 2; 3062 } else if (pad == 2) { 3063 int decc; 3064 3065 if (i % 4 != 2) 3066 goto return1; 3067 for (decc = _xmlSchemaBase64Decode(*cur); 3068 (decc < 0) || (decc > 63); 3069 decc = _xmlSchemaBase64Decode(*cur)) 3070 --cur; 3071 /* 8bits in 12bits means 4 pad bits: nnnnnn nn0000 */ 3072 /* 00110000 -> 0x30 */ 3073 if (decc & ~0x30) 3074 goto return1; 3075 total += 1; 3076 } else 3077 goto return1; 3078 3079 if (val != NULL) { 3080 v = xmlSchemaNewValue(XML_SCHEMAS_BASE64BINARY); 3081 if (v == NULL) 3082 goto error; 3083 base = 3084 (xmlChar *) xmlMallocAtomic((i + pad + 1) * 3085 sizeof(xmlChar)); 3086 if (base == NULL) { 3087 xmlSchemaTypeErrMemory(node, "allocating base64 data"); 3088 xmlFree(v); 3089 goto return1; 3090 } 3091 v->value.base64.str = base; 3092 for (cur = value; *cur; ++cur) 3093 if (_xmlSchemaBase64Decode(*cur) >= 0) { 3094 *base = *cur; 3095 ++base; 3096 } 3097 *base = 0; 3098 v->value.base64.total = total; 3099 *val = v; 3100 } 3101 goto return0; 3102 } 3103 case XML_SCHEMAS_INTEGER: 3104 case XML_SCHEMAS_PINTEGER: 3105 case XML_SCHEMAS_NPINTEGER: 3106 case XML_SCHEMAS_NINTEGER: 3107 case XML_SCHEMAS_NNINTEGER:{ 3108 const xmlChar *cur = value; 3109 unsigned long lo, mi, hi; 3110 int sign = 0; 3111 3112 if (cur == NULL) 3113 goto return1; 3114 if (normOnTheFly) 3115 while IS_WSP_BLANK_CH(*cur) cur++; 3116 if (*cur == '-') { 3117 sign = 1; 3118 cur++; 3119 } else if (*cur == '+') 3120 cur++; 3121 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi); 3122 if (ret < 0) 3123 goto return1; 3124 if (normOnTheFly) 3125 while IS_WSP_BLANK_CH(*cur) cur++; 3126 if (*cur != 0) 3127 goto return1; 3128 if (type->builtInType == XML_SCHEMAS_NPINTEGER) { 3129 if ((sign == 0) && 3130 ((hi != 0) || (mi != 0) || (lo != 0))) 3131 goto return1; 3132 } else if (type->builtInType == XML_SCHEMAS_PINTEGER) { 3133 if (sign == 1) 3134 goto return1; 3135 if ((hi == 0) && (mi == 0) && (lo == 0)) 3136 goto return1; 3137 } else if (type->builtInType == XML_SCHEMAS_NINTEGER) { 3138 if (sign == 0) 3139 goto return1; 3140 if ((hi == 0) && (mi == 0) && (lo == 0)) 3141 goto return1; 3142 } else if (type->builtInType == XML_SCHEMAS_NNINTEGER) { 3143 if ((sign == 1) && 3144 ((hi != 0) || (mi != 0) || (lo != 0))) 3145 goto return1; 3146 } 3147 if (val != NULL) { 3148 v = xmlSchemaNewValue(type->builtInType); 3149 if (v != NULL) { 3150 if (ret == 0) 3151 ret++; 3152 v->value.decimal.lo = lo; 3153 v->value.decimal.mi = mi; 3154 v->value.decimal.hi = hi; 3155 v->value.decimal.sign = sign; 3156 v->value.decimal.frac = 0; 3157 v->value.decimal.total = ret; 3158 *val = v; 3159 } 3160 } 3161 goto return0; 3162 } 3163 case XML_SCHEMAS_LONG: 3164 case XML_SCHEMAS_BYTE: 3165 case XML_SCHEMAS_SHORT: 3166 case XML_SCHEMAS_INT:{ 3167 const xmlChar *cur = value; 3168 unsigned long lo, mi, hi; 3169 int sign = 0; 3170 3171 if (cur == NULL) 3172 goto return1; 3173 if (*cur == '-') { 3174 sign = 1; 3175 cur++; 3176 } else if (*cur == '+') 3177 cur++; 3178 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi); 3179 if (ret < 0) 3180 goto return1; 3181 if (*cur != 0) 3182 goto return1; 3183 if (type->builtInType == XML_SCHEMAS_LONG) { 3184 if (hi >= 922) { 3185 if (hi > 922) 3186 goto return1; 3187 if (mi >= 33720368) { 3188 if (mi > 33720368) 3189 goto return1; 3190 if ((sign == 0) && (lo > 54775807)) 3191 goto return1; 3192 if ((sign == 1) && (lo > 54775808)) 3193 goto return1; 3194 } 3195 } 3196 } else if (type->builtInType == XML_SCHEMAS_INT) { 3197 if (hi != 0) 3198 goto return1; 3199 if (mi >= 21) { 3200 if (mi > 21) 3201 goto return1; 3202 if ((sign == 0) && (lo > 47483647)) 3203 goto return1; 3204 if ((sign == 1) && (lo > 47483648)) 3205 goto return1; 3206 } 3207 } else if (type->builtInType == XML_SCHEMAS_SHORT) { 3208 if ((mi != 0) || (hi != 0)) 3209 goto return1; 3210 if ((sign == 1) && (lo > 32768)) 3211 goto return1; 3212 if ((sign == 0) && (lo > 32767)) 3213 goto return1; 3214 } else if (type->builtInType == XML_SCHEMAS_BYTE) { 3215 if ((mi != 0) || (hi != 0)) 3216 goto return1; 3217 if ((sign == 1) && (lo > 128)) 3218 goto return1; 3219 if ((sign == 0) && (lo > 127)) 3220 goto return1; 3221 } 3222 if (val != NULL) { 3223 v = xmlSchemaNewValue(type->builtInType); 3224 if (v != NULL) { 3225 v->value.decimal.lo = lo; 3226 v->value.decimal.mi = mi; 3227 v->value.decimal.hi = hi; 3228 v->value.decimal.sign = sign; 3229 v->value.decimal.frac = 0; 3230 v->value.decimal.total = ret; 3231 *val = v; 3232 } 3233 } 3234 goto return0; 3235 } 3236 case XML_SCHEMAS_UINT: 3237 case XML_SCHEMAS_ULONG: 3238 case XML_SCHEMAS_USHORT: 3239 case XML_SCHEMAS_UBYTE:{ 3240 const xmlChar *cur = value; 3241 unsigned long lo, mi, hi; 3242 3243 if (cur == NULL) 3244 goto return1; 3245 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi); 3246 if (ret < 0) 3247 goto return1; 3248 if (*cur != 0) 3249 goto return1; 3250 if (type->builtInType == XML_SCHEMAS_ULONG) { 3251 if (hi >= 1844) { 3252 if (hi > 1844) 3253 goto return1; 3254 if (mi >= 67440737) { 3255 if (mi > 67440737) 3256 goto return1; 3257 if (lo > 9551615) 3258 goto return1; 3259 } 3260 } 3261 } else if (type->builtInType == XML_SCHEMAS_UINT) { 3262 if (hi != 0) 3263 goto return1; 3264 if (mi >= 42) { 3265 if (mi > 42) 3266 goto return1; 3267 if (lo > 94967295) 3268 goto return1; 3269 } 3270 } else if (type->builtInType == XML_SCHEMAS_USHORT) { 3271 if ((mi != 0) || (hi != 0)) 3272 goto return1; 3273 if (lo > 65535) 3274 goto return1; 3275 } else if (type->builtInType == XML_SCHEMAS_UBYTE) { 3276 if ((mi != 0) || (hi != 0)) 3277 goto return1; 3278 if (lo > 255) 3279 goto return1; 3280 } 3281 if (val != NULL) { 3282 v = xmlSchemaNewValue(type->builtInType); 3283 if (v != NULL) { 3284 v->value.decimal.lo = lo; 3285 v->value.decimal.mi = mi; 3286 v->value.decimal.hi = hi; 3287 v->value.decimal.sign = 0; 3288 v->value.decimal.frac = 0; 3289 v->value.decimal.total = ret; 3290 *val = v; 3291 } 3292 } 3293 goto return0; 3294 } 3295 } 3296 3297 done: 3298 if (norm != NULL) 3299 xmlFree(norm); 3300 return (ret); 3301 return3: 3302 if (norm != NULL) 3303 xmlFree(norm); 3304 return (3); 3305 return1: 3306 if (norm != NULL) 3307 xmlFree(norm); 3308 return (1); 3309 return0: 3310 if (norm != NULL) 3311 xmlFree(norm); 3312 return (0); 3313 error: 3314 if (norm != NULL) 3315 xmlFree(norm); 3316 return (-1); 3317} 3318 3319/** 3320 * xmlSchemaValPredefTypeNode: 3321 * @type: the predefined type 3322 * @value: the value to check 3323 * @val: the return computed value 3324 * @node: the node containing the value 3325 * 3326 * Check that a value conforms to the lexical space of the predefined type. 3327 * if true a value is computed and returned in @val. 3328 * 3329 * Returns 0 if this validates, a positive error code number otherwise 3330 * and -1 in case of internal or API error. 3331 */ 3332int 3333xmlSchemaValPredefTypeNode(xmlSchemaTypePtr type, const xmlChar *value, 3334 xmlSchemaValPtr *val, xmlNodePtr node) { 3335 return(xmlSchemaValAtomicType(type, value, val, node, 0, 3336 XML_SCHEMA_WHITESPACE_UNKNOWN, 1, 1, 0)); 3337} 3338 3339/** 3340 * xmlSchemaValPredefTypeNodeNoNorm: 3341 * @type: the predefined type 3342 * @value: the value to check 3343 * @val: the return computed value 3344 * @node: the node containing the value 3345 * 3346 * Check that a value conforms to the lexical space of the predefined type. 3347 * if true a value is computed and returned in @val. 3348 * This one does apply any normalization to the value. 3349 * 3350 * Returns 0 if this validates, a positive error code number otherwise 3351 * and -1 in case of internal or API error. 3352 */ 3353int 3354xmlSchemaValPredefTypeNodeNoNorm(xmlSchemaTypePtr type, const xmlChar *value, 3355 xmlSchemaValPtr *val, xmlNodePtr node) { 3356 return(xmlSchemaValAtomicType(type, value, val, node, 1, 3357 XML_SCHEMA_WHITESPACE_UNKNOWN, 1, 0, 1)); 3358} 3359 3360/** 3361 * xmlSchemaValidatePredefinedType: 3362 * @type: the predefined type 3363 * @value: the value to check 3364 * @val: the return computed value 3365 * 3366 * Check that a value conforms to the lexical space of the predefined type. 3367 * if true a value is computed and returned in @val. 3368 * 3369 * Returns 0 if this validates, a positive error code number otherwise 3370 * and -1 in case of internal or API error. 3371 */ 3372int 3373xmlSchemaValidatePredefinedType(xmlSchemaTypePtr type, const xmlChar *value, 3374 xmlSchemaValPtr *val) { 3375 return(xmlSchemaValPredefTypeNode(type, value, val, NULL)); 3376} 3377 3378/** 3379 * xmlSchemaCompareDecimals: 3380 * @x: a first decimal value 3381 * @y: a second decimal value 3382 * 3383 * Compare 2 decimals 3384 * 3385 * Returns -1 if x < y, 0 if x == y, 1 if x > y and -2 in case of error 3386 */ 3387static int 3388xmlSchemaCompareDecimals(xmlSchemaValPtr x, xmlSchemaValPtr y) 3389{ 3390 xmlSchemaValPtr swp; 3391 int order = 1, integx, integy, dlen; 3392 unsigned long hi, mi, lo; 3393 3394 /* 3395 * First test: If x is -ve and not zero 3396 */ 3397 if ((x->value.decimal.sign) && 3398 ((x->value.decimal.lo != 0) || 3399 (x->value.decimal.mi != 0) || 3400 (x->value.decimal.hi != 0))) { 3401 /* 3402 * Then if y is -ve and not zero reverse the compare 3403 */ 3404 if ((y->value.decimal.sign) && 3405 ((y->value.decimal.lo != 0) || 3406 (y->value.decimal.mi != 0) || 3407 (y->value.decimal.hi != 0))) 3408 order = -1; 3409 /* 3410 * Otherwise (y >= 0) we have the answer 3411 */ 3412 else 3413 return (-1); 3414 /* 3415 * If x is not -ve and y is -ve we have the answer 3416 */ 3417 } else if ((y->value.decimal.sign) && 3418 ((y->value.decimal.lo != 0) || 3419 (y->value.decimal.mi != 0) || 3420 (y->value.decimal.hi != 0))) { 3421 return (1); 3422 } 3423 /* 3424 * If it's not simply determined by a difference in sign, 3425 * then we need to compare the actual values of the two nums. 3426 * To do this, we start by looking at the integral parts. 3427 * If the number of integral digits differ, then we have our 3428 * answer. 3429 */ 3430 integx = x->value.decimal.total - x->value.decimal.frac; 3431 integy = y->value.decimal.total - y->value.decimal.frac; 3432 /* 3433 * NOTE: We changed the "total" for values like "0.1" 3434 * (or "-0.1" or ".1") to be 1, which was 2 previously. 3435 * Therefore the special case, when such values are 3436 * compared with 0, needs to be handled separately; 3437 * otherwise a zero would be recognized incorrectly as 3438 * greater than those values. This has the nice side effect 3439 * that we gain an overall optimized comparison with zeroes. 3440 * Note that a "0" has a "total" of 1 already. 3441 */ 3442 if (integx == 1) { 3443 if (x->value.decimal.lo == 0) { 3444 if (integy != 1) 3445 return -order; 3446 else if (y->value.decimal.lo != 0) 3447 return -order; 3448 else 3449 return(0); 3450 } 3451 } 3452 if (integy == 1) { 3453 if (y->value.decimal.lo == 0) { 3454 if (integx != 1) 3455 return order; 3456 else if (x->value.decimal.lo != 0) 3457 return order; 3458 else 3459 return(0); 3460 } 3461 } 3462 3463 if (integx > integy) 3464 return order; 3465 else if (integy > integx) 3466 return -order; 3467 3468 /* 3469 * If the number of integral digits is the same for both numbers, 3470 * then things get a little more complicated. We need to "normalize" 3471 * the numbers in order to properly compare them. To do this, we 3472 * look at the total length of each number (length => number of 3473 * significant digits), and divide the "shorter" by 10 (decreasing 3474 * the length) until they are of equal length. 3475 */ 3476 dlen = x->value.decimal.total - y->value.decimal.total; 3477 if (dlen < 0) { /* y has more digits than x */ 3478 swp = x; 3479 hi = y->value.decimal.hi; 3480 mi = y->value.decimal.mi; 3481 lo = y->value.decimal.lo; 3482 dlen = -dlen; 3483 order = -order; 3484 } else { /* x has more digits than y */ 3485 swp = y; 3486 hi = x->value.decimal.hi; 3487 mi = x->value.decimal.mi; 3488 lo = x->value.decimal.lo; 3489 } 3490 while (dlen > 8) { /* in effect, right shift by 10**8 */ 3491 lo = mi; 3492 mi = hi; 3493 hi = 0; 3494 dlen -= 8; 3495 } 3496 while (dlen > 0) { 3497 unsigned long rem1, rem2; 3498 rem1 = (hi % 10) * 100000000L; 3499 hi = hi / 10; 3500 rem2 = (mi % 10) * 100000000L; 3501 mi = (mi + rem1) / 10; 3502 lo = (lo + rem2) / 10; 3503 dlen--; 3504 } 3505 if (hi > swp->value.decimal.hi) { 3506 return order; 3507 } else if (hi == swp->value.decimal.hi) { 3508 if (mi > swp->value.decimal.mi) { 3509 return order; 3510 } else if (mi == swp->value.decimal.mi) { 3511 if (lo > swp->value.decimal.lo) { 3512 return order; 3513 } else if (lo == swp->value.decimal.lo) { 3514 if (x->value.decimal.total == y->value.decimal.total) { 3515 return 0; 3516 } else { 3517 return order; 3518 } 3519 } 3520 } 3521 } 3522 return -order; 3523} 3524 3525/** 3526 * xmlSchemaCompareDurations: 3527 * @x: a first duration value 3528 * @y: a second duration value 3529 * 3530 * Compare 2 durations 3531 * 3532 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in 3533 * case of error 3534 */ 3535static int 3536xmlSchemaCompareDurations(xmlSchemaValPtr x, xmlSchemaValPtr y) 3537{ 3538 long carry, mon, day; 3539 double sec; 3540 int invert = 1; 3541 long xmon, xday, myear, minday, maxday; 3542 static const long dayRange [2][12] = { 3543 { 0, 28, 59, 89, 120, 150, 181, 212, 242, 273, 303, 334, }, 3544 { 0, 31, 62, 92, 123, 153, 184, 215, 245, 276, 306, 337} }; 3545 3546 if ((x == NULL) || (y == NULL)) 3547 return -2; 3548 3549 /* months */ 3550 mon = x->value.dur.mon - y->value.dur.mon; 3551 3552 /* seconds */ 3553 sec = x->value.dur.sec - y->value.dur.sec; 3554 carry = (long)sec / SECS_PER_DAY; 3555 sec -= (double)(carry * SECS_PER_DAY); 3556 3557 /* days */ 3558 day = x->value.dur.day - y->value.dur.day + carry; 3559 3560 /* easy test */ 3561 if (mon == 0) { 3562 if (day == 0) 3563 if (sec == 0.0) 3564 return 0; 3565 else if (sec < 0.0) 3566 return -1; 3567 else 3568 return 1; 3569 else if (day < 0) 3570 return -1; 3571 else 3572 return 1; 3573 } 3574 3575 if (mon > 0) { 3576 if ((day >= 0) && (sec >= 0.0)) 3577 return 1; 3578 else { 3579 xmon = mon; 3580 xday = -day; 3581 } 3582 } else if ((day <= 0) && (sec <= 0.0)) { 3583 return -1; 3584 } else { 3585 invert = -1; 3586 xmon = -mon; 3587 xday = day; 3588 } 3589 3590 myear = xmon / 12; 3591 if (myear == 0) { 3592 minday = 0; 3593 maxday = 0; 3594 } else { 3595 maxday = 366 * ((myear + 3) / 4) + 3596 365 * ((myear - 1) % 4); 3597 minday = maxday - 1; 3598 } 3599 3600 xmon = xmon % 12; 3601 minday += dayRange[0][xmon]; 3602 maxday += dayRange[1][xmon]; 3603 3604 if ((maxday == minday) && (maxday == xday)) 3605 return(0); /* can this really happen ? */ 3606 if (maxday < xday) 3607 return(-invert); 3608 if (minday > xday) 3609 return(invert); 3610 3611 /* indeterminate */ 3612 return 2; 3613} 3614 3615/* 3616 * macros for adding date/times and durations 3617 */ 3618#define FQUOTIENT(a,b) (floor(((double)a/(double)b))) 3619#define MODULO(a,b) (a - FQUOTIENT(a,b) * b) 3620#define FQUOTIENT_RANGE(a,low,high) (FQUOTIENT((a-low),(high-low))) 3621#define MODULO_RANGE(a,low,high) ((MODULO((a-low),(high-low)))+low) 3622 3623/** 3624 * xmlSchemaDupVal: 3625 * @v: the #xmlSchemaValPtr value to duplicate 3626 * 3627 * Makes a copy of @v. The calling program is responsible for freeing 3628 * the returned value. 3629 * 3630 * returns a pointer to a duplicated #xmlSchemaValPtr or NULL if error. 3631 */ 3632static xmlSchemaValPtr 3633xmlSchemaDupVal (xmlSchemaValPtr v) 3634{ 3635 xmlSchemaValPtr ret = xmlSchemaNewValue(v->type); 3636 if (ret == NULL) 3637 return NULL; 3638 3639 memcpy(ret, v, sizeof(xmlSchemaVal)); 3640 ret->next = NULL; 3641 return ret; 3642} 3643 3644/** 3645 * xmlSchemaCopyValue: 3646 * @val: the precomputed value to be copied 3647 * 3648 * Copies the precomputed value. This duplicates any string within. 3649 * 3650 * Returns the copy or NULL if a copy for a data-type is not implemented. 3651 */ 3652xmlSchemaValPtr 3653xmlSchemaCopyValue(xmlSchemaValPtr val) 3654{ 3655 xmlSchemaValPtr ret = NULL, prev = NULL, cur; 3656 3657 /* 3658 * Copy the string values. 3659 */ 3660 while (val != NULL) { 3661 switch (val->type) { 3662 case XML_SCHEMAS_ANYTYPE: 3663 case XML_SCHEMAS_IDREFS: 3664 case XML_SCHEMAS_ENTITIES: 3665 case XML_SCHEMAS_NMTOKENS: 3666 xmlSchemaFreeValue(ret); 3667 return (NULL); 3668 case XML_SCHEMAS_ANYSIMPLETYPE: 3669 case XML_SCHEMAS_STRING: 3670 case XML_SCHEMAS_NORMSTRING: 3671 case XML_SCHEMAS_TOKEN: 3672 case XML_SCHEMAS_LANGUAGE: 3673 case XML_SCHEMAS_NAME: 3674 case XML_SCHEMAS_NCNAME: 3675 case XML_SCHEMAS_ID: 3676 case XML_SCHEMAS_IDREF: 3677 case XML_SCHEMAS_ENTITY: 3678 case XML_SCHEMAS_NMTOKEN: 3679 case XML_SCHEMAS_ANYURI: 3680 cur = xmlSchemaDupVal(val); 3681 if (val->value.str != NULL) 3682 cur->value.str = xmlStrdup(BAD_CAST val->value.str); 3683 break; 3684 case XML_SCHEMAS_QNAME: 3685 case XML_SCHEMAS_NOTATION: 3686 cur = xmlSchemaDupVal(val); 3687 if (val->value.qname.name != NULL) 3688 cur->value.qname.name = 3689 xmlStrdup(BAD_CAST val->value.qname.name); 3690 if (val->value.qname.uri != NULL) 3691 cur->value.qname.uri = 3692 xmlStrdup(BAD_CAST val->value.qname.uri); 3693 break; 3694 case XML_SCHEMAS_HEXBINARY: 3695 cur = xmlSchemaDupVal(val); 3696 if (val->value.hex.str != NULL) 3697 cur->value.hex.str = xmlStrdup(BAD_CAST val->value.hex.str); 3698 break; 3699 case XML_SCHEMAS_BASE64BINARY: 3700 cur = xmlSchemaDupVal(val); 3701 if (val->value.base64.str != NULL) 3702 cur->value.base64.str = 3703 xmlStrdup(BAD_CAST val->value.base64.str); 3704 break; 3705 default: 3706 cur = xmlSchemaDupVal(val); 3707 break; 3708 } 3709 if (ret == NULL) 3710 ret = cur; 3711 else 3712 prev->next = cur; 3713 prev = cur; 3714 val = val->next; 3715 } 3716 return (ret); 3717} 3718 3719/** 3720 * _xmlSchemaDateAdd: 3721 * @dt: an #xmlSchemaValPtr 3722 * @dur: an #xmlSchemaValPtr of type #XS_DURATION 3723 * 3724 * Compute a new date/time from @dt and @dur. This function assumes @dt 3725 * is either #XML_SCHEMAS_DATETIME, #XML_SCHEMAS_DATE, #XML_SCHEMAS_GYEARMONTH, 3726 * or #XML_SCHEMAS_GYEAR. The returned #xmlSchemaVal is the same type as 3727 * @dt. The calling program is responsible for freeing the returned value. 3728 * 3729 * Returns a pointer to a new #xmlSchemaVal or NULL if error. 3730 */ 3731static xmlSchemaValPtr 3732_xmlSchemaDateAdd (xmlSchemaValPtr dt, xmlSchemaValPtr dur) 3733{ 3734 xmlSchemaValPtr ret, tmp; 3735 long carry, tempdays, temp; 3736 xmlSchemaValDatePtr r, d; 3737 xmlSchemaValDurationPtr u; 3738 3739 if ((dt == NULL) || (dur == NULL)) 3740 return NULL; 3741 3742 ret = xmlSchemaNewValue(dt->type); 3743 if (ret == NULL) 3744 return NULL; 3745 3746 /* make a copy so we don't alter the original value */ 3747 tmp = xmlSchemaDupVal(dt); 3748 if (tmp == NULL) { 3749 xmlSchemaFreeValue(ret); 3750 return NULL; 3751 } 3752 3753 r = &(ret->value.date); 3754 d = &(tmp->value.date); 3755 u = &(dur->value.dur); 3756 3757 /* normalization */ 3758 if (d->mon == 0) 3759 d->mon = 1; 3760 3761 /* normalize for time zone offset */ 3762 u->sec -= (d->tzo * 60); 3763 d->tzo = 0; 3764 3765 /* normalization */ 3766 if (d->day == 0) 3767 d->day = 1; 3768 3769 /* month */ 3770 carry = d->mon + u->mon; 3771 r->mon = (unsigned int) MODULO_RANGE(carry, 1, 13); 3772 carry = (long) FQUOTIENT_RANGE(carry, 1, 13); 3773 3774 /* year (may be modified later) */ 3775 r->year = d->year + carry; 3776 if (r->year == 0) { 3777 if (d->year > 0) 3778 r->year--; 3779 else 3780 r->year++; 3781 } 3782 3783 /* time zone */ 3784 r->tzo = d->tzo; 3785 r->tz_flag = d->tz_flag; 3786 3787 /* seconds */ 3788 r->sec = d->sec + u->sec; 3789 carry = (long) FQUOTIENT((long)r->sec, 60); 3790 if (r->sec != 0.0) { 3791 r->sec = MODULO(r->sec, 60.0); 3792 } 3793 3794 /* minute */ 3795 carry += d->min; 3796 r->min = (unsigned int) MODULO(carry, 60); 3797 carry = (long) FQUOTIENT(carry, 60); 3798 3799 /* hours */ 3800 carry += d->hour; 3801 r->hour = (unsigned int) MODULO(carry, 24); 3802 carry = (long)FQUOTIENT(carry, 24); 3803 3804 /* 3805 * days 3806 * Note we use tempdays because the temporary values may need more 3807 * than 5 bits 3808 */ 3809 if ((VALID_YEAR(r->year)) && (VALID_MONTH(r->mon)) && 3810 (d->day > MAX_DAYINMONTH(r->year, r->mon))) 3811 tempdays = MAX_DAYINMONTH(r->year, r->mon); 3812 else if (d->day < 1) 3813 tempdays = 1; 3814 else 3815 tempdays = d->day; 3816 3817 tempdays += u->day + carry; 3818 3819 while (1) { 3820 if (tempdays < 1) { 3821 long tmon = (long) MODULO_RANGE((int)r->mon-1, 1, 13); 3822 long tyr = r->year + (long)FQUOTIENT_RANGE((int)r->mon-1, 1, 13); 3823 if (tyr == 0) 3824 tyr--; 3825 /* 3826 * Coverity detected an overrun in daysInMonth 3827 * of size 12 at position 12 with index variable "((r)->mon - 1)" 3828 */ 3829 if (tmon < 0) 3830 tmon = 0; 3831 if (tmon > 12) 3832 tmon = 12; 3833 tempdays += MAX_DAYINMONTH(tyr, tmon); 3834 carry = -1; 3835 } else if (tempdays > (long) MAX_DAYINMONTH(r->year, r->mon)) { 3836 tempdays = tempdays - MAX_DAYINMONTH(r->year, r->mon); 3837 carry = 1; 3838 } else 3839 break; 3840 3841 temp = r->mon + carry; 3842 r->mon = (unsigned int) MODULO_RANGE(temp, 1, 13); 3843 r->year = r->year + (unsigned int) FQUOTIENT_RANGE(temp, 1, 13); 3844 if (r->year == 0) { 3845 if (temp < 1) 3846 r->year--; 3847 else 3848 r->year++; 3849 } 3850 } 3851 3852 r->day = tempdays; 3853 3854 /* 3855 * adjust the date/time type to the date values 3856 */ 3857 if (ret->type != XML_SCHEMAS_DATETIME) { 3858 if ((r->hour) || (r->min) || (r->sec)) 3859 ret->type = XML_SCHEMAS_DATETIME; 3860 else if (ret->type != XML_SCHEMAS_DATE) { 3861 if ((r->mon != 1) && (r->day != 1)) 3862 ret->type = XML_SCHEMAS_DATE; 3863 else if ((ret->type != XML_SCHEMAS_GYEARMONTH) && (r->mon != 1)) 3864 ret->type = XML_SCHEMAS_GYEARMONTH; 3865 } 3866 } 3867 3868 xmlSchemaFreeValue(tmp); 3869 3870 return ret; 3871} 3872 3873/** 3874 * xmlSchemaDateNormalize: 3875 * @dt: an #xmlSchemaValPtr of a date/time type value. 3876 * @offset: number of seconds to adjust @dt by. 3877 * 3878 * Normalize @dt to GMT time. The @offset parameter is subtracted from 3879 * the return value is a time-zone offset is present on @dt. 3880 * 3881 * Returns a normalized copy of @dt or NULL if error. 3882 */ 3883static xmlSchemaValPtr 3884xmlSchemaDateNormalize (xmlSchemaValPtr dt, double offset) 3885{ 3886 xmlSchemaValPtr dur, ret; 3887 3888 if (dt == NULL) 3889 return NULL; 3890 3891 if (((dt->type != XML_SCHEMAS_TIME) && 3892 (dt->type != XML_SCHEMAS_DATETIME) && 3893 (dt->type != XML_SCHEMAS_DATE)) || (dt->value.date.tzo == 0)) 3894 return xmlSchemaDupVal(dt); 3895 3896 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION); 3897 if (dur == NULL) 3898 return NULL; 3899 3900 dur->value.date.sec -= offset; 3901 3902 ret = _xmlSchemaDateAdd(dt, dur); 3903 if (ret == NULL) 3904 return NULL; 3905 3906 xmlSchemaFreeValue(dur); 3907 3908 /* ret->value.date.tzo = 0; */ 3909 return ret; 3910} 3911 3912/** 3913 * _xmlSchemaDateCastYMToDays: 3914 * @dt: an #xmlSchemaValPtr 3915 * 3916 * Convert mon and year of @dt to total number of days. Take the 3917 * number of years since (or before) 1 AD and add the number of leap 3918 * years. This is a function because negative 3919 * years must be handled a little differently and there is no zero year. 3920 * 3921 * Returns number of days. 3922 */ 3923static long 3924_xmlSchemaDateCastYMToDays (const xmlSchemaValPtr dt) 3925{ 3926 long ret; 3927 int mon; 3928 3929 mon = dt->value.date.mon; 3930 if (mon <= 0) mon = 1; /* normalization */ 3931 3932 if (dt->value.date.year <= 0) 3933 ret = (dt->value.date.year * 365) + 3934 (((dt->value.date.year+1)/4)-((dt->value.date.year+1)/100)+ 3935 ((dt->value.date.year+1)/400)) + 3936 DAY_IN_YEAR(0, mon, dt->value.date.year); 3937 else 3938 ret = ((dt->value.date.year-1) * 365) + 3939 (((dt->value.date.year-1)/4)-((dt->value.date.year-1)/100)+ 3940 ((dt->value.date.year-1)/400)) + 3941 DAY_IN_YEAR(0, mon, dt->value.date.year); 3942 3943 return ret; 3944} 3945 3946/** 3947 * TIME_TO_NUMBER: 3948 * @dt: an #xmlSchemaValPtr 3949 * 3950 * Calculates the number of seconds in the time portion of @dt. 3951 * 3952 * Returns seconds. 3953 */ 3954#define TIME_TO_NUMBER(dt) \ 3955 ((double)((dt->value.date.hour * SECS_PER_HOUR) + \ 3956 (dt->value.date.min * SECS_PER_MIN) + \ 3957 (dt->value.date.tzo * SECS_PER_MIN)) + \ 3958 dt->value.date.sec) 3959 3960/** 3961 * xmlSchemaCompareDates: 3962 * @x: a first date/time value 3963 * @y: a second date/time value 3964 * 3965 * Compare 2 date/times 3966 * 3967 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in 3968 * case of error 3969 */ 3970static int 3971xmlSchemaCompareDates (xmlSchemaValPtr x, xmlSchemaValPtr y) 3972{ 3973 unsigned char xmask, ymask, xor_mask, and_mask; 3974 xmlSchemaValPtr p1, p2, q1, q2; 3975 long p1d, p2d, q1d, q2d; 3976 3977 if ((x == NULL) || (y == NULL)) 3978 return -2; 3979 3980 if (x->value.date.tz_flag) { 3981 3982 if (!y->value.date.tz_flag) { 3983 p1 = xmlSchemaDateNormalize(x, 0); 3984 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day; 3985 /* normalize y + 14:00 */ 3986 q1 = xmlSchemaDateNormalize(y, (14 * SECS_PER_HOUR)); 3987 3988 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day; 3989 if (p1d < q1d) { 3990 xmlSchemaFreeValue(p1); 3991 xmlSchemaFreeValue(q1); 3992 return -1; 3993 } else if (p1d == q1d) { 3994 double sec; 3995 3996 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1); 3997 if (sec < 0.0) { 3998 xmlSchemaFreeValue(p1); 3999 xmlSchemaFreeValue(q1); 4000 return -1; 4001 } else { 4002 int ret = 0; 4003 /* normalize y - 14:00 */ 4004 q2 = xmlSchemaDateNormalize(y, -(14 * SECS_PER_HOUR)); 4005 q2d = _xmlSchemaDateCastYMToDays(q2) + q2->value.date.day; 4006 if (p1d > q2d) 4007 ret = 1; 4008 else if (p1d == q2d) { 4009 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q2); 4010 if (sec > 0.0) 4011 ret = 1; 4012 else 4013 ret = 2; /* indeterminate */ 4014 } 4015 xmlSchemaFreeValue(p1); 4016 xmlSchemaFreeValue(q1); 4017 xmlSchemaFreeValue(q2); 4018 if (ret != 0) 4019 return(ret); 4020 } 4021 } else { 4022 xmlSchemaFreeValue(p1); 4023 xmlSchemaFreeValue(q1); 4024 } 4025 } 4026 } else if (y->value.date.tz_flag) { 4027 q1 = xmlSchemaDateNormalize(y, 0); 4028 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day; 4029 4030 /* normalize x - 14:00 */ 4031 p1 = xmlSchemaDateNormalize(x, -(14 * SECS_PER_HOUR)); 4032 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day; 4033 4034 if (p1d < q1d) { 4035 xmlSchemaFreeValue(p1); 4036 xmlSchemaFreeValue(q1); 4037 return -1; 4038 } else if (p1d == q1d) { 4039 double sec; 4040 4041 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1); 4042 if (sec < 0.0) { 4043 xmlSchemaFreeValue(p1); 4044 xmlSchemaFreeValue(q1); 4045 return -1; 4046 } else { 4047 int ret = 0; 4048 /* normalize x + 14:00 */ 4049 p2 = xmlSchemaDateNormalize(x, (14 * SECS_PER_HOUR)); 4050 p2d = _xmlSchemaDateCastYMToDays(p2) + p2->value.date.day; 4051 4052 if (p2d > q1d) { 4053 ret = 1; 4054 } else if (p2d == q1d) { 4055 sec = TIME_TO_NUMBER(p2) - TIME_TO_NUMBER(q1); 4056 if (sec > 0.0) 4057 ret = 1; 4058 else 4059 ret = 2; /* indeterminate */ 4060 } 4061 xmlSchemaFreeValue(p1); 4062 xmlSchemaFreeValue(q1); 4063 xmlSchemaFreeValue(p2); 4064 if (ret != 0) 4065 return(ret); 4066 } 4067 } else { 4068 xmlSchemaFreeValue(p1); 4069 xmlSchemaFreeValue(q1); 4070 } 4071 } 4072 4073 /* 4074 * if the same type then calculate the difference 4075 */ 4076 if (x->type == y->type) { 4077 int ret = 0; 4078 q1 = xmlSchemaDateNormalize(y, 0); 4079 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day; 4080 4081 p1 = xmlSchemaDateNormalize(x, 0); 4082 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day; 4083 4084 if (p1d < q1d) { 4085 ret = -1; 4086 } else if (p1d > q1d) { 4087 ret = 1; 4088 } else { 4089 double sec; 4090 4091 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1); 4092 if (sec < 0.0) 4093 ret = -1; 4094 else if (sec > 0.0) 4095 ret = 1; 4096 4097 } 4098 xmlSchemaFreeValue(p1); 4099 xmlSchemaFreeValue(q1); 4100 return(ret); 4101 } 4102 4103 switch (x->type) { 4104 case XML_SCHEMAS_DATETIME: 4105 xmask = 0xf; 4106 break; 4107 case XML_SCHEMAS_DATE: 4108 xmask = 0x7; 4109 break; 4110 case XML_SCHEMAS_GYEAR: 4111 xmask = 0x1; 4112 break; 4113 case XML_SCHEMAS_GMONTH: 4114 xmask = 0x2; 4115 break; 4116 case XML_SCHEMAS_GDAY: 4117 xmask = 0x3; 4118 break; 4119 case XML_SCHEMAS_GYEARMONTH: 4120 xmask = 0x3; 4121 break; 4122 case XML_SCHEMAS_GMONTHDAY: 4123 xmask = 0x6; 4124 break; 4125 case XML_SCHEMAS_TIME: 4126 xmask = 0x8; 4127 break; 4128 default: 4129 xmask = 0; 4130 break; 4131 } 4132 4133 switch (y->type) { 4134 case XML_SCHEMAS_DATETIME: 4135 ymask = 0xf; 4136 break; 4137 case XML_SCHEMAS_DATE: 4138 ymask = 0x7; 4139 break; 4140 case XML_SCHEMAS_GYEAR: 4141 ymask = 0x1; 4142 break; 4143 case XML_SCHEMAS_GMONTH: 4144 ymask = 0x2; 4145 break; 4146 case XML_SCHEMAS_GDAY: 4147 ymask = 0x3; 4148 break; 4149 case XML_SCHEMAS_GYEARMONTH: 4150 ymask = 0x3; 4151 break; 4152 case XML_SCHEMAS_GMONTHDAY: 4153 ymask = 0x6; 4154 break; 4155 case XML_SCHEMAS_TIME: 4156 ymask = 0x8; 4157 break; 4158 default: 4159 ymask = 0; 4160 break; 4161 } 4162 4163 xor_mask = xmask ^ ymask; /* mark type differences */ 4164 and_mask = xmask & ymask; /* mark field specification */ 4165 4166 /* year */ 4167 if (xor_mask & 1) 4168 return 2; /* indeterminate */ 4169 else if (and_mask & 1) { 4170 if (x->value.date.year < y->value.date.year) 4171 return -1; 4172 else if (x->value.date.year > y->value.date.year) 4173 return 1; 4174 } 4175 4176 /* month */ 4177 if (xor_mask & 2) 4178 return 2; /* indeterminate */ 4179 else if (and_mask & 2) { 4180 if (x->value.date.mon < y->value.date.mon) 4181 return -1; 4182 else if (x->value.date.mon > y->value.date.mon) 4183 return 1; 4184 } 4185 4186 /* day */ 4187 if (xor_mask & 4) 4188 return 2; /* indeterminate */ 4189 else if (and_mask & 4) { 4190 if (x->value.date.day < y->value.date.day) 4191 return -1; 4192 else if (x->value.date.day > y->value.date.day) 4193 return 1; 4194 } 4195 4196 /* time */ 4197 if (xor_mask & 8) 4198 return 2; /* indeterminate */ 4199 else if (and_mask & 8) { 4200 if (x->value.date.hour < y->value.date.hour) 4201 return -1; 4202 else if (x->value.date.hour > y->value.date.hour) 4203 return 1; 4204 else if (x->value.date.min < y->value.date.min) 4205 return -1; 4206 else if (x->value.date.min > y->value.date.min) 4207 return 1; 4208 else if (x->value.date.sec < y->value.date.sec) 4209 return -1; 4210 else if (x->value.date.sec > y->value.date.sec) 4211 return 1; 4212 } 4213 4214 return 0; 4215} 4216 4217/** 4218 * xmlSchemaComparePreserveReplaceStrings: 4219 * @x: a first string value 4220 * @y: a second string value 4221 * @invert: inverts the result if x < y or x > y. 4222 * 4223 * Compare 2 string for their normalized values. 4224 * @x is a string with whitespace of "preserve", @y is 4225 * a string with a whitespace of "replace". I.e. @x could 4226 * be an "xsd:string" and @y an "xsd:normalizedString". 4227 * 4228 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in 4229 * case of error 4230 */ 4231static int 4232xmlSchemaComparePreserveReplaceStrings(const xmlChar *x, 4233 const xmlChar *y, 4234 int invert) 4235{ 4236 int tmp; 4237 4238 while ((*x != 0) && (*y != 0)) { 4239 if (IS_WSP_REPLACE_CH(*y)) { 4240 if (! IS_WSP_SPACE_CH(*x)) { 4241 if ((*x - 0x20) < 0) { 4242 if (invert) 4243 return(1); 4244 else 4245 return(-1); 4246 } else { 4247 if (invert) 4248 return(-1); 4249 else 4250 return(1); 4251 } 4252 } 4253 } else { 4254 tmp = *x - *y; 4255 if (tmp < 0) { 4256 if (invert) 4257 return(1); 4258 else 4259 return(-1); 4260 } 4261 if (tmp > 0) { 4262 if (invert) 4263 return(-1); 4264 else 4265 return(1); 4266 } 4267 } 4268 x++; 4269 y++; 4270 } 4271 if (*x != 0) { 4272 if (invert) 4273 return(-1); 4274 else 4275 return(1); 4276 } 4277 if (*y != 0) { 4278 if (invert) 4279 return(1); 4280 else 4281 return(-1); 4282 } 4283 return(0); 4284} 4285 4286/** 4287 * xmlSchemaComparePreserveCollapseStrings: 4288 * @x: a first string value 4289 * @y: a second string value 4290 * 4291 * Compare 2 string for their normalized values. 4292 * @x is a string with whitespace of "preserve", @y is 4293 * a string with a whitespace of "collapse". I.e. @x could 4294 * be an "xsd:string" and @y an "xsd:normalizedString". 4295 * 4296 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in 4297 * case of error 4298 */ 4299static int 4300xmlSchemaComparePreserveCollapseStrings(const xmlChar *x, 4301 const xmlChar *y, 4302 int invert) 4303{ 4304 int tmp; 4305 4306 /* 4307 * Skip leading blank chars of the collapsed string. 4308 */ 4309 while IS_WSP_BLANK_CH(*y) 4310 y++; 4311 4312 while ((*x != 0) && (*y != 0)) { 4313 if IS_WSP_BLANK_CH(*y) { 4314 if (! IS_WSP_SPACE_CH(*x)) { 4315 /* 4316 * The yv character would have been replaced to 0x20. 4317 */ 4318 if ((*x - 0x20) < 0) { 4319 if (invert) 4320 return(1); 4321 else 4322 return(-1); 4323 } else { 4324 if (invert) 4325 return(-1); 4326 else 4327 return(1); 4328 } 4329 } 4330 x++; 4331 y++; 4332 /* 4333 * Skip contiguous blank chars of the collapsed string. 4334 */ 4335 while IS_WSP_BLANK_CH(*y) 4336 y++; 4337 } else { 4338 tmp = *x++ - *y++; 4339 if (tmp < 0) { 4340 if (invert) 4341 return(1); 4342 else 4343 return(-1); 4344 } 4345 if (tmp > 0) { 4346 if (invert) 4347 return(-1); 4348 else 4349 return(1); 4350 } 4351 } 4352 } 4353 if (*x != 0) { 4354 if (invert) 4355 return(-1); 4356 else 4357 return(1); 4358 } 4359 if (*y != 0) { 4360 /* 4361 * Skip trailing blank chars of the collapsed string. 4362 */ 4363 while IS_WSP_BLANK_CH(*y) 4364 y++; 4365 if (*y != 0) { 4366 if (invert) 4367 return(1); 4368 else 4369 return(-1); 4370 } 4371 } 4372 return(0); 4373} 4374 4375/** 4376 * xmlSchemaComparePreserveCollapseStrings: 4377 * @x: a first string value 4378 * @y: a second string value 4379 * 4380 * Compare 2 string for their normalized values. 4381 * @x is a string with whitespace of "preserve", @y is 4382 * a string with a whitespace of "collapse". I.e. @x could 4383 * be an "xsd:string" and @y an "xsd:normalizedString". 4384 * 4385 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in 4386 * case of error 4387 */ 4388static int 4389xmlSchemaCompareReplaceCollapseStrings(const xmlChar *x, 4390 const xmlChar *y, 4391 int invert) 4392{ 4393 int tmp; 4394 4395 /* 4396 * Skip leading blank chars of the collapsed string. 4397 */ 4398 while IS_WSP_BLANK_CH(*y) 4399 y++; 4400 4401 while ((*x != 0) && (*y != 0)) { 4402 if IS_WSP_BLANK_CH(*y) { 4403 if (! IS_WSP_BLANK_CH(*x)) { 4404 /* 4405 * The yv character would have been replaced to 0x20. 4406 */ 4407 if ((*x - 0x20) < 0) { 4408 if (invert) 4409 return(1); 4410 else 4411 return(-1); 4412 } else { 4413 if (invert) 4414 return(-1); 4415 else 4416 return(1); 4417 } 4418 } 4419 x++; 4420 y++; 4421 /* 4422 * Skip contiguous blank chars of the collapsed string. 4423 */ 4424 while IS_WSP_BLANK_CH(*y) 4425 y++; 4426 } else { 4427 if IS_WSP_BLANK_CH(*x) { 4428 /* 4429 * The xv character would have been replaced to 0x20. 4430 */ 4431 if ((0x20 - *y) < 0) { 4432 if (invert) 4433 return(1); 4434 else 4435 return(-1); 4436 } else { 4437 if (invert) 4438 return(-1); 4439 else 4440 return(1); 4441 } 4442 } 4443 tmp = *x++ - *y++; 4444 if (tmp < 0) 4445 return(-1); 4446 if (tmp > 0) 4447 return(1); 4448 } 4449 } 4450 if (*x != 0) { 4451 if (invert) 4452 return(-1); 4453 else 4454 return(1); 4455 } 4456 if (*y != 0) { 4457 /* 4458 * Skip trailing blank chars of the collapsed string. 4459 */ 4460 while IS_WSP_BLANK_CH(*y) 4461 y++; 4462 if (*y != 0) { 4463 if (invert) 4464 return(1); 4465 else 4466 return(-1); 4467 } 4468 } 4469 return(0); 4470} 4471 4472 4473/** 4474 * xmlSchemaCompareReplacedStrings: 4475 * @x: a first string value 4476 * @y: a second string value 4477 * 4478 * Compare 2 string for their normalized values. 4479 * 4480 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in 4481 * case of error 4482 */ 4483static int 4484xmlSchemaCompareReplacedStrings(const xmlChar *x, 4485 const xmlChar *y) 4486{ 4487 int tmp; 4488 4489 while ((*x != 0) && (*y != 0)) { 4490 if IS_WSP_BLANK_CH(*y) { 4491 if (! IS_WSP_BLANK_CH(*x)) { 4492 if ((*x - 0x20) < 0) 4493 return(-1); 4494 else 4495 return(1); 4496 } 4497 } else { 4498 if IS_WSP_BLANK_CH(*x) { 4499 if ((0x20 - *y) < 0) 4500 return(-1); 4501 else 4502 return(1); 4503 } 4504 tmp = *x - *y; 4505 if (tmp < 0) 4506 return(-1); 4507 if (tmp > 0) 4508 return(1); 4509 } 4510 x++; 4511 y++; 4512 } 4513 if (*x != 0) 4514 return(1); 4515 if (*y != 0) 4516 return(-1); 4517 return(0); 4518} 4519 4520/** 4521 * xmlSchemaCompareNormStrings: 4522 * @x: a first string value 4523 * @y: a second string value 4524 * 4525 * Compare 2 string for their normalized values. 4526 * 4527 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in 4528 * case of error 4529 */ 4530static int 4531xmlSchemaCompareNormStrings(const xmlChar *x, 4532 const xmlChar *y) { 4533 int tmp; 4534 4535 while (IS_BLANK_CH(*x)) x++; 4536 while (IS_BLANK_CH(*y)) y++; 4537 while ((*x != 0) && (*y != 0)) { 4538 if (IS_BLANK_CH(*x)) { 4539 if (!IS_BLANK_CH(*y)) { 4540 tmp = *x - *y; 4541 return(tmp); 4542 } 4543 while (IS_BLANK_CH(*x)) x++; 4544 while (IS_BLANK_CH(*y)) y++; 4545 } else { 4546 tmp = *x++ - *y++; 4547 if (tmp < 0) 4548 return(-1); 4549 if (tmp > 0) 4550 return(1); 4551 } 4552 } 4553 if (*x != 0) { 4554 while (IS_BLANK_CH(*x)) x++; 4555 if (*x != 0) 4556 return(1); 4557 } 4558 if (*y != 0) { 4559 while (IS_BLANK_CH(*y)) y++; 4560 if (*y != 0) 4561 return(-1); 4562 } 4563 return(0); 4564} 4565 4566/** 4567 * xmlSchemaCompareFloats: 4568 * @x: a first float or double value 4569 * @y: a second float or double value 4570 * 4571 * Compare 2 values 4572 * 4573 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in 4574 * case of error 4575 */ 4576static int 4577xmlSchemaCompareFloats(xmlSchemaValPtr x, xmlSchemaValPtr y) { 4578 double d1, d2; 4579 4580 if ((x == NULL) || (y == NULL)) 4581 return(-2); 4582 4583 /* 4584 * Cast everything to doubles. 4585 */ 4586 if (x->type == XML_SCHEMAS_DOUBLE) 4587 d1 = x->value.d; 4588 else if (x->type == XML_SCHEMAS_FLOAT) 4589 d1 = x->value.f; 4590 else 4591 return(-2); 4592 4593 if (y->type == XML_SCHEMAS_DOUBLE) 4594 d2 = y->value.d; 4595 else if (y->type == XML_SCHEMAS_FLOAT) 4596 d2 = y->value.f; 4597 else 4598 return(-2); 4599 4600 /* 4601 * Check for special cases. 4602 */ 4603 if (xmlXPathIsNaN(d1)) { 4604 if (xmlXPathIsNaN(d2)) 4605 return(0); 4606 return(1); 4607 } 4608 if (xmlXPathIsNaN(d2)) 4609 return(-1); 4610 if (d1 == xmlXPathPINF) { 4611 if (d2 == xmlXPathPINF) 4612 return(0); 4613 return(1); 4614 } 4615 if (d2 == xmlXPathPINF) 4616 return(-1); 4617 if (d1 == xmlXPathNINF) { 4618 if (d2 == xmlXPathNINF) 4619 return(0); 4620 return(-1); 4621 } 4622 if (d2 == xmlXPathNINF) 4623 return(1); 4624 4625 /* 4626 * basic tests, the last one we should have equality, but 4627 * portability is more important than speed and handling 4628 * NaN or Inf in a portable way is always a challenge, so ... 4629 */ 4630 if (d1 < d2) 4631 return(-1); 4632 if (d1 > d2) 4633 return(1); 4634 if (d1 == d2) 4635 return(0); 4636 return(2); 4637} 4638 4639/** 4640 * xmlSchemaCompareValues: 4641 * @x: a first value 4642 * @xvalue: the first value as a string (optional) 4643 * @xwtsp: the whitespace type 4644 * @y: a second value 4645 * @xvalue: the second value as a string (optional) 4646 * @ywtsp: the whitespace type 4647 * 4648 * Compare 2 values 4649 * 4650 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, 3 if not 4651 * comparable and -2 in case of error 4652 */ 4653static int 4654xmlSchemaCompareValuesInternal(xmlSchemaValType xtype, 4655 xmlSchemaValPtr x, 4656 const xmlChar *xvalue, 4657 xmlSchemaWhitespaceValueType xws, 4658 xmlSchemaValType ytype, 4659 xmlSchemaValPtr y, 4660 const xmlChar *yvalue, 4661 xmlSchemaWhitespaceValueType yws) 4662{ 4663 switch (xtype) { 4664 case XML_SCHEMAS_UNKNOWN: 4665 case XML_SCHEMAS_ANYTYPE: 4666 return(-2); 4667 case XML_SCHEMAS_INTEGER: 4668 case XML_SCHEMAS_NPINTEGER: 4669 case XML_SCHEMAS_NINTEGER: 4670 case XML_SCHEMAS_NNINTEGER: 4671 case XML_SCHEMAS_PINTEGER: 4672 case XML_SCHEMAS_INT: 4673 case XML_SCHEMAS_UINT: 4674 case XML_SCHEMAS_LONG: 4675 case XML_SCHEMAS_ULONG: 4676 case XML_SCHEMAS_SHORT: 4677 case XML_SCHEMAS_USHORT: 4678 case XML_SCHEMAS_BYTE: 4679 case XML_SCHEMAS_UBYTE: 4680 case XML_SCHEMAS_DECIMAL: 4681 if ((x == NULL) || (y == NULL)) 4682 return(-2); 4683 if (ytype == xtype) 4684 return(xmlSchemaCompareDecimals(x, y)); 4685 if ((ytype == XML_SCHEMAS_DECIMAL) || 4686 (ytype == XML_SCHEMAS_INTEGER) || 4687 (ytype == XML_SCHEMAS_NPINTEGER) || 4688 (ytype == XML_SCHEMAS_NINTEGER) || 4689 (ytype == XML_SCHEMAS_NNINTEGER) || 4690 (ytype == XML_SCHEMAS_PINTEGER) || 4691 (ytype == XML_SCHEMAS_INT) || 4692 (ytype == XML_SCHEMAS_UINT) || 4693 (ytype == XML_SCHEMAS_LONG) || 4694 (ytype == XML_SCHEMAS_ULONG) || 4695 (ytype == XML_SCHEMAS_SHORT) || 4696 (ytype == XML_SCHEMAS_USHORT) || 4697 (ytype == XML_SCHEMAS_BYTE) || 4698 (ytype == XML_SCHEMAS_UBYTE)) 4699 return(xmlSchemaCompareDecimals(x, y)); 4700 return(-2); 4701 case XML_SCHEMAS_DURATION: 4702 if ((x == NULL) || (y == NULL)) 4703 return(-2); 4704 if (ytype == XML_SCHEMAS_DURATION) 4705 return(xmlSchemaCompareDurations(x, y)); 4706 return(-2); 4707 case XML_SCHEMAS_TIME: 4708 case XML_SCHEMAS_GDAY: 4709 case XML_SCHEMAS_GMONTH: 4710 case XML_SCHEMAS_GMONTHDAY: 4711 case XML_SCHEMAS_GYEAR: 4712 case XML_SCHEMAS_GYEARMONTH: 4713 case XML_SCHEMAS_DATE: 4714 case XML_SCHEMAS_DATETIME: 4715 if ((x == NULL) || (y == NULL)) 4716 return(-2); 4717 if ((ytype == XML_SCHEMAS_DATETIME) || 4718 (ytype == XML_SCHEMAS_TIME) || 4719 (ytype == XML_SCHEMAS_GDAY) || 4720 (ytype == XML_SCHEMAS_GMONTH) || 4721 (ytype == XML_SCHEMAS_GMONTHDAY) || 4722 (ytype == XML_SCHEMAS_GYEAR) || 4723 (ytype == XML_SCHEMAS_DATE) || 4724 (ytype == XML_SCHEMAS_GYEARMONTH)) 4725 return (xmlSchemaCompareDates(x, y)); 4726 return (-2); 4727 /* 4728 * Note that we will support comparison of string types against 4729 * anySimpleType as well. 4730 */ 4731 case XML_SCHEMAS_ANYSIMPLETYPE: 4732 case XML_SCHEMAS_STRING: 4733 case XML_SCHEMAS_NORMSTRING: 4734 case XML_SCHEMAS_TOKEN: 4735 case XML_SCHEMAS_LANGUAGE: 4736 case XML_SCHEMAS_NMTOKEN: 4737 case XML_SCHEMAS_NAME: 4738 case XML_SCHEMAS_NCNAME: 4739 case XML_SCHEMAS_ID: 4740 case XML_SCHEMAS_IDREF: 4741 case XML_SCHEMAS_ENTITY: 4742 case XML_SCHEMAS_ANYURI: 4743 { 4744 const xmlChar *xv, *yv; 4745 4746 if (x == NULL) 4747 xv = xvalue; 4748 else 4749 xv = x->value.str; 4750 if (y == NULL) 4751 yv = yvalue; 4752 else 4753 yv = y->value.str; 4754 /* 4755 * TODO: Compare those against QName. 4756 */ 4757 if (ytype == XML_SCHEMAS_QNAME) { 4758 TODO 4759 if (y == NULL) 4760 return(-2); 4761 return (-2); 4762 } 4763 if ((ytype == XML_SCHEMAS_ANYSIMPLETYPE) || 4764 (ytype == XML_SCHEMAS_STRING) || 4765 (ytype == XML_SCHEMAS_NORMSTRING) || 4766 (ytype == XML_SCHEMAS_TOKEN) || 4767 (ytype == XML_SCHEMAS_LANGUAGE) || 4768 (ytype == XML_SCHEMAS_NMTOKEN) || 4769 (ytype == XML_SCHEMAS_NAME) || 4770 (ytype == XML_SCHEMAS_NCNAME) || 4771 (ytype == XML_SCHEMAS_ID) || 4772 (ytype == XML_SCHEMAS_IDREF) || 4773 (ytype == XML_SCHEMAS_ENTITY) || 4774 (ytype == XML_SCHEMAS_ANYURI)) { 4775 4776 if (xws == XML_SCHEMA_WHITESPACE_PRESERVE) { 4777 4778 if (yws == XML_SCHEMA_WHITESPACE_PRESERVE) { 4779 /* TODO: What about x < y or x > y. */ 4780 if (xmlStrEqual(xv, yv)) 4781 return (0); 4782 else 4783 return (2); 4784 } else if (yws == XML_SCHEMA_WHITESPACE_REPLACE) 4785 return (xmlSchemaComparePreserveReplaceStrings(xv, yv, 0)); 4786 else if (yws == XML_SCHEMA_WHITESPACE_COLLAPSE) 4787 return (xmlSchemaComparePreserveCollapseStrings(xv, yv, 0)); 4788 4789 } else if (xws == XML_SCHEMA_WHITESPACE_REPLACE) { 4790 4791 if (yws == XML_SCHEMA_WHITESPACE_PRESERVE) 4792 return (xmlSchemaComparePreserveReplaceStrings(yv, xv, 1)); 4793 if (yws == XML_SCHEMA_WHITESPACE_REPLACE) 4794 return (xmlSchemaCompareReplacedStrings(xv, yv)); 4795 if (yws == XML_SCHEMA_WHITESPACE_COLLAPSE) 4796 return (xmlSchemaCompareReplaceCollapseStrings(xv, yv, 0)); 4797 4798 } else if (xws == XML_SCHEMA_WHITESPACE_COLLAPSE) { 4799 4800 if (yws == XML_SCHEMA_WHITESPACE_PRESERVE) 4801 return (xmlSchemaComparePreserveCollapseStrings(yv, xv, 1)); 4802 if (yws == XML_SCHEMA_WHITESPACE_REPLACE) 4803 return (xmlSchemaCompareReplaceCollapseStrings(yv, xv, 1)); 4804 if (yws == XML_SCHEMA_WHITESPACE_COLLAPSE) 4805 return (xmlSchemaCompareNormStrings(xv, yv)); 4806 } else 4807 return (-2); 4808 4809 } 4810 return (-2); 4811 } 4812 case XML_SCHEMAS_QNAME: 4813 case XML_SCHEMAS_NOTATION: 4814 if ((x == NULL) || (y == NULL)) 4815 return(-2); 4816 if ((ytype == XML_SCHEMAS_QNAME) || 4817 (ytype == XML_SCHEMAS_NOTATION)) { 4818 if ((xmlStrEqual(x->value.qname.name, y->value.qname.name)) && 4819 (xmlStrEqual(x->value.qname.uri, y->value.qname.uri))) 4820 return(0); 4821 return(2); 4822 } 4823 return (-2); 4824 case XML_SCHEMAS_FLOAT: 4825 case XML_SCHEMAS_DOUBLE: 4826 if ((x == NULL) || (y == NULL)) 4827 return(-2); 4828 if ((ytype == XML_SCHEMAS_FLOAT) || 4829 (ytype == XML_SCHEMAS_DOUBLE)) 4830 return (xmlSchemaCompareFloats(x, y)); 4831 return (-2); 4832 case XML_SCHEMAS_BOOLEAN: 4833 if ((x == NULL) || (y == NULL)) 4834 return(-2); 4835 if (ytype == XML_SCHEMAS_BOOLEAN) { 4836 if (x->value.b == y->value.b) 4837 return(0); 4838 if (x->value.b == 0) 4839 return(-1); 4840 return(1); 4841 } 4842 return (-2); 4843 case XML_SCHEMAS_HEXBINARY: 4844 if ((x == NULL) || (y == NULL)) 4845 return(-2); 4846 if (ytype == XML_SCHEMAS_HEXBINARY) { 4847 if (x->value.hex.total == y->value.hex.total) { 4848 int ret = xmlStrcmp(x->value.hex.str, y->value.hex.str); 4849 if (ret > 0) 4850 return(1); 4851 else if (ret == 0) 4852 return(0); 4853 } 4854 else if (x->value.hex.total > y->value.hex.total) 4855 return(1); 4856 4857 return(-1); 4858 } 4859 return (-2); 4860 case XML_SCHEMAS_BASE64BINARY: 4861 if ((x == NULL) || (y == NULL)) 4862 return(-2); 4863 if (ytype == XML_SCHEMAS_BASE64BINARY) { 4864 if (x->value.base64.total == y->value.base64.total) { 4865 int ret = xmlStrcmp(x->value.base64.str, 4866 y->value.base64.str); 4867 if (ret > 0) 4868 return(1); 4869 else if (ret == 0) 4870 return(0); 4871 else 4872 return(-1); 4873 } 4874 else if (x->value.base64.total > y->value.base64.total) 4875 return(1); 4876 else 4877 return(-1); 4878 } 4879 return (-2); 4880 case XML_SCHEMAS_IDREFS: 4881 case XML_SCHEMAS_ENTITIES: 4882 case XML_SCHEMAS_NMTOKENS: 4883 TODO 4884 break; 4885 } 4886 return -2; 4887} 4888 4889/** 4890 * xmlSchemaCompareValues: 4891 * @x: a first value 4892 * @y: a second value 4893 * 4894 * Compare 2 values 4895 * 4896 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in 4897 * case of error 4898 */ 4899int 4900xmlSchemaCompareValues(xmlSchemaValPtr x, xmlSchemaValPtr y) { 4901 xmlSchemaWhitespaceValueType xws, yws; 4902 4903 if ((x == NULL) || (y == NULL)) 4904 return(-2); 4905 if (x->type == XML_SCHEMAS_STRING) 4906 xws = XML_SCHEMA_WHITESPACE_PRESERVE; 4907 else if (x->type == XML_SCHEMAS_NORMSTRING) 4908 xws = XML_SCHEMA_WHITESPACE_REPLACE; 4909 else 4910 xws = XML_SCHEMA_WHITESPACE_COLLAPSE; 4911 4912 if (y->type == XML_SCHEMAS_STRING) 4913 yws = XML_SCHEMA_WHITESPACE_PRESERVE; 4914 else if (x->type == XML_SCHEMAS_NORMSTRING) 4915 yws = XML_SCHEMA_WHITESPACE_REPLACE; 4916 else 4917 yws = XML_SCHEMA_WHITESPACE_COLLAPSE; 4918 4919 return(xmlSchemaCompareValuesInternal(x->type, x, NULL, xws, y->type, 4920 y, NULL, yws)); 4921} 4922 4923/** 4924 * xmlSchemaCompareValuesWhtsp: 4925 * @x: a first value 4926 * @xws: the whitespace value of x 4927 * @y: a second value 4928 * @yws: the whitespace value of y 4929 * 4930 * Compare 2 values 4931 * 4932 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in 4933 * case of error 4934 */ 4935int 4936xmlSchemaCompareValuesWhtsp(xmlSchemaValPtr x, 4937 xmlSchemaWhitespaceValueType xws, 4938 xmlSchemaValPtr y, 4939 xmlSchemaWhitespaceValueType yws) 4940{ 4941 if ((x == NULL) || (y == NULL)) 4942 return(-2); 4943 return(xmlSchemaCompareValuesInternal(x->type, x, NULL, xws, y->type, 4944 y, NULL, yws)); 4945} 4946 4947/** 4948 * xmlSchemaCompareValuesWhtspExt: 4949 * @x: a first value 4950 * @xws: the whitespace value of x 4951 * @y: a second value 4952 * @yws: the whitespace value of y 4953 * 4954 * Compare 2 values 4955 * 4956 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in 4957 * case of error 4958 */ 4959static int 4960xmlSchemaCompareValuesWhtspExt(xmlSchemaValType xtype, 4961 xmlSchemaValPtr x, 4962 const xmlChar *xvalue, 4963 xmlSchemaWhitespaceValueType xws, 4964 xmlSchemaValType ytype, 4965 xmlSchemaValPtr y, 4966 const xmlChar *yvalue, 4967 xmlSchemaWhitespaceValueType yws) 4968{ 4969 return(xmlSchemaCompareValuesInternal(xtype, x, xvalue, xws, ytype, y, 4970 yvalue, yws)); 4971} 4972 4973/** 4974 * xmlSchemaNormLen: 4975 * @value: a string 4976 * 4977 * Computes the UTF8 length of the normalized value of the string 4978 * 4979 * Returns the length or -1 in case of error. 4980 */ 4981static int 4982xmlSchemaNormLen(const xmlChar *value) { 4983 const xmlChar *utf; 4984 int ret = 0; 4985 4986 if (value == NULL) 4987 return(-1); 4988 utf = value; 4989 while (IS_BLANK_CH(*utf)) utf++; 4990 while (*utf != 0) { 4991 if (utf[0] & 0x80) { 4992 if ((utf[1] & 0xc0) != 0x80) 4993 return(-1); 4994 if ((utf[0] & 0xe0) == 0xe0) { 4995 if ((utf[2] & 0xc0) != 0x80) 4996 return(-1); 4997 if ((utf[0] & 0xf0) == 0xf0) { 4998 if ((utf[0] & 0xf8) != 0xf0 || (utf[3] & 0xc0) != 0x80) 4999 return(-1); 5000 utf += 4; 5001 } else { 5002 utf += 3; 5003 } 5004 } else { 5005 utf += 2; 5006 } 5007 } else if (IS_BLANK_CH(*utf)) { 5008 while (IS_BLANK_CH(*utf)) utf++; 5009 if (*utf == 0) 5010 break; 5011 } else { 5012 utf++; 5013 } 5014 ret++; 5015 } 5016 return(ret); 5017} 5018 5019/** 5020 * xmlSchemaGetFacetValueAsULong: 5021 * @facet: an schemas type facet 5022 * 5023 * Extract the value of a facet 5024 * 5025 * Returns the value as a long 5026 */ 5027unsigned long 5028xmlSchemaGetFacetValueAsULong(xmlSchemaFacetPtr facet) 5029{ 5030 /* 5031 * TODO: Check if this is a decimal. 5032 */ 5033 if (facet == NULL) 5034 return 0; 5035 return ((unsigned long) facet->val->value.decimal.lo); 5036} 5037 5038/** 5039 * xmlSchemaValidateListSimpleTypeFacet: 5040 * @facet: the facet to check 5041 * @value: the lexical repr of the value to validate 5042 * @actualLen: the number of list items 5043 * @expectedLen: the resulting expected number of list items 5044 * 5045 * Checks the value of a list simple type against a facet. 5046 * 5047 * Returns 0 if the value is valid, a positive error code 5048 * number otherwise and -1 in case of an internal error. 5049 */ 5050int 5051xmlSchemaValidateListSimpleTypeFacet(xmlSchemaFacetPtr facet, 5052 const xmlChar *value, 5053 unsigned long actualLen, 5054 unsigned long *expectedLen) 5055{ 5056 if (facet == NULL) 5057 return(-1); 5058 /* 5059 * TODO: Check if this will work with large numbers. 5060 * (compare value.decimal.mi and value.decimal.hi as well?). 5061 */ 5062 if (facet->type == XML_SCHEMA_FACET_LENGTH) { 5063 if (actualLen != facet->val->value.decimal.lo) { 5064 if (expectedLen != NULL) 5065 *expectedLen = facet->val->value.decimal.lo; 5066 return (XML_SCHEMAV_CVC_LENGTH_VALID); 5067 } 5068 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) { 5069 if (actualLen < facet->val->value.decimal.lo) { 5070 if (expectedLen != NULL) 5071 *expectedLen = facet->val->value.decimal.lo; 5072 return (XML_SCHEMAV_CVC_MINLENGTH_VALID); 5073 } 5074 } else if (facet->type == XML_SCHEMA_FACET_MAXLENGTH) { 5075 if (actualLen > facet->val->value.decimal.lo) { 5076 if (expectedLen != NULL) 5077 *expectedLen = facet->val->value.decimal.lo; 5078 return (XML_SCHEMAV_CVC_MAXLENGTH_VALID); 5079 } 5080 } else 5081 /* 5082 * NOTE: That we can pass NULL as xmlSchemaValPtr to 5083 * xmlSchemaValidateFacet, since the remaining facet types 5084 * are: XML_SCHEMA_FACET_PATTERN, XML_SCHEMA_FACET_ENUMERATION. 5085 */ 5086 return(xmlSchemaValidateFacet(NULL, facet, value, NULL)); 5087 return (0); 5088} 5089 5090/** 5091 * xmlSchemaValidateLengthFacet: 5092 * @type: the built-in type 5093 * @facet: the facet to check 5094 * @value: the lexical repr. of the value to be validated 5095 * @val: the precomputed value 5096 * @ws: the whitespace type of the value 5097 * @length: the actual length of the value 5098 * 5099 * Checka a value against a "length", "minLength" and "maxLength" 5100 * facet; sets @length to the computed length of @value. 5101 * 5102 * Returns 0 if the value is valid, a positive error code 5103 * otherwise and -1 in case of an internal or API error. 5104 */ 5105static int 5106xmlSchemaValidateLengthFacetInternal(xmlSchemaFacetPtr facet, 5107 xmlSchemaTypeType valType, 5108 const xmlChar *value, 5109 xmlSchemaValPtr val, 5110 unsigned long *length, 5111 xmlSchemaWhitespaceValueType ws) 5112{ 5113 unsigned int len = 0; 5114 5115 if ((length == NULL) || (facet == NULL)) 5116 return (-1); 5117 *length = 0; 5118 if ((facet->type != XML_SCHEMA_FACET_LENGTH) && 5119 (facet->type != XML_SCHEMA_FACET_MAXLENGTH) && 5120 (facet->type != XML_SCHEMA_FACET_MINLENGTH)) 5121 return (-1); 5122 5123 /* 5124 * TODO: length, maxLength and minLength must be of type 5125 * nonNegativeInteger only. Check if decimal is used somehow. 5126 */ 5127 if ((facet->val == NULL) || 5128 ((facet->val->type != XML_SCHEMAS_DECIMAL) && 5129 (facet->val->type != XML_SCHEMAS_NNINTEGER)) || 5130 (facet->val->value.decimal.frac != 0)) { 5131 return(-1); 5132 } 5133 if ((val != NULL) && (val->type == XML_SCHEMAS_HEXBINARY)) 5134 len = val->value.hex.total; 5135 else if ((val != NULL) && (val->type == XML_SCHEMAS_BASE64BINARY)) 5136 len = val->value.base64.total; 5137 else { 5138 switch (valType) { 5139 case XML_SCHEMAS_STRING: 5140 case XML_SCHEMAS_NORMSTRING: 5141 if (ws == XML_SCHEMA_WHITESPACE_UNKNOWN) { 5142 /* 5143 * This is to ensure API compatibility with the old 5144 * xmlSchemaValidateLengthFacet(). Anyway, this was and 5145 * is not the correct handling. 5146 * TODO: Get rid of this case somehow. 5147 */ 5148 if (valType == XML_SCHEMAS_STRING) 5149 len = xmlUTF8Strlen(value); 5150 else 5151 len = xmlSchemaNormLen(value); 5152 } else if (value != NULL) { 5153 if (ws == XML_SCHEMA_WHITESPACE_COLLAPSE) 5154 len = xmlSchemaNormLen(value); 5155 else 5156 /* 5157 * Should be OK for "preserve" as well. 5158 */ 5159 len = xmlUTF8Strlen(value); 5160 } 5161 break; 5162 case XML_SCHEMAS_IDREF: 5163 case XML_SCHEMAS_TOKEN: 5164 case XML_SCHEMAS_LANGUAGE: 5165 case XML_SCHEMAS_NMTOKEN: 5166 case XML_SCHEMAS_NAME: 5167 case XML_SCHEMAS_NCNAME: 5168 case XML_SCHEMAS_ID: 5169 /* 5170 * FIXME: What exactly to do with anyURI? 5171 */ 5172 case XML_SCHEMAS_ANYURI: 5173 if (value != NULL) 5174 len = xmlSchemaNormLen(value); 5175 break; 5176 case XML_SCHEMAS_QNAME: 5177 case XML_SCHEMAS_NOTATION: 5178 /* 5179 * For QName and NOTATION, those facets are 5180 * deprecated and should be ignored. 5181 */ 5182 return (0); 5183 default: 5184 TODO 5185 } 5186 } 5187 *length = (unsigned long) len; 5188 /* 5189 * TODO: Return the whole expected value, i.e. "lo", "mi" and "hi". 5190 */ 5191 if (facet->type == XML_SCHEMA_FACET_LENGTH) { 5192 if (len != facet->val->value.decimal.lo) 5193 return(XML_SCHEMAV_CVC_LENGTH_VALID); 5194 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) { 5195 if (len < facet->val->value.decimal.lo) 5196 return(XML_SCHEMAV_CVC_MINLENGTH_VALID); 5197 } else { 5198 if (len > facet->val->value.decimal.lo) 5199 return(XML_SCHEMAV_CVC_MAXLENGTH_VALID); 5200 } 5201 5202 return (0); 5203} 5204 5205/** 5206 * xmlSchemaValidateLengthFacet: 5207 * @type: the built-in type 5208 * @facet: the facet to check 5209 * @value: the lexical repr. of the value to be validated 5210 * @val: the precomputed value 5211 * @length: the actual length of the value 5212 * 5213 * Checka a value against a "length", "minLength" and "maxLength" 5214 * facet; sets @length to the computed length of @value. 5215 * 5216 * Returns 0 if the value is valid, a positive error code 5217 * otherwise and -1 in case of an internal or API error. 5218 */ 5219int 5220xmlSchemaValidateLengthFacet(xmlSchemaTypePtr type, 5221 xmlSchemaFacetPtr facet, 5222 const xmlChar *value, 5223 xmlSchemaValPtr val, 5224 unsigned long *length) 5225{ 5226 if (type == NULL) 5227 return(-1); 5228 return (xmlSchemaValidateLengthFacetInternal(facet, 5229 type->builtInType, value, val, length, 5230 XML_SCHEMA_WHITESPACE_UNKNOWN)); 5231} 5232 5233/** 5234 * xmlSchemaValidateLengthFacetWhtsp: 5235 * @facet: the facet to check 5236 * @valType: the built-in type 5237 * @value: the lexical repr. of the value to be validated 5238 * @val: the precomputed value 5239 * @ws: the whitespace type of the value 5240 * @length: the actual length of the value 5241 * 5242 * Checka a value against a "length", "minLength" and "maxLength" 5243 * facet; sets @length to the computed length of @value. 5244 * 5245 * Returns 0 if the value is valid, a positive error code 5246 * otherwise and -1 in case of an internal or API error. 5247 */ 5248int 5249xmlSchemaValidateLengthFacetWhtsp(xmlSchemaFacetPtr facet, 5250 xmlSchemaValType valType, 5251 const xmlChar *value, 5252 xmlSchemaValPtr val, 5253 unsigned long *length, 5254 xmlSchemaWhitespaceValueType ws) 5255{ 5256 return (xmlSchemaValidateLengthFacetInternal(facet, valType, value, val, 5257 length, ws)); 5258} 5259 5260/** 5261 * xmlSchemaValidateFacetInternal: 5262 * @facet: the facet to check 5263 * @fws: the whitespace type of the facet's value 5264 * @valType: the built-in type of the value 5265 * @value: the lexical repr of the value to validate 5266 * @val: the precomputed value 5267 * @ws: the whitespace type of the value 5268 * 5269 * Check a value against a facet condition 5270 * 5271 * Returns 0 if the element is schemas valid, a positive error code 5272 * number otherwise and -1 in case of internal or API error. 5273 */ 5274static int 5275xmlSchemaValidateFacetInternal(xmlSchemaFacetPtr facet, 5276 xmlSchemaWhitespaceValueType fws, 5277 xmlSchemaValType valType, 5278 const xmlChar *value, 5279 xmlSchemaValPtr val, 5280 xmlSchemaWhitespaceValueType ws) 5281{ 5282 int ret; 5283 5284 if (facet == NULL) 5285 return(-1); 5286 5287 switch (facet->type) { 5288 case XML_SCHEMA_FACET_PATTERN: 5289 /* 5290 * NOTE that for patterns, the @value needs to be the normalized 5291 * value, *not* the lexical initial value or the canonical value. 5292 */ 5293 if (value == NULL) 5294 return(-1); 5295 ret = xmlRegexpExec(facet->regexp, value); 5296 if (ret == 1) 5297 return(0); 5298 if (ret == 0) 5299 return(XML_SCHEMAV_CVC_PATTERN_VALID); 5300 return(ret); 5301 case XML_SCHEMA_FACET_MAXEXCLUSIVE: 5302 ret = xmlSchemaCompareValues(val, facet->val); 5303 if (ret == -2) 5304 return(-1); 5305 if (ret == -1) 5306 return(0); 5307 return(XML_SCHEMAV_CVC_MAXEXCLUSIVE_VALID); 5308 case XML_SCHEMA_FACET_MAXINCLUSIVE: 5309 ret = xmlSchemaCompareValues(val, facet->val); 5310 if (ret == -2) 5311 return(-1); 5312 if ((ret == -1) || (ret == 0)) 5313 return(0); 5314 return(XML_SCHEMAV_CVC_MAXINCLUSIVE_VALID); 5315 case XML_SCHEMA_FACET_MINEXCLUSIVE: 5316 ret = xmlSchemaCompareValues(val, facet->val); 5317 if (ret == -2) 5318 return(-1); 5319 if (ret == 1) 5320 return(0); 5321 return(XML_SCHEMAV_CVC_MINEXCLUSIVE_VALID); 5322 case XML_SCHEMA_FACET_MININCLUSIVE: 5323 ret = xmlSchemaCompareValues(val, facet->val); 5324 if (ret == -2) 5325 return(-1); 5326 if ((ret == 1) || (ret == 0)) 5327 return(0); 5328 return(XML_SCHEMAV_CVC_MININCLUSIVE_VALID); 5329 case XML_SCHEMA_FACET_WHITESPACE: 5330 /* TODO whitespaces */ 5331 /* 5332 * NOTE: Whitespace should be handled to normalize 5333 * the value to be validated against a the facets; 5334 * not to normalize the value in-between. 5335 */ 5336 return(0); 5337 case XML_SCHEMA_FACET_ENUMERATION: 5338 if (ws == XML_SCHEMA_WHITESPACE_UNKNOWN) { 5339 /* 5340 * This is to ensure API compatibility with the old 5341 * xmlSchemaValidateFacet(). 5342 * TODO: Get rid of this case. 5343 */ 5344 if ((facet->value != NULL) && 5345 (xmlStrEqual(facet->value, value))) 5346 return(0); 5347 } else { 5348 ret = xmlSchemaCompareValuesWhtspExt(facet->val->type, 5349 facet->val, facet->value, fws, valType, val, 5350 value, ws); 5351 if (ret == -2) 5352 return(-1); 5353 if (ret == 0) 5354 return(0); 5355 } 5356 return(XML_SCHEMAV_CVC_ENUMERATION_VALID); 5357 case XML_SCHEMA_FACET_LENGTH: 5358 /* 5359 * SPEC (1.3) "if {primitive type definition} is QName or NOTATION, 5360 * then any {value} is facet-valid." 5361 */ 5362 if ((valType == XML_SCHEMAS_QNAME) || 5363 (valType == XML_SCHEMAS_NOTATION)) 5364 return (0); 5365 /* No break on purpose. */ 5366 case XML_SCHEMA_FACET_MAXLENGTH: 5367 case XML_SCHEMA_FACET_MINLENGTH: { 5368 unsigned int len = 0; 5369 5370 if ((valType == XML_SCHEMAS_QNAME) || 5371 (valType == XML_SCHEMAS_NOTATION)) 5372 return (0); 5373 /* 5374 * TODO: length, maxLength and minLength must be of type 5375 * nonNegativeInteger only. Check if decimal is used somehow. 5376 */ 5377 if ((facet->val == NULL) || 5378 ((facet->val->type != XML_SCHEMAS_DECIMAL) && 5379 (facet->val->type != XML_SCHEMAS_NNINTEGER)) || 5380 (facet->val->value.decimal.frac != 0)) { 5381 return(-1); 5382 } 5383 if ((val != NULL) && (val->type == XML_SCHEMAS_HEXBINARY)) 5384 len = val->value.hex.total; 5385 else if ((val != NULL) && (val->type == XML_SCHEMAS_BASE64BINARY)) 5386 len = val->value.base64.total; 5387 else { 5388 switch (valType) { 5389 case XML_SCHEMAS_STRING: 5390 case XML_SCHEMAS_NORMSTRING: 5391 if (ws == XML_SCHEMA_WHITESPACE_UNKNOWN) { 5392 /* 5393 * This is to ensure API compatibility with the old 5394 * xmlSchemaValidateFacet(). Anyway, this was and 5395 * is not the correct handling. 5396 * TODO: Get rid of this case somehow. 5397 */ 5398 if (valType == XML_SCHEMAS_STRING) 5399 len = xmlUTF8Strlen(value); 5400 else 5401 len = xmlSchemaNormLen(value); 5402 } else if (value != NULL) { 5403 if (ws == XML_SCHEMA_WHITESPACE_COLLAPSE) 5404 len = xmlSchemaNormLen(value); 5405 else 5406 /* 5407 * Should be OK for "preserve" as well. 5408 */ 5409 len = xmlUTF8Strlen(value); 5410 } 5411 break; 5412 case XML_SCHEMAS_IDREF: 5413 case XML_SCHEMAS_TOKEN: 5414 case XML_SCHEMAS_LANGUAGE: 5415 case XML_SCHEMAS_NMTOKEN: 5416 case XML_SCHEMAS_NAME: 5417 case XML_SCHEMAS_NCNAME: 5418 case XML_SCHEMAS_ID: 5419 case XML_SCHEMAS_ANYURI: 5420 if (value != NULL) 5421 len = xmlSchemaNormLen(value); 5422 break; 5423 default: 5424 TODO 5425 } 5426 } 5427 if (facet->type == XML_SCHEMA_FACET_LENGTH) { 5428 if (len != facet->val->value.decimal.lo) 5429 return(XML_SCHEMAV_CVC_LENGTH_VALID); 5430 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) { 5431 if (len < facet->val->value.decimal.lo) 5432 return(XML_SCHEMAV_CVC_MINLENGTH_VALID); 5433 } else { 5434 if (len > facet->val->value.decimal.lo) 5435 return(XML_SCHEMAV_CVC_MAXLENGTH_VALID); 5436 } 5437 break; 5438 } 5439 case XML_SCHEMA_FACET_TOTALDIGITS: 5440 case XML_SCHEMA_FACET_FRACTIONDIGITS: 5441 5442 if ((facet->val == NULL) || 5443 ((facet->val->type != XML_SCHEMAS_PINTEGER) && 5444 (facet->val->type != XML_SCHEMAS_NNINTEGER)) || 5445 (facet->val->value.decimal.frac != 0)) { 5446 return(-1); 5447 } 5448 if ((val == NULL) || 5449 ((val->type != XML_SCHEMAS_DECIMAL) && 5450 (val->type != XML_SCHEMAS_INTEGER) && 5451 (val->type != XML_SCHEMAS_NPINTEGER) && 5452 (val->type != XML_SCHEMAS_NINTEGER) && 5453 (val->type != XML_SCHEMAS_NNINTEGER) && 5454 (val->type != XML_SCHEMAS_PINTEGER) && 5455 (val->type != XML_SCHEMAS_INT) && 5456 (val->type != XML_SCHEMAS_UINT) && 5457 (val->type != XML_SCHEMAS_LONG) && 5458 (val->type != XML_SCHEMAS_ULONG) && 5459 (val->type != XML_SCHEMAS_SHORT) && 5460 (val->type != XML_SCHEMAS_USHORT) && 5461 (val->type != XML_SCHEMAS_BYTE) && 5462 (val->type != XML_SCHEMAS_UBYTE))) { 5463 return(-1); 5464 } 5465 if (facet->type == XML_SCHEMA_FACET_TOTALDIGITS) { 5466 if (val->value.decimal.total > facet->val->value.decimal.lo) 5467 return(XML_SCHEMAV_CVC_TOTALDIGITS_VALID); 5468 5469 } else if (facet->type == XML_SCHEMA_FACET_FRACTIONDIGITS) { 5470 if (val->value.decimal.frac > facet->val->value.decimal.lo) 5471 return(XML_SCHEMAV_CVC_FRACTIONDIGITS_VALID); 5472 } 5473 break; 5474 default: 5475 TODO 5476 } 5477 return(0); 5478 5479} 5480 5481/** 5482 * xmlSchemaValidateFacet: 5483 * @base: the base type 5484 * @facet: the facet to check 5485 * @value: the lexical repr of the value to validate 5486 * @val: the precomputed value 5487 * 5488 * Check a value against a facet condition 5489 * 5490 * Returns 0 if the element is schemas valid, a positive error code 5491 * number otherwise and -1 in case of internal or API error. 5492 */ 5493int 5494xmlSchemaValidateFacet(xmlSchemaTypePtr base, 5495 xmlSchemaFacetPtr facet, 5496 const xmlChar *value, 5497 xmlSchemaValPtr val) 5498{ 5499 /* 5500 * This tries to ensure API compatibility regarding the old 5501 * xmlSchemaValidateFacet() and the new xmlSchemaValidateFacetInternal() and 5502 * xmlSchemaValidateFacetWhtsp(). 5503 */ 5504 if (val != NULL) 5505 return(xmlSchemaValidateFacetInternal(facet, 5506 XML_SCHEMA_WHITESPACE_UNKNOWN, val->type, value, val, 5507 XML_SCHEMA_WHITESPACE_UNKNOWN)); 5508 else if (base != NULL) 5509 return(xmlSchemaValidateFacetInternal(facet, 5510 XML_SCHEMA_WHITESPACE_UNKNOWN, base->builtInType, value, val, 5511 XML_SCHEMA_WHITESPACE_UNKNOWN)); 5512 return(-1); 5513} 5514 5515/** 5516 * xmlSchemaValidateFacetWhtsp: 5517 * @facet: the facet to check 5518 * @fws: the whitespace type of the facet's value 5519 * @valType: the built-in type of the value 5520 * @value: the lexical (or normalized for pattern) repr of the value to validate 5521 * @val: the precomputed value 5522 * @ws: the whitespace type of the value 5523 * 5524 * Check a value against a facet condition. This takes value normalization 5525 * according to the specified whitespace types into account. 5526 * Note that @value needs to be the *normalized* value if the facet 5527 * is of type "pattern". 5528 * 5529 * Returns 0 if the element is schemas valid, a positive error code 5530 * number otherwise and -1 in case of internal or API error. 5531 */ 5532int 5533xmlSchemaValidateFacetWhtsp(xmlSchemaFacetPtr facet, 5534 xmlSchemaWhitespaceValueType fws, 5535 xmlSchemaValType valType, 5536 const xmlChar *value, 5537 xmlSchemaValPtr val, 5538 xmlSchemaWhitespaceValueType ws) 5539{ 5540 return(xmlSchemaValidateFacetInternal(facet, fws, valType, 5541 value, val, ws)); 5542} 5543 5544#if 0 5545#ifndef DBL_DIG 5546#define DBL_DIG 16 5547#endif 5548#ifndef DBL_EPSILON 5549#define DBL_EPSILON 1E-9 5550#endif 5551 5552#define INTEGER_DIGITS DBL_DIG 5553#define FRACTION_DIGITS (DBL_DIG + 1) 5554#define EXPONENT_DIGITS (3 + 2) 5555 5556/** 5557 * xmlXPathFormatNumber: 5558 * @number: number to format 5559 * @buffer: output buffer 5560 * @buffersize: size of output buffer 5561 * 5562 * Convert the number into a string representation. 5563 */ 5564static void 5565xmlSchemaFormatFloat(double number, char buffer[], int buffersize) 5566{ 5567 switch (xmlXPathIsInf(number)) { 5568 case 1: 5569 if (buffersize > (int)sizeof("INF")) 5570 snprintf(buffer, buffersize, "INF"); 5571 break; 5572 case -1: 5573 if (buffersize > (int)sizeof("-INF")) 5574 snprintf(buffer, buffersize, "-INF"); 5575 break; 5576 default: 5577 if (xmlXPathIsNaN(number)) { 5578 if (buffersize > (int)sizeof("NaN")) 5579 snprintf(buffer, buffersize, "NaN"); 5580 } else if (number == 0) { 5581 snprintf(buffer, buffersize, "0.0E0"); 5582 } else { 5583 /* 3 is sign, decimal point, and terminating zero */ 5584 char work[DBL_DIG + EXPONENT_DIGITS + 3]; 5585 int integer_place, fraction_place; 5586 char *ptr; 5587 char *after_fraction; 5588 double absolute_value; 5589 int size; 5590 5591 absolute_value = fabs(number); 5592 5593 /* 5594 * Result is in work, and after_fraction points 5595 * just past the fractional part. 5596 * Use scientific notation 5597 */ 5598 integer_place = DBL_DIG + EXPONENT_DIGITS + 1; 5599 fraction_place = DBL_DIG - 1; 5600 snprintf(work, sizeof(work),"%*.*e", 5601 integer_place, fraction_place, number); 5602 after_fraction = strchr(work + DBL_DIG, 'e'); 5603 /* Remove fractional trailing zeroes */ 5604 ptr = after_fraction; 5605 while (*(--ptr) == '0') 5606 ; 5607 if (*ptr != '.') 5608 ptr++; 5609 while ((*ptr++ = *after_fraction++) != 0); 5610 5611 /* Finally copy result back to caller */ 5612 size = strlen(work) + 1; 5613 if (size > buffersize) { 5614 work[buffersize - 1] = 0; 5615 size = buffersize; 5616 } 5617 memmove(buffer, work, size); 5618 } 5619 break; 5620 } 5621} 5622#endif 5623 5624/** 5625 * xmlSchemaGetCanonValue: 5626 * @val: the precomputed value 5627 * @retValue: the returned value 5628 * 5629 * Get a the cononical lexical representation of the value. 5630 * The caller has to FREE the returned retValue. 5631 * 5632 * WARNING: Some value types are not supported yet, resulting 5633 * in a @retValue of "???". 5634 * 5635 * TODO: XML Schema 1.0 does not define canonical representations 5636 * for: duration, gYearMonth, gYear, gMonthDay, gMonth, gDay, 5637 * anyURI, QName, NOTATION. This will be fixed in XML Schema 1.1. 5638 * 5639 * 5640 * Returns 0 if the value could be built, 1 if the value type is 5641 * not supported yet and -1 in case of API errors. 5642 */ 5643int 5644xmlSchemaGetCanonValue(xmlSchemaValPtr val, const xmlChar **retValue) 5645{ 5646 if ((retValue == NULL) || (val == NULL)) 5647 return (-1); 5648 *retValue = NULL; 5649 switch (val->type) { 5650 case XML_SCHEMAS_STRING: 5651 if (val->value.str == NULL) 5652 *retValue = BAD_CAST xmlStrdup(BAD_CAST ""); 5653 else 5654 *retValue = 5655 BAD_CAST xmlStrdup((const xmlChar *) val->value.str); 5656 break; 5657 case XML_SCHEMAS_NORMSTRING: 5658 if (val->value.str == NULL) 5659 *retValue = BAD_CAST xmlStrdup(BAD_CAST ""); 5660 else { 5661 *retValue = xmlSchemaWhiteSpaceReplace( 5662 (const xmlChar *) val->value.str); 5663 if ((*retValue) == NULL) 5664 *retValue = BAD_CAST xmlStrdup( 5665 (const xmlChar *) val->value.str); 5666 } 5667 break; 5668 case XML_SCHEMAS_TOKEN: 5669 case XML_SCHEMAS_LANGUAGE: 5670 case XML_SCHEMAS_NMTOKEN: 5671 case XML_SCHEMAS_NAME: 5672 case XML_SCHEMAS_NCNAME: 5673 case XML_SCHEMAS_ID: 5674 case XML_SCHEMAS_IDREF: 5675 case XML_SCHEMAS_ENTITY: 5676 case XML_SCHEMAS_NOTATION: /* Unclear */ 5677 case XML_SCHEMAS_ANYURI: /* Unclear */ 5678 if (val->value.str == NULL) 5679 return (-1); 5680 *retValue = 5681 BAD_CAST xmlSchemaCollapseString(BAD_CAST val->value.str); 5682 if (*retValue == NULL) 5683 *retValue = 5684 BAD_CAST xmlStrdup((const xmlChar *) val->value.str); 5685 break; 5686 case XML_SCHEMAS_QNAME: 5687 /* TODO: Unclear in XML Schema 1.0. */ 5688 if (val->value.qname.uri == NULL) { 5689 *retValue = BAD_CAST xmlStrdup(BAD_CAST val->value.qname.name); 5690 return (0); 5691 } else { 5692 *retValue = BAD_CAST xmlStrdup(BAD_CAST "{"); 5693 *retValue = BAD_CAST xmlStrcat((xmlChar *) (*retValue), 5694 BAD_CAST val->value.qname.uri); 5695 *retValue = BAD_CAST xmlStrcat((xmlChar *) (*retValue), 5696 BAD_CAST "}"); 5697 *retValue = BAD_CAST xmlStrcat((xmlChar *) (*retValue), 5698 BAD_CAST val->value.qname.uri); 5699 } 5700 break; 5701 case XML_SCHEMAS_DECIMAL: 5702 /* 5703 * TODO: Lookout for a more simple implementation. 5704 */ 5705 if ((val->value.decimal.total == 1) && 5706 (val->value.decimal.lo == 0)) { 5707 *retValue = xmlStrdup(BAD_CAST "0.0"); 5708 } else { 5709 xmlSchemaValDecimal dec = val->value.decimal; 5710 int bufsize; 5711 char *buf = NULL, *offs; 5712 5713 /* Add room for the decimal point as well. */ 5714 bufsize = dec.total + 2; 5715 if (dec.sign) 5716 bufsize++; 5717 /* Add room for leading/trailing zero. */ 5718 if ((dec.frac == 0) || (dec.frac == dec.total)) 5719 bufsize++; 5720 buf = xmlMalloc(bufsize); 5721 if (buf == NULL) 5722 return(-1); 5723 offs = buf; 5724 if (dec.sign) 5725 *offs++ = '-'; 5726 if (dec.frac == dec.total) { 5727 *offs++ = '0'; 5728 *offs++ = '.'; 5729 } 5730 if (dec.hi != 0) 5731 snprintf(offs, bufsize - (offs - buf), 5732 "%lu%lu%lu", dec.hi, dec.mi, dec.lo); 5733 else if (dec.mi != 0) 5734 snprintf(offs, bufsize - (offs - buf), 5735 "%lu%lu", dec.mi, dec.lo); 5736 else 5737 snprintf(offs, bufsize - (offs - buf), 5738 "%lu", dec.lo); 5739 5740 if (dec.frac != 0) { 5741 if (dec.frac != dec.total) { 5742 int diff = dec.total - dec.frac; 5743 /* 5744 * Insert the decimal point. 5745 */ 5746 memmove(offs + diff + 1, offs + diff, dec.frac +1); 5747 offs[diff] = '.'; 5748 } else { 5749 unsigned int i = 0; 5750 /* 5751 * Insert missing zeroes behind the decimal point. 5752 */ 5753 while (*(offs + i) != 0) 5754 i++; 5755 if (i < dec.total) { 5756 memmove(offs + (dec.total - i), offs, i +1); 5757 memset(offs, '0', dec.total - i); 5758 } 5759 } 5760 } else { 5761 /* 5762 * Append decimal point and zero. 5763 */ 5764 offs = buf + bufsize - 1; 5765 *offs-- = 0; 5766 *offs-- = '0'; 5767 *offs-- = '.'; 5768 } 5769 *retValue = BAD_CAST buf; 5770 } 5771 break; 5772 case XML_SCHEMAS_INTEGER: 5773 case XML_SCHEMAS_PINTEGER: 5774 case XML_SCHEMAS_NPINTEGER: 5775 case XML_SCHEMAS_NINTEGER: 5776 case XML_SCHEMAS_NNINTEGER: 5777 case XML_SCHEMAS_LONG: 5778 case XML_SCHEMAS_BYTE: 5779 case XML_SCHEMAS_SHORT: 5780 case XML_SCHEMAS_INT: 5781 case XML_SCHEMAS_UINT: 5782 case XML_SCHEMAS_ULONG: 5783 case XML_SCHEMAS_USHORT: 5784 case XML_SCHEMAS_UBYTE: 5785 if ((val->value.decimal.total == 1) && 5786 (val->value.decimal.lo == 0)) 5787 *retValue = xmlStrdup(BAD_CAST "0"); 5788 else { 5789 xmlSchemaValDecimal dec = val->value.decimal; 5790 int bufsize = dec.total + 1; 5791 5792 /* Add room for the decimal point as well. */ 5793 if (dec.sign) 5794 bufsize++; 5795 *retValue = xmlMalloc(bufsize); 5796 if (*retValue == NULL) 5797 return(-1); 5798 if (dec.hi != 0) { 5799 if (dec.sign) 5800 snprintf((char *) *retValue, bufsize, 5801 "-%lu%lu%lu", dec.hi, dec.mi, dec.lo); 5802 else 5803 snprintf((char *) *retValue, bufsize, 5804 "%lu%lu%lu", dec.hi, dec.mi, dec.lo); 5805 } else if (dec.mi != 0) { 5806 if (dec.sign) 5807 snprintf((char *) *retValue, bufsize, 5808 "-%lu%lu", dec.mi, dec.lo); 5809 else 5810 snprintf((char *) *retValue, bufsize, 5811 "%lu%lu", dec.mi, dec.lo); 5812 } else { 5813 if (dec.sign) 5814 snprintf((char *) *retValue, bufsize, "-%lu", dec.lo); 5815 else 5816 snprintf((char *) *retValue, bufsize, "%lu", dec.lo); 5817 } 5818 } 5819 break; 5820 case XML_SCHEMAS_BOOLEAN: 5821 if (val->value.b) 5822 *retValue = BAD_CAST xmlStrdup(BAD_CAST "true"); 5823 else 5824 *retValue = BAD_CAST xmlStrdup(BAD_CAST "false"); 5825 break; 5826 case XML_SCHEMAS_DURATION: { 5827 char buf[100]; 5828 unsigned long year; 5829 unsigned long mon, day, hour = 0, min = 0; 5830 double sec = 0, left; 5831 5832 /* TODO: Unclear in XML Schema 1.0 */ 5833 /* 5834 * TODO: This results in a normalized output of the value 5835 * - which is NOT conformant to the spec - 5836 * since the exact values of each property are not 5837 * recoverable. Think about extending the structure to 5838 * provide a field for every property. 5839 */ 5840 year = (unsigned long) FQUOTIENT(labs(val->value.dur.mon), 12); 5841 mon = labs(val->value.dur.mon) - 12 * year; 5842 5843 day = (unsigned long) FQUOTIENT(fabs(val->value.dur.sec), 86400); 5844 left = fabs(val->value.dur.sec) - day * 86400; 5845 if (left > 0) { 5846 hour = (unsigned long) FQUOTIENT(left, 3600); 5847 left = left - (hour * 3600); 5848 if (left > 0) { 5849 min = (unsigned long) FQUOTIENT(left, 60); 5850 sec = left - (min * 60); 5851 } 5852 } 5853 if ((val->value.dur.mon < 0) || (val->value.dur.sec < 0)) 5854 snprintf(buf, 100, "P%luY%luM%luDT%luH%luM%.14gS", 5855 year, mon, day, hour, min, sec); 5856 else 5857 snprintf(buf, 100, "-P%luY%luM%luDT%luH%luM%.14gS", 5858 year, mon, day, hour, min, sec); 5859 *retValue = BAD_CAST xmlStrdup(BAD_CAST buf); 5860 } 5861 break; 5862 case XML_SCHEMAS_GYEAR: { 5863 char buf[30]; 5864 /* TODO: Unclear in XML Schema 1.0 */ 5865 /* TODO: What to do with the timezone? */ 5866 snprintf(buf, 30, "%04ld", val->value.date.year); 5867 *retValue = BAD_CAST xmlStrdup(BAD_CAST buf); 5868 } 5869 break; 5870 case XML_SCHEMAS_GMONTH: { 5871 /* TODO: Unclear in XML Schema 1.0 */ 5872 /* TODO: What to do with the timezone? */ 5873 *retValue = xmlMalloc(6); 5874 if (*retValue == NULL) 5875 return(-1); 5876 snprintf((char *) *retValue, 6, "--%02u", 5877 val->value.date.mon); 5878 } 5879 break; 5880 case XML_SCHEMAS_GDAY: { 5881 /* TODO: Unclear in XML Schema 1.0 */ 5882 /* TODO: What to do with the timezone? */ 5883 *retValue = xmlMalloc(6); 5884 if (*retValue == NULL) 5885 return(-1); 5886 snprintf((char *) *retValue, 6, "---%02u", 5887 val->value.date.day); 5888 } 5889 break; 5890 case XML_SCHEMAS_GMONTHDAY: { 5891 /* TODO: Unclear in XML Schema 1.0 */ 5892 /* TODO: What to do with the timezone? */ 5893 *retValue = xmlMalloc(8); 5894 if (*retValue == NULL) 5895 return(-1); 5896 snprintf((char *) *retValue, 8, "--%02u-%02u", 5897 val->value.date.mon, val->value.date.day); 5898 } 5899 break; 5900 case XML_SCHEMAS_GYEARMONTH: { 5901 char buf[35]; 5902 /* TODO: Unclear in XML Schema 1.0 */ 5903 /* TODO: What to do with the timezone? */ 5904 if (val->value.date.year < 0) 5905 snprintf(buf, 35, "-%04ld-%02u", 5906 labs(val->value.date.year), 5907 val->value.date.mon); 5908 else 5909 snprintf(buf, 35, "%04ld-%02u", 5910 val->value.date.year, val->value.date.mon); 5911 *retValue = BAD_CAST xmlStrdup(BAD_CAST buf); 5912 } 5913 break; 5914 case XML_SCHEMAS_TIME: 5915 { 5916 char buf[30]; 5917 5918 if (val->value.date.tz_flag) { 5919 xmlSchemaValPtr norm; 5920 5921 norm = xmlSchemaDateNormalize(val, 0); 5922 if (norm == NULL) 5923 return (-1); 5924 /* 5925 * TODO: Check if "%.14g" is portable. 5926 */ 5927 snprintf(buf, 30, 5928 "%02u:%02u:%02.14gZ", 5929 norm->value.date.hour, 5930 norm->value.date.min, 5931 norm->value.date.sec); 5932 xmlSchemaFreeValue(norm); 5933 } else { 5934 snprintf(buf, 30, 5935 "%02u:%02u:%02.14g", 5936 val->value.date.hour, 5937 val->value.date.min, 5938 val->value.date.sec); 5939 } 5940 *retValue = BAD_CAST xmlStrdup(BAD_CAST buf); 5941 } 5942 break; 5943 case XML_SCHEMAS_DATE: 5944 { 5945 char buf[30]; 5946 5947 if (val->value.date.tz_flag) { 5948 xmlSchemaValPtr norm; 5949 5950 norm = xmlSchemaDateNormalize(val, 0); 5951 if (norm == NULL) 5952 return (-1); 5953 /* 5954 * TODO: Append the canonical value of the 5955 * recoverable timezone and not "Z". 5956 */ 5957 snprintf(buf, 30, 5958 "%04ld:%02u:%02uZ", 5959 norm->value.date.year, norm->value.date.mon, 5960 norm->value.date.day); 5961 xmlSchemaFreeValue(norm); 5962 } else { 5963 snprintf(buf, 30, 5964 "%04ld:%02u:%02u", 5965 val->value.date.year, val->value.date.mon, 5966 val->value.date.day); 5967 } 5968 *retValue = BAD_CAST xmlStrdup(BAD_CAST buf); 5969 } 5970 break; 5971 case XML_SCHEMAS_DATETIME: 5972 { 5973 char buf[50]; 5974 5975 if (val->value.date.tz_flag) { 5976 xmlSchemaValPtr norm; 5977 5978 norm = xmlSchemaDateNormalize(val, 0); 5979 if (norm == NULL) 5980 return (-1); 5981 /* 5982 * TODO: Check if "%.14g" is portable. 5983 */ 5984 snprintf(buf, 50, 5985 "%04ld:%02u:%02uT%02u:%02u:%02.14gZ", 5986 norm->value.date.year, norm->value.date.mon, 5987 norm->value.date.day, norm->value.date.hour, 5988 norm->value.date.min, norm->value.date.sec); 5989 xmlSchemaFreeValue(norm); 5990 } else { 5991 snprintf(buf, 50, 5992 "%04ld:%02u:%02uT%02u:%02u:%02.14g", 5993 val->value.date.year, val->value.date.mon, 5994 val->value.date.day, val->value.date.hour, 5995 val->value.date.min, val->value.date.sec); 5996 } 5997 *retValue = BAD_CAST xmlStrdup(BAD_CAST buf); 5998 } 5999 break; 6000 case XML_SCHEMAS_HEXBINARY: 6001 *retValue = BAD_CAST xmlStrdup(BAD_CAST val->value.hex.str); 6002 break; 6003 case XML_SCHEMAS_BASE64BINARY: 6004 /* 6005 * TODO: Is the following spec piece implemented?: 6006 * SPEC: "Note: For some values the canonical form defined 6007 * above does not conform to [RFC 2045], which requires breaking 6008 * with linefeeds at appropriate intervals." 6009 */ 6010 *retValue = BAD_CAST xmlStrdup(BAD_CAST val->value.base64.str); 6011 break; 6012 case XML_SCHEMAS_FLOAT: { 6013 char buf[30]; 6014 /* 6015 * |m| < 16777216, -149 <= e <= 104. 6016 * TODO: Handle, NaN, INF, -INF. The format is not 6017 * yet conformant. The c type float does not cover 6018 * the whole range. 6019 */ 6020 snprintf(buf, 30, "%01.14e", val->value.f); 6021 *retValue = BAD_CAST xmlStrdup(BAD_CAST buf); 6022 } 6023 break; 6024 case XML_SCHEMAS_DOUBLE: { 6025 char buf[40]; 6026 /* |m| < 9007199254740992, -1075 <= e <= 970 */ 6027 /* 6028 * TODO: Handle, NaN, INF, -INF. The format is not 6029 * yet conformant. The c type float does not cover 6030 * the whole range. 6031 */ 6032 snprintf(buf, 40, "%01.14e", val->value.d); 6033 *retValue = BAD_CAST xmlStrdup(BAD_CAST buf); 6034 } 6035 break; 6036 default: 6037 *retValue = BAD_CAST xmlStrdup(BAD_CAST "???"); 6038 return (1); 6039 } 6040 if (*retValue == NULL) 6041 return(-1); 6042 return (0); 6043} 6044 6045/** 6046 * xmlSchemaGetCanonValueWhtsp: 6047 * @val: the precomputed value 6048 * @retValue: the returned value 6049 * @ws: the whitespace type of the value 6050 * 6051 * Get a the cononical representation of the value. 6052 * The caller has to free the returned @retValue. 6053 * 6054 * Returns 0 if the value could be built, 1 if the value type is 6055 * not supported yet and -1 in case of API errors. 6056 */ 6057int 6058xmlSchemaGetCanonValueWhtsp(xmlSchemaValPtr val, 6059 const xmlChar **retValue, 6060 xmlSchemaWhitespaceValueType ws) 6061{ 6062 if ((retValue == NULL) || (val == NULL)) 6063 return (-1); 6064 if ((ws == XML_SCHEMA_WHITESPACE_UNKNOWN) || 6065 (ws > XML_SCHEMA_WHITESPACE_COLLAPSE)) 6066 return (-1); 6067 6068 *retValue = NULL; 6069 switch (val->type) { 6070 case XML_SCHEMAS_STRING: 6071 if (val->value.str == NULL) 6072 *retValue = BAD_CAST xmlStrdup(BAD_CAST ""); 6073 else if (ws == XML_SCHEMA_WHITESPACE_COLLAPSE) 6074 *retValue = xmlSchemaCollapseString(val->value.str); 6075 else if (ws == XML_SCHEMA_WHITESPACE_REPLACE) 6076 *retValue = xmlSchemaWhiteSpaceReplace(val->value.str); 6077 if ((*retValue) == NULL) 6078 *retValue = BAD_CAST xmlStrdup(val->value.str); 6079 break; 6080 case XML_SCHEMAS_NORMSTRING: 6081 if (val->value.str == NULL) 6082 *retValue = BAD_CAST xmlStrdup(BAD_CAST ""); 6083 else { 6084 if (ws == XML_SCHEMA_WHITESPACE_COLLAPSE) 6085 *retValue = xmlSchemaCollapseString(val->value.str); 6086 else 6087 *retValue = xmlSchemaWhiteSpaceReplace(val->value.str); 6088 if ((*retValue) == NULL) 6089 *retValue = BAD_CAST xmlStrdup(val->value.str); 6090 } 6091 break; 6092 default: 6093 return (xmlSchemaGetCanonValue(val, retValue)); 6094 } 6095 return (0); 6096} 6097 6098/** 6099 * xmlSchemaGetValType: 6100 * @val: a schemas value 6101 * 6102 * Accessor for the type of a value 6103 * 6104 * Returns the xmlSchemaValType of the value 6105 */ 6106xmlSchemaValType 6107xmlSchemaGetValType(xmlSchemaValPtr val) 6108{ 6109 if (val == NULL) 6110 return(XML_SCHEMAS_UNKNOWN); 6111 return (val->type); 6112} 6113 6114#define bottom_xmlschemastypes 6115#include "elfgcchack.h" 6116#endif /* LIBXML_SCHEMAS_ENABLED */ 6117