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