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