VirtualBox

source: vbox/trunk/src/libs/libxml2-2.12.6/xmlschemastypes.c

Last change on this file was 104180, checked in by vboxsync, 6 weeks ago

libxml2-2.12.6: Make it build for windows. bugref:10640

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

© 2023 Oracle
ContactPrivacy policyTerms of Use