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