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