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