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