summaryrefslogtreecommitdiff
path: root/xmlschemastypes.c
diff options
context:
space:
mode:
Diffstat (limited to 'xmlschemastypes.c')
-rw-r--r--xmlschemastypes.c3597
1 files changed, 3597 insertions, 0 deletions
diff --git a/xmlschemastypes.c b/xmlschemastypes.c
new file mode 100644
index 0000000..91e34b8
--- /dev/null
+++ b/xmlschemastypes.c
@@ -0,0 +1,3597 @@
+/*
+ * schemastypes.c : implementation of the XML Schema Datatypes
+ * definition and validity checking
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel Veillard <veillard@redhat.com>
+ */
+
+#define IN_LIBXML
+#include "libxml.h"
+
+#ifdef LIBXML_SCHEMAS_ENABLED
+
+#include <string.h>
+#include <libxml/xmlmemory.h>
+#include <libxml/parser.h>
+#include <libxml/parserInternals.h>
+#include <libxml/hash.h>
+#include <libxml/valid.h>
+#include <libxml/xpath.h>
+#include <libxml/uri.h>
+
+#include <libxml/xmlschemas.h>
+#include <libxml/schemasInternals.h>
+#include <libxml/xmlschemastypes.h>
+
+#ifdef HAVE_MATH_H
+#include <math.h>
+#endif
+
+#define DEBUG
+
+#define TODO \
+ xmlGenericError(xmlGenericErrorContext, \
+ "Unimplemented block at %s:%d\n", \
+ __FILE__, __LINE__);
+
+#define XML_SCHEMAS_NAMESPACE_NAME \
+ (const xmlChar *)"http://www.w3.org/2001/XMLSchema"
+
+typedef enum {
+ XML_SCHEMAS_UNKNOWN = 0,
+ XML_SCHEMAS_STRING,
+ XML_SCHEMAS_NORMSTRING,
+ XML_SCHEMAS_DECIMAL,
+ XML_SCHEMAS_TIME,
+ XML_SCHEMAS_GDAY,
+ XML_SCHEMAS_GMONTH,
+ XML_SCHEMAS_GMONTHDAY,
+ XML_SCHEMAS_GYEAR,
+ XML_SCHEMAS_GYEARMONTH,
+ XML_SCHEMAS_DATE,
+ XML_SCHEMAS_DATETIME,
+ XML_SCHEMAS_DURATION,
+ XML_SCHEMAS_FLOAT,
+ XML_SCHEMAS_DOUBLE,
+ XML_SCHEMAS_BOOLEAN,
+ XML_SCHEMAS_TOKEN,
+ XML_SCHEMAS_LANGUAGE,
+ XML_SCHEMAS_NMTOKEN,
+ XML_SCHEMAS_NMTOKENS,
+ XML_SCHEMAS_NAME,
+ XML_SCHEMAS_QNAME,
+ XML_SCHEMAS_NCNAME,
+ XML_SCHEMAS_ID,
+ XML_SCHEMAS_IDREF,
+ XML_SCHEMAS_IDREFS,
+ XML_SCHEMAS_ENTITY,
+ XML_SCHEMAS_ENTITIES,
+ XML_SCHEMAS_NOTATION,
+ XML_SCHEMAS_ANYURI,
+ XML_SCHEMAS_INTEGER,
+ XML_SCHEMAS_NPINTEGER,
+ XML_SCHEMAS_NINTEGER,
+ XML_SCHEMAS_NNINTEGER,
+ XML_SCHEMAS_PINTEGER,
+ XML_SCHEMAS_INT,
+ XML_SCHEMAS_UINT,
+ XML_SCHEMAS_LONG,
+ XML_SCHEMAS_ULONG,
+ XML_SCHEMAS_SHORT,
+ XML_SCHEMAS_USHORT,
+ XML_SCHEMAS_BYTE,
+ XML_SCHEMAS_UBYTE,
+ XML_SCHEMAS_HEXBINARY,
+ XML_SCHEMAS_BASE64BINARY
+} xmlSchemaValType;
+
+static unsigned long powten[10] = {
+ 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000L,
+ 100000000L, 1000000000L
+};
+
+/* Date value */
+typedef struct _xmlSchemaValDate xmlSchemaValDate;
+typedef xmlSchemaValDate *xmlSchemaValDatePtr;
+struct _xmlSchemaValDate {
+ long year;
+ unsigned int mon :4; /* 1 <= mon <= 12 */
+ unsigned int day :5; /* 1 <= day <= 31 */
+ unsigned int hour :5; /* 0 <= hour <= 23 */
+ unsigned int min :6; /* 0 <= min <= 59 */
+ double sec;
+ unsigned int tz_flag :1; /* is tzo explicitely set? */
+ int tzo :11; /* -1440 <= tzo <= 1440 */
+};
+
+/* Duration value */
+typedef struct _xmlSchemaValDuration xmlSchemaValDuration;
+typedef xmlSchemaValDuration *xmlSchemaValDurationPtr;
+struct _xmlSchemaValDuration {
+ long mon; /* mon stores years also */
+ long day;
+ double sec; /* sec stores min and hour also */
+};
+
+typedef struct _xmlSchemaValDecimal xmlSchemaValDecimal;
+typedef xmlSchemaValDecimal *xmlSchemaValDecimalPtr;
+struct _xmlSchemaValDecimal {
+ /* would use long long but not portable */
+ unsigned long lo;
+ unsigned long mi;
+ unsigned long hi;
+ unsigned int extra;
+ unsigned int sign:1;
+ unsigned int frac:7;
+ unsigned int total:8;
+};
+
+typedef struct _xmlSchemaValQName xmlSchemaValQName;
+typedef xmlSchemaValQName *xmlSchemaValQNamePtr;
+struct _xmlSchemaValQName {
+ xmlChar *name;
+ xmlChar *uri;
+};
+
+typedef struct _xmlSchemaValHex xmlSchemaValHex;
+typedef xmlSchemaValHex *xmlSchemaValHexPtr;
+struct _xmlSchemaValHex {
+ xmlChar *str;
+ unsigned int total;
+};
+
+typedef struct _xmlSchemaValBase64 xmlSchemaValBase64;
+typedef xmlSchemaValBase64 *xmlSchemaValBase64Ptr;
+struct _xmlSchemaValBase64 {
+ xmlChar *str;
+ unsigned int total;
+};
+
+struct _xmlSchemaVal {
+ xmlSchemaValType type;
+ union {
+ xmlSchemaValDecimal decimal;
+ xmlSchemaValDate date;
+ xmlSchemaValDuration dur;
+ xmlSchemaValQName qname;
+ xmlSchemaValHex hex;
+ xmlSchemaValBase64 base64;
+ float f;
+ double d;
+ int b;
+ xmlChar *str;
+ } value;
+};
+
+static int xmlSchemaTypesInitialized = 0;
+static xmlHashTablePtr xmlSchemaTypesBank = NULL;
+
+/*
+ * Basic types
+ */
+static xmlSchemaTypePtr xmlSchemaTypeStringDef = NULL;
+static xmlSchemaTypePtr xmlSchemaTypeAnyTypeDef = NULL;
+static xmlSchemaTypePtr xmlSchemaTypeAnySimpleTypeDef = NULL;
+static xmlSchemaTypePtr xmlSchemaTypeDecimalDef = NULL;
+static xmlSchemaTypePtr xmlSchemaTypeDatetimeDef = NULL;
+static xmlSchemaTypePtr xmlSchemaTypeDateDef = NULL;
+static xmlSchemaTypePtr xmlSchemaTypeTimeDef = NULL;
+static xmlSchemaTypePtr xmlSchemaTypeGYearDef = NULL;
+static xmlSchemaTypePtr xmlSchemaTypeGYearMonthDef = NULL;
+static xmlSchemaTypePtr xmlSchemaTypeGDayDef = NULL;
+static xmlSchemaTypePtr xmlSchemaTypeGMonthDayDef = NULL;
+static xmlSchemaTypePtr xmlSchemaTypeGMonthDef = NULL;
+static xmlSchemaTypePtr xmlSchemaTypeDurationDef = NULL;
+static xmlSchemaTypePtr xmlSchemaTypeFloatDef = NULL;
+static xmlSchemaTypePtr xmlSchemaTypeBooleanDef = NULL;
+static xmlSchemaTypePtr xmlSchemaTypeDoubleDef = NULL;
+static xmlSchemaTypePtr xmlSchemaTypeHexBinaryDef = NULL;
+static xmlSchemaTypePtr xmlSchemaTypeBase64BinaryDef = NULL;
+static xmlSchemaTypePtr xmlSchemaTypeAnyURIDef = NULL;
+
+/*
+ * Derived types
+ */
+static xmlSchemaTypePtr xmlSchemaTypePositiveIntegerDef = NULL;
+static xmlSchemaTypePtr xmlSchemaTypeNonPositiveIntegerDef = NULL;
+static xmlSchemaTypePtr xmlSchemaTypeNegativeIntegerDef = NULL;
+static xmlSchemaTypePtr xmlSchemaTypeNonNegativeIntegerDef = NULL;
+static xmlSchemaTypePtr xmlSchemaTypeIntegerDef = NULL;
+static xmlSchemaTypePtr xmlSchemaTypeLongDef = NULL;
+static xmlSchemaTypePtr xmlSchemaTypeIntDef = NULL;
+static xmlSchemaTypePtr xmlSchemaTypeShortDef = NULL;
+static xmlSchemaTypePtr xmlSchemaTypeByteDef = NULL;
+static xmlSchemaTypePtr xmlSchemaTypeUnsignedLongDef = NULL;
+static xmlSchemaTypePtr xmlSchemaTypeUnsignedIntDef = NULL;
+static xmlSchemaTypePtr xmlSchemaTypeUnsignedShortDef = NULL;
+static xmlSchemaTypePtr xmlSchemaTypeUnsignedByteDef = NULL;
+static xmlSchemaTypePtr xmlSchemaTypeNormStringDef = NULL;
+static xmlSchemaTypePtr xmlSchemaTypeTokenDef = NULL;
+static xmlSchemaTypePtr xmlSchemaTypeLanguageDef = NULL;
+static xmlSchemaTypePtr xmlSchemaTypeNameDef = NULL;
+static xmlSchemaTypePtr xmlSchemaTypeQNameDef = NULL;
+static xmlSchemaTypePtr xmlSchemaTypeNCNameDef = NULL;
+static xmlSchemaTypePtr xmlSchemaTypeIdDef = NULL;
+static xmlSchemaTypePtr xmlSchemaTypeIdrefDef = NULL;
+static xmlSchemaTypePtr xmlSchemaTypeIdrefsDef = NULL;
+static xmlSchemaTypePtr xmlSchemaTypeEntityDef = NULL;
+static xmlSchemaTypePtr xmlSchemaTypeEntitiesDef = NULL;
+static xmlSchemaTypePtr xmlSchemaTypeNotationDef = NULL;
+static xmlSchemaTypePtr xmlSchemaTypeNmtokenDef = NULL;
+static xmlSchemaTypePtr xmlSchemaTypeNmtokensDef = NULL;
+
+/************************************************************************
+ * *
+ * Datatype error handlers *
+ * *
+ ************************************************************************/
+/**
+ * xmlSchemaTypeErrMemory:
+ * @extra: extra informations
+ *
+ * Handle an out of memory condition
+ */
+static void
+xmlSchemaTypeErrMemory(xmlNodePtr node, const char *extra)
+{
+ __xmlSimpleError(XML_FROM_DATATYPE, XML_ERR_NO_MEMORY, node, NULL, extra);
+}
+
+/************************************************************************
+ * *
+ * Base types support *
+ * *
+ ************************************************************************/
+/*
+ * xmlSchemaInitBasicType:
+ * @name: the type name
+ * @type: the value type associated
+ *
+ * Initialize one default type
+ */
+static xmlSchemaTypePtr
+xmlSchemaInitBasicType(const char *name, xmlSchemaValType type) {
+ xmlSchemaTypePtr ret;
+
+ ret = (xmlSchemaTypePtr) xmlMalloc(sizeof(xmlSchemaType));
+ if (ret == NULL) {
+ xmlSchemaTypeErrMemory(NULL, "could not initialize basic types");
+ return(NULL);
+ }
+ memset(ret, 0, sizeof(xmlSchemaType));
+ ret->name = (const xmlChar *)name;
+ ret->type = XML_SCHEMA_TYPE_BASIC;
+ ret->flags = type;
+ ret->contentType = XML_SCHEMA_CONTENT_BASIC;
+ xmlHashAddEntry2(xmlSchemaTypesBank, ret->name,
+ XML_SCHEMAS_NAMESPACE_NAME, ret);
+ return(ret);
+}
+
+/*
+ * xmlSchemaInitTypes:
+ *
+ * Initialize the default XML Schemas type library
+ */
+void
+xmlSchemaInitTypes(void)
+{
+ if (xmlSchemaTypesInitialized != 0)
+ return;
+ xmlSchemaTypesBank = xmlHashCreate(40);
+
+ /*
+ * primitive datatypes
+ */
+ xmlSchemaTypeStringDef = xmlSchemaInitBasicType("string",
+ XML_SCHEMAS_STRING);
+ xmlSchemaTypeAnyTypeDef = xmlSchemaInitBasicType("anyType",
+ XML_SCHEMAS_UNKNOWN);
+ xmlSchemaTypeAnySimpleTypeDef = xmlSchemaInitBasicType("anySimpleType",
+ XML_SCHEMAS_UNKNOWN);
+ xmlSchemaTypeDecimalDef = xmlSchemaInitBasicType("decimal",
+ XML_SCHEMAS_DECIMAL);
+ xmlSchemaTypeDateDef = xmlSchemaInitBasicType("date",
+ XML_SCHEMAS_DATE);
+ xmlSchemaTypeDatetimeDef = xmlSchemaInitBasicType("dateTime",
+ XML_SCHEMAS_DATETIME);
+ xmlSchemaTypeTimeDef = xmlSchemaInitBasicType("time",
+ XML_SCHEMAS_TIME);
+ xmlSchemaTypeGYearDef = xmlSchemaInitBasicType("gYear",
+ XML_SCHEMAS_GYEAR);
+ xmlSchemaTypeGYearMonthDef = xmlSchemaInitBasicType("gYearMonth",
+ XML_SCHEMAS_GYEARMONTH);
+ xmlSchemaTypeGMonthDef = xmlSchemaInitBasicType("gMonth",
+ XML_SCHEMAS_GMONTH);
+ xmlSchemaTypeGMonthDayDef = xmlSchemaInitBasicType("gMonthDay",
+ XML_SCHEMAS_GMONTHDAY);
+ xmlSchemaTypeGDayDef = xmlSchemaInitBasicType("gDay",
+ XML_SCHEMAS_GDAY);
+ xmlSchemaTypeDurationDef = xmlSchemaInitBasicType("duration",
+ XML_SCHEMAS_DURATION);
+ xmlSchemaTypeFloatDef = xmlSchemaInitBasicType("float",
+ XML_SCHEMAS_FLOAT);
+ xmlSchemaTypeDoubleDef = xmlSchemaInitBasicType("double",
+ XML_SCHEMAS_DOUBLE);
+ xmlSchemaTypeBooleanDef = xmlSchemaInitBasicType("boolean",
+ XML_SCHEMAS_BOOLEAN);
+ xmlSchemaTypeAnyURIDef = xmlSchemaInitBasicType("anyURI",
+ XML_SCHEMAS_ANYURI);
+ xmlSchemaTypeHexBinaryDef = xmlSchemaInitBasicType("hexBinary",
+ XML_SCHEMAS_HEXBINARY);
+ xmlSchemaTypeBase64BinaryDef
+ = xmlSchemaInitBasicType("base64Binary", XML_SCHEMAS_BASE64BINARY);
+
+ /*
+ * derived datatypes
+ */
+ xmlSchemaTypeIntegerDef = xmlSchemaInitBasicType("integer",
+ XML_SCHEMAS_INTEGER);;
+ xmlSchemaTypeNonPositiveIntegerDef =
+ xmlSchemaInitBasicType("nonPositiveInteger",
+ XML_SCHEMAS_NPINTEGER);;
+ xmlSchemaTypeNegativeIntegerDef =
+ xmlSchemaInitBasicType("negativeInteger", XML_SCHEMAS_NINTEGER);;
+ xmlSchemaTypeLongDef =
+ xmlSchemaInitBasicType("long", XML_SCHEMAS_LONG);;
+ xmlSchemaTypeIntDef = xmlSchemaInitBasicType("int", XML_SCHEMAS_INT);;
+ xmlSchemaTypeShortDef = xmlSchemaInitBasicType("short",
+ XML_SCHEMAS_SHORT);;
+ xmlSchemaTypeByteDef = xmlSchemaInitBasicType("byte",
+ XML_SCHEMAS_BYTE);;
+ xmlSchemaTypeNonNegativeIntegerDef =
+ xmlSchemaInitBasicType("nonNegativeInteger",
+ XML_SCHEMAS_NNINTEGER);
+ xmlSchemaTypeUnsignedLongDef =
+ xmlSchemaInitBasicType("unsignedLong", XML_SCHEMAS_ULONG);;
+ xmlSchemaTypeUnsignedIntDef =
+ xmlSchemaInitBasicType("unsignedInt", XML_SCHEMAS_UINT);;
+ xmlSchemaTypeUnsignedShortDef =
+ xmlSchemaInitBasicType("unsignedShort", XML_SCHEMAS_USHORT);;
+ xmlSchemaTypeUnsignedByteDef =
+ xmlSchemaInitBasicType("unsignedByte", XML_SCHEMAS_UBYTE);;
+ xmlSchemaTypePositiveIntegerDef =
+ xmlSchemaInitBasicType("positiveInteger", XML_SCHEMAS_PINTEGER);
+
+ xmlSchemaTypeNormStringDef = xmlSchemaInitBasicType("normalizedString",
+ XML_SCHEMAS_NORMSTRING);
+ xmlSchemaTypeTokenDef = xmlSchemaInitBasicType("token",
+ XML_SCHEMAS_TOKEN);
+ xmlSchemaTypeLanguageDef = xmlSchemaInitBasicType("language",
+ XML_SCHEMAS_LANGUAGE);
+ xmlSchemaTypeIdDef = xmlSchemaInitBasicType("ID", XML_SCHEMAS_ID);
+ xmlSchemaTypeIdrefDef = xmlSchemaInitBasicType("IDREF",
+ XML_SCHEMAS_IDREF);
+ xmlSchemaTypeIdrefsDef = xmlSchemaInitBasicType("IDREFS",
+ XML_SCHEMAS_IDREFS);
+ xmlSchemaTypeEntityDef = xmlSchemaInitBasicType("ENTITY",
+ XML_SCHEMAS_ENTITY);
+ xmlSchemaTypeEntitiesDef = xmlSchemaInitBasicType("ENTITIES",
+ XML_SCHEMAS_ENTITIES);
+ xmlSchemaTypeNotationDef = xmlSchemaInitBasicType("NOTATION",
+ XML_SCHEMAS_NOTATION);
+ xmlSchemaTypeNameDef = xmlSchemaInitBasicType("Name",
+ XML_SCHEMAS_NAME);
+ xmlSchemaTypeQNameDef = xmlSchemaInitBasicType("QName",
+ XML_SCHEMAS_QNAME);
+ xmlSchemaTypeNCNameDef = xmlSchemaInitBasicType("NCName",
+ XML_SCHEMAS_NCNAME);
+ xmlSchemaTypeNmtokenDef = xmlSchemaInitBasicType("NMTOKEN",
+ XML_SCHEMAS_NMTOKEN);
+ xmlSchemaTypeNmtokensDef = xmlSchemaInitBasicType("NMTOKENS",
+ XML_SCHEMAS_NMTOKENS);
+ xmlSchemaTypesInitialized = 1;
+}
+
+/**
+ * xmlSchemaCleanupTypes:
+ *
+ * Cleanup the default XML Schemas type library
+ */
+void
+xmlSchemaCleanupTypes(void) {
+ if (xmlSchemaTypesInitialized == 0)
+ return;
+ xmlHashFree(xmlSchemaTypesBank, (xmlHashDeallocator) xmlSchemaFreeType);
+ xmlSchemaTypesInitialized = 0;
+}
+
+/**
+ * xmlSchemaNewValue:
+ * @type: the value type
+ *
+ * Allocate a new simple type value
+ *
+ * Returns a pointer to the new value or NULL in case of error
+ */
+static xmlSchemaValPtr
+xmlSchemaNewValue(xmlSchemaValType type) {
+ xmlSchemaValPtr value;
+
+ value = (xmlSchemaValPtr) xmlMalloc(sizeof(xmlSchemaVal));
+ if (value == NULL) {
+ return(NULL);
+ }
+ memset(value, 0, sizeof(xmlSchemaVal));
+ value->type = type;
+ return(value);
+}
+
+/**
+ * xmlSchemaFreeValue:
+ * @value: the value to free
+ *
+ * Cleanup the default XML Schemas type library
+ */
+void
+xmlSchemaFreeValue(xmlSchemaValPtr value) {
+ if (value == NULL)
+ return;
+ switch (value->type) {
+ case XML_SCHEMAS_STRING:
+ case XML_SCHEMAS_NORMSTRING:
+ case XML_SCHEMAS_TOKEN:
+ case XML_SCHEMAS_LANGUAGE:
+ case XML_SCHEMAS_NMTOKEN:
+ case XML_SCHEMAS_NMTOKENS:
+ case XML_SCHEMAS_NAME:
+ case XML_SCHEMAS_NCNAME:
+ case XML_SCHEMAS_ID:
+ case XML_SCHEMAS_IDREF:
+ case XML_SCHEMAS_IDREFS:
+ case XML_SCHEMAS_ENTITY:
+ case XML_SCHEMAS_ENTITIES:
+ case XML_SCHEMAS_NOTATION:
+ case XML_SCHEMAS_ANYURI:
+ if (value->value.str != NULL)
+ xmlFree(value->value.str);
+ break;
+ case XML_SCHEMAS_QNAME:
+ if (value->value.qname.uri != NULL)
+ xmlFree(value->value.qname.uri);
+ if (value->value.qname.name != NULL)
+ xmlFree(value->value.qname.name);
+ break;
+ case XML_SCHEMAS_HEXBINARY:
+ if (value->value.hex.str != NULL)
+ xmlFree(value->value.hex.str);
+ break;
+ case XML_SCHEMAS_BASE64BINARY:
+ if (value->value.base64.str != NULL)
+ xmlFree(value->value.base64.str);
+ break;
+ default:
+ break;
+ }
+ xmlFree(value);
+}
+
+/**
+ * xmlSchemaGetPredefinedType:
+ * @name: the type name
+ * @ns: the URI of the namespace usually "http://www.w3.org/2001/XMLSchema"
+ *
+ * Lookup a type in the default XML Schemas type library
+ *
+ * Returns the type if found, NULL otherwise
+ */
+xmlSchemaTypePtr
+xmlSchemaGetPredefinedType(const xmlChar *name, const xmlChar *ns) {
+ if (xmlSchemaTypesInitialized == 0)
+ xmlSchemaInitTypes();
+ if (name == NULL)
+ return(NULL);
+ return((xmlSchemaTypePtr) xmlHashLookup2(xmlSchemaTypesBank, name, ns));
+}
+
+/****************************************************************
+ * *
+ * Convenience macros and functions *
+ * *
+ ****************************************************************/
+
+#define IS_TZO_CHAR(c) \
+ ((c == 0) || (c == 'Z') || (c == '+') || (c == '-'))
+
+#define VALID_YEAR(yr) (yr != 0)
+#define VALID_MONTH(mon) ((mon >= 1) && (mon <= 12))
+/* VALID_DAY should only be used when month is unknown */
+#define VALID_DAY(day) ((day >= 1) && (day <= 31))
+#define VALID_HOUR(hr) ((hr >= 0) && (hr <= 23))
+#define VALID_MIN(min) ((min >= 0) && (min <= 59))
+#define VALID_SEC(sec) ((sec >= 0) && (sec < 60))
+#define VALID_TZO(tzo) ((tzo > -1440) && (tzo < 1440))
+#define IS_LEAP(y) \
+ (((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0))
+
+static const long daysInMonth[12] =
+ { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+static const long daysInMonthLeap[12] =
+ { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+
+#define MAX_DAYINMONTH(yr,mon) \
+ (IS_LEAP(yr) ? daysInMonthLeap[mon - 1] : daysInMonth[mon - 1])
+
+#define VALID_MDAY(dt) \
+ (IS_LEAP(dt->year) ? \
+ (dt->day <= daysInMonthLeap[dt->mon - 1]) : \
+ (dt->day <= daysInMonth[dt->mon - 1]))
+
+#define VALID_DATE(dt) \
+ (VALID_YEAR(dt->year) && VALID_MONTH(dt->mon) && VALID_MDAY(dt))
+
+#define VALID_TIME(dt) \
+ (VALID_HOUR(dt->hour) && VALID_MIN(dt->min) && \
+ VALID_SEC(dt->sec) && VALID_TZO(dt->tzo))
+
+#define VALID_DATETIME(dt) \
+ (VALID_DATE(dt) && VALID_TIME(dt))
+
+#define SECS_PER_MIN (60)
+#define SECS_PER_HOUR (60 * SECS_PER_MIN)
+#define SECS_PER_DAY (24 * SECS_PER_HOUR)
+
+static const long dayInYearByMonth[12] =
+ { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
+static const long dayInLeapYearByMonth[12] =
+ { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 };
+
+#define DAY_IN_YEAR(day, month, year) \
+ ((IS_LEAP(year) ? \
+ dayInLeapYearByMonth[month - 1] : \
+ dayInYearByMonth[month - 1]) + day)
+
+#ifdef DEBUG
+#define DEBUG_DATE(dt) \
+ xmlGenericError(xmlGenericErrorContext, \
+ "type=%o %04ld-%02u-%02uT%02u:%02u:%03f", \
+ dt->type,dt->value.date.year,dt->value.date.mon, \
+ dt->value.date.day,dt->value.date.hour,dt->value.date.min, \
+ dt->value.date.sec); \
+ if (dt->value.date.tz_flag) \
+ if (dt->value.date.tzo != 0) \
+ xmlGenericError(xmlGenericErrorContext, \
+ "%+05d\n",dt->value.date.tzo); \
+ else \
+ xmlGenericError(xmlGenericErrorContext, "Z\n"); \
+ else \
+ xmlGenericError(xmlGenericErrorContext,"\n")
+#else
+#define DEBUG_DATE(dt)
+#endif
+
+/**
+ * _xmlSchemaParseGYear:
+ * @dt: pointer to a date structure
+ * @str: pointer to the string to analyze
+ *
+ * Parses a xs:gYear without time zone and fills in the appropriate
+ * field of the @dt structure. @str is updated to point just after the
+ * xs:gYear. It is supposed that @dt->year is big enough to contain
+ * the year.
+ *
+ * Returns 0 or the error code
+ */
+static int
+_xmlSchemaParseGYear (xmlSchemaValDatePtr dt, const xmlChar **str) {
+ const xmlChar *cur = *str, *firstChar;
+ int isneg = 0, digcnt = 0;
+
+ if (((*cur < '0') || (*cur > '9')) &&
+ (*cur != '-') && (*cur != '+'))
+ return -1;
+
+ if (*cur == '-') {
+ isneg = 1;
+ cur++;
+ }
+
+ firstChar = cur;
+
+ while ((*cur >= '0') && (*cur <= '9')) {
+ dt->year = dt->year * 10 + (*cur - '0');
+ cur++;
+ digcnt++;
+ }
+
+ /* year must be at least 4 digits (CCYY); over 4
+ * digits cannot have a leading zero. */
+ if ((digcnt < 4) || ((digcnt > 4) && (*firstChar == '0')))
+ return 1;
+
+ if (isneg)
+ dt->year = - dt->year;
+
+ if (!VALID_YEAR(dt->year))
+ return 2;
+
+ *str = cur;
+ return 0;
+}
+
+/**
+ * PARSE_2_DIGITS:
+ * @num: the integer to fill in
+ * @cur: an #xmlChar *
+ * @invalid: an integer
+ *
+ * Parses a 2-digits integer and updates @num with the value. @cur is
+ * updated to point just after the integer.
+ * In case of error, @invalid is set to %TRUE, values of @num and
+ * @cur are undefined.
+ */
+#define PARSE_2_DIGITS(num, cur, invalid) \
+ if ((cur[0] < '0') || (cur[0] > '9') || \
+ (cur[1] < '0') || (cur[1] > '9')) \
+ invalid = 1; \
+ else \
+ num = (cur[0] - '0') * 10 + (cur[1] - '0'); \
+ cur += 2;
+
+/**
+ * PARSE_FLOAT:
+ * @num: the double to fill in
+ * @cur: an #xmlChar *
+ * @invalid: an integer
+ *
+ * Parses a float and updates @num with the value. @cur is
+ * updated to point just after the float. The float must have a
+ * 2-digits integer part and may or may not have a decimal part.
+ * In case of error, @invalid is set to %TRUE, values of @num and
+ * @cur are undefined.
+ */
+#define PARSE_FLOAT(num, cur, invalid) \
+ PARSE_2_DIGITS(num, cur, invalid); \
+ if (!invalid && (*cur == '.')) { \
+ double mult = 1; \
+ cur++; \
+ if ((*cur < '0') || (*cur > '9')) \
+ invalid = 1; \
+ while ((*cur >= '0') && (*cur <= '9')) { \
+ mult /= 10; \
+ num += (*cur - '0') * mult; \
+ cur++; \
+ } \
+ }
+
+/**
+ * _xmlSchemaParseGMonth:
+ * @dt: pointer to a date structure
+ * @str: pointer to the string to analyze
+ *
+ * Parses a xs:gMonth without time zone and fills in the appropriate
+ * field of the @dt structure. @str is updated to point just after the
+ * xs:gMonth.
+ *
+ * Returns 0 or the error code
+ */
+static int
+_xmlSchemaParseGMonth (xmlSchemaValDatePtr dt, const xmlChar **str) {
+ const xmlChar *cur = *str;
+ int ret = 0;
+
+ PARSE_2_DIGITS(dt->mon, cur, ret);
+ if (ret != 0)
+ return ret;
+
+ if (!VALID_MONTH(dt->mon))
+ return 2;
+
+ *str = cur;
+ return 0;
+}
+
+/**
+ * _xmlSchemaParseGDay:
+ * @dt: pointer to a date structure
+ * @str: pointer to the string to analyze
+ *
+ * Parses a xs:gDay without time zone and fills in the appropriate
+ * field of the @dt structure. @str is updated to point just after the
+ * xs:gDay.
+ *
+ * Returns 0 or the error code
+ */
+static int
+_xmlSchemaParseGDay (xmlSchemaValDatePtr dt, const xmlChar **str) {
+ const xmlChar *cur = *str;
+ int ret = 0;
+
+ PARSE_2_DIGITS(dt->day, cur, ret);
+ if (ret != 0)
+ return ret;
+
+ if (!VALID_DAY(dt->day))
+ return 2;
+
+ *str = cur;
+ return 0;
+}
+
+/**
+ * _xmlSchemaParseTime:
+ * @dt: pointer to a date structure
+ * @str: pointer to the string to analyze
+ *
+ * Parses a xs:time without time zone and fills in the appropriate
+ * fields of the @dt structure. @str is updated to point just after the
+ * xs:time.
+ * In case of error, values of @dt fields are undefined.
+ *
+ * Returns 0 or the error code
+ */
+static int
+_xmlSchemaParseTime (xmlSchemaValDatePtr dt, const xmlChar **str) {
+ const xmlChar *cur = *str;
+ unsigned int hour = 0; /* use temp var in case str is not xs:time */
+ int ret = 0;
+
+ PARSE_2_DIGITS(hour, cur, ret);
+ if (ret != 0)
+ return ret;
+
+ if (*cur != ':')
+ return 1;
+ cur++;
+
+ /* the ':' insures this string is xs:time */
+ dt->hour = hour;
+
+ PARSE_2_DIGITS(dt->min, cur, ret);
+ if (ret != 0)
+ return ret;
+
+ if (*cur != ':')
+ return 1;
+ cur++;
+
+ PARSE_FLOAT(dt->sec, cur, ret);
+ if (ret != 0)
+ return ret;
+
+ if (!VALID_TIME(dt))
+ return 2;
+
+ *str = cur;
+ return 0;
+}
+
+/**
+ * _xmlSchemaParseTimeZone:
+ * @dt: pointer to a date structure
+ * @str: pointer to the string to analyze
+ *
+ * Parses a time zone without time zone and fills in the appropriate
+ * field of the @dt structure. @str is updated to point just after the
+ * time zone.
+ *
+ * Returns 0 or the error code
+ */
+static int
+_xmlSchemaParseTimeZone (xmlSchemaValDatePtr dt, const xmlChar **str) {
+ const xmlChar *cur = *str;
+ int ret = 0;
+
+ if (str == NULL)
+ return -1;
+
+ switch (*cur) {
+ case 0:
+ dt->tz_flag = 0;
+ dt->tzo = 0;
+ break;
+
+ case 'Z':
+ dt->tz_flag = 1;
+ dt->tzo = 0;
+ cur++;
+ break;
+
+ case '+':
+ case '-': {
+ int isneg = 0, tmp = 0;
+ isneg = (*cur == '-');
+
+ cur++;
+
+ PARSE_2_DIGITS(tmp, cur, ret);
+ if (ret != 0)
+ return ret;
+ if (!VALID_HOUR(tmp))
+ return 2;
+
+ if (*cur != ':')
+ return 1;
+ cur++;
+
+ dt->tzo = tmp * 60;
+
+ PARSE_2_DIGITS(tmp, cur, ret);
+ if (ret != 0)
+ return ret;
+ if (!VALID_MIN(tmp))
+ return 2;
+
+ dt->tzo += tmp;
+ if (isneg)
+ dt->tzo = - dt->tzo;
+
+ if (!VALID_TZO(dt->tzo))
+ return 2;
+
+ dt->tz_flag = 1;
+ break;
+ }
+ default:
+ return 1;
+ }
+
+ *str = cur;
+ return 0;
+}
+
+/**
+ * _xmlSchemaBase64Decode:
+ * @ch: a character
+ *
+ * Converts a base64 encoded character to its base 64 value.
+ *
+ * Returns 0-63 (value), 64 (pad), or -1 (not recognized)
+ */
+static int
+_xmlSchemaBase64Decode (const xmlChar ch) {
+ if (('A' <= ch) && (ch <= 'Z')) return ch - 'A';
+ if (('a' <= ch) && (ch <= 'z')) return ch - 'a' + 26;
+ if (('0' <= ch) && (ch <= '9')) return ch - '0' + 52;
+ if ('+' == ch) return 62;
+ if ('/' == ch) return 63;
+ if ('=' == ch) return 64;
+ return -1;
+}
+
+/****************************************************************
+ * *
+ * XML Schema Dates/Times Datatypes Handling *
+ * *
+ ****************************************************************/
+
+/**
+ * PARSE_DIGITS:
+ * @num: the integer to fill in
+ * @cur: an #xmlChar *
+ * @num_type: an integer flag
+ *
+ * Parses a digits integer and updates @num with the value. @cur is
+ * updated to point just after the integer.
+ * In case of error, @num_type is set to -1, values of @num and
+ * @cur are undefined.
+ */
+#define PARSE_DIGITS(num, cur, num_type) \
+ if ((*cur < '0') || (*cur > '9')) \
+ num_type = -1; \
+ else \
+ while ((*cur >= '0') && (*cur <= '9')) { \
+ num = num * 10 + (*cur - '0'); \
+ cur++; \
+ }
+
+/**
+ * PARSE_NUM:
+ * @num: the double to fill in
+ * @cur: an #xmlChar *
+ * @num_type: an integer flag
+ *
+ * Parses a float or integer and updates @num with the value. @cur is
+ * updated to point just after the number. If the number is a float,
+ * then it must have an integer part and a decimal part; @num_type will
+ * be set to 1. If there is no decimal part, @num_type is set to zero.
+ * In case of error, @num_type is set to -1, values of @num and
+ * @cur are undefined.
+ */
+#define PARSE_NUM(num, cur, num_type) \
+ num = 0; \
+ PARSE_DIGITS(num, cur, num_type); \
+ if (!num_type && (*cur == '.')) { \
+ double mult = 1; \
+ cur++; \
+ if ((*cur < '0') || (*cur > '9')) \
+ num_type = -1; \
+ else \
+ num_type = 1; \
+ while ((*cur >= '0') && (*cur <= '9')) { \
+ mult /= 10; \
+ num += (*cur - '0') * mult; \
+ cur++; \
+ } \
+ }
+
+/**
+ * xmlSchemaValidateDates:
+ * @type: the expected type or XML_SCHEMAS_UNKNOWN
+ * @dateTime: string to analyze
+ * @val: the return computed value
+ *
+ * Check that @dateTime conforms to the lexical space of one of the date types.
+ * if true a value is computed and returned in @val.
+ *
+ * Returns 0 if this validates, a positive error code number otherwise
+ * and -1 in case of internal or API error.
+ */
+static int
+xmlSchemaValidateDates (xmlSchemaValType type,
+ const xmlChar *dateTime, xmlSchemaValPtr *val) {
+ xmlSchemaValPtr dt;
+ int ret;
+ const xmlChar *cur = dateTime;
+
+#define RETURN_TYPE_IF_VALID(t) \
+ if (IS_TZO_CHAR(*cur)) { \
+ ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur); \
+ if (ret == 0) { \
+ if (*cur != 0) \
+ goto error; \
+ dt->type = t; \
+ goto done; \
+ } \
+ }
+
+ if (dateTime == NULL)
+ return -1;
+
+ if ((*cur != '-') && (*cur < '0') && (*cur > '9'))
+ return 1;
+
+ dt = xmlSchemaNewValue(XML_SCHEMAS_UNKNOWN);
+ if (dt == NULL)
+ return -1;
+
+ if ((cur[0] == '-') && (cur[1] == '-')) {
+ /*
+ * It's an incomplete date (xs:gMonthDay, xs:gMonth or
+ * xs:gDay)
+ */
+ cur += 2;
+
+ /* is it an xs:gDay? */
+ if (*cur == '-') {
+ if (type == XML_SCHEMAS_GMONTH)
+ goto error;
+ ++cur;
+ ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
+ if (ret != 0)
+ goto error;
+
+ RETURN_TYPE_IF_VALID(XML_SCHEMAS_GDAY);
+
+ goto error;
+ }
+
+ /*
+ * it should be an xs:gMonthDay or xs:gMonth
+ */
+ ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
+ if (ret != 0)
+ goto error;
+
+ /*
+ * a '-' char could indicate this type is xs:gMonthDay or
+ * a negative time zone offset. Check for xs:gMonthDay first.
+ * Also the first three char's of a negative tzo (-MM:SS) can
+ * appear to be a valid day; so even if the day portion
+ * of the xs:gMonthDay verifies, we must insure it was not
+ * a tzo.
+ */
+ if (*cur == '-') {
+ const xmlChar *rewnd = cur;
+ cur++;
+
+ ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
+ if ((ret == 0) && ((*cur == 0) || (*cur != ':'))) {
+
+ /*
+ * we can use the VALID_MDAY macro to validate the month
+ * and day because the leap year test will flag year zero
+ * as a leap year (even though zero is an invalid year).
+ */
+ if (VALID_MDAY((&(dt->value.date)))) {
+
+ RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTHDAY);
+
+ goto error;
+ }
+ }
+
+ /*
+ * not xs:gMonthDay so rewind and check if just xs:gMonth
+ * with an optional time zone.
+ */
+ cur = rewnd;
+ }
+
+ RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTH);
+
+ goto error;
+ }
+
+ /*
+ * It's a right-truncated date or an xs:time.
+ * Try to parse an xs:time then fallback on right-truncated dates.
+ */
+ if ((*cur >= '0') && (*cur <= '9')) {
+ ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
+ if (ret == 0) {
+ /* it's an xs:time */
+ RETURN_TYPE_IF_VALID(XML_SCHEMAS_TIME);
+ }
+ }
+
+ /* fallback on date parsing */
+ cur = dateTime;
+
+ ret = _xmlSchemaParseGYear(&(dt->value.date), &cur);
+ if (ret != 0)
+ goto error;
+
+ /* is it an xs:gYear? */
+ RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEAR);
+
+ if (*cur != '-')
+ goto error;
+ cur++;
+
+ ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
+ if (ret != 0)
+ goto error;
+
+ /* is it an xs:gYearMonth? */
+ RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEARMONTH);
+
+ if (*cur != '-')
+ goto error;
+ cur++;
+
+ ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
+ if ((ret != 0) || !VALID_DATE((&(dt->value.date))))
+ goto error;
+
+ /* is it an xs:date? */
+ RETURN_TYPE_IF_VALID(XML_SCHEMAS_DATE);
+
+ if (*cur != 'T')
+ goto error;
+ cur++;
+
+ /* it should be an xs:dateTime */
+ ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
+ if (ret != 0)
+ goto error;
+
+ ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur);
+ if ((ret != 0) || (*cur != 0) || !VALID_DATETIME((&(dt->value.date))))
+ goto error;
+
+
+ dt->type = XML_SCHEMAS_DATETIME;
+
+done:
+#if 1
+ if ((type != XML_SCHEMAS_UNKNOWN) && (type != dt->type))
+ goto error;
+#else
+ /*
+ * insure the parsed type is equal to or less significant (right
+ * truncated) than the desired type.
+ */
+ if ((type != XML_SCHEMAS_UNKNOWN) && (type != dt->type)) {
+
+ /* time only matches time */
+ if ((type == XML_SCHEMAS_TIME) && (dt->type == XML_SCHEMAS_TIME))
+ goto error;
+
+ if ((type == XML_SCHEMAS_DATETIME) &&
+ ((dt->type != XML_SCHEMAS_DATE) ||
+ (dt->type != XML_SCHEMAS_GYEARMONTH) ||
+ (dt->type != XML_SCHEMAS_GYEAR)))
+ goto error;
+
+ if ((type == XML_SCHEMAS_DATE) &&
+ ((dt->type != XML_SCHEMAS_GYEAR) ||
+ (dt->type != XML_SCHEMAS_GYEARMONTH)))
+ goto error;
+
+ if ((type == XML_SCHEMAS_GYEARMONTH) && (dt->type != XML_SCHEMAS_GYEAR))
+ goto error;
+
+ if ((type == XML_SCHEMAS_GMONTHDAY) && (dt->type != XML_SCHEMAS_GMONTH))
+ goto error;
+ }
+#endif
+
+ if (val != NULL)
+ *val = dt;
+ else
+ xmlSchemaFreeValue(dt);
+
+ return 0;
+
+error:
+ if (dt != NULL)
+ xmlSchemaFreeValue(dt);
+ return 1;
+}
+
+/**
+ * xmlSchemaValidateDuration:
+ * @type: the predefined type
+ * @duration: string to analyze
+ * @val: the return computed value
+ *
+ * Check that @duration conforms to the lexical space of the duration type.
+ * if true a value is computed and returned in @val.
+ *
+ * Returns 0 if this validates, a positive error code number otherwise
+ * and -1 in case of internal or API error.
+ */
+static int
+xmlSchemaValidateDuration (xmlSchemaTypePtr type ATTRIBUTE_UNUSED,
+ const xmlChar *duration, xmlSchemaValPtr *val) {
+ const xmlChar *cur = duration;
+ xmlSchemaValPtr dur;
+ int isneg = 0;
+ unsigned int seq = 0;
+ double num;
+ int num_type = 0; /* -1 = invalid, 0 = int, 1 = floating */
+ const xmlChar desig[] = {'Y', 'M', 'D', 'H', 'M', 'S'};
+ const double multi[] = { 0.0, 0.0, 86400.0, 3600.0, 60.0, 1.0, 0.0};
+
+ if (duration == NULL)
+ return -1;
+
+ if (*cur == '-') {
+ isneg = 1;
+ cur++;
+ }
+
+ /* duration must start with 'P' (after sign) */
+ if (*cur++ != 'P')
+ return 1;
+
+ if (*cur == 0)
+ return 1;
+
+ dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
+ if (dur == NULL)
+ return -1;
+
+ while (*cur != 0) {
+
+ /* input string should be empty or invalid date/time item */
+ if (seq >= sizeof(desig))
+ goto error;
+
+ /* T designator must be present for time items */
+ if (*cur == 'T') {
+ if (seq <= 3) {
+ seq = 3;
+ cur++;
+ } else
+ return 1;
+ } else if (seq == 3)
+ goto error;
+
+ /* parse the number portion of the item */
+ PARSE_NUM(num, cur, num_type);
+
+ if ((num_type == -1) || (*cur == 0))
+ goto error;
+
+ /* update duration based on item type */
+ while (seq < sizeof(desig)) {
+ if (*cur == desig[seq]) {
+
+ /* verify numeric type; only seconds can be float */
+ if ((num_type != 0) && (seq < (sizeof(desig)-1)))
+ goto error;
+
+ switch (seq) {
+ case 0:
+ dur->value.dur.mon = (long)num * 12;
+ break;
+ case 1:
+ dur->value.dur.mon += (long)num;
+ break;
+ default:
+ /* convert to seconds using multiplier */
+ dur->value.dur.sec += num * multi[seq];
+ seq++;
+ break;
+ }
+
+ break; /* exit loop */
+ }
+ /* no date designators found? */
+ if (++seq == 3)
+ goto error;
+ }
+ cur++;
+ }
+
+ if (isneg) {
+ dur->value.dur.mon = -dur->value.dur.mon;
+ dur->value.dur.day = -dur->value.dur.day;
+ dur->value.dur.sec = -dur->value.dur.sec;
+ }
+
+ if (val != NULL)
+ *val = dur;
+ else
+ xmlSchemaFreeValue(dur);
+
+ return 0;
+
+error:
+ if (dur != NULL)
+ xmlSchemaFreeValue(dur);
+ return 1;
+}
+
+/**
+ * xmlSchemaStrip:
+ * @value: a value
+ *
+ * Removes the leading and ending spaces of a string
+ *
+ * Returns the new string or NULL if no change was required.
+ */
+static xmlChar *
+xmlSchemaStrip(const xmlChar *value) {
+ const xmlChar *start = value, *end, *f;
+
+ if (value == NULL) return(NULL);
+ while ((*start != 0) && (IS_BLANK_CH(*start))) start++;
+ end = start;
+ while (*end != 0) end++;
+ f = end;
+ end--;
+ while ((end > start) && (IS_BLANK_CH(*end))) end--;
+ end++;
+ if ((start == value) && (f == end)) return(NULL);
+ return(xmlStrndup(start, end - start));
+}
+
+/**
+ * xmlSchemaCollapseString:
+ * @value: a value
+ *
+ * Removes and normalize white spaces in the string
+ *
+ * Returns the new string or NULL if no change was required.
+ */
+static xmlChar *
+xmlSchemaCollapseString(const xmlChar *value) {
+ const xmlChar *start = value, *end, *f;
+ xmlChar *g;
+ int col = 0;
+
+ if (value == NULL) return(NULL);
+ while ((*start != 0) && (IS_BLANK_CH(*start))) start++;
+ end = start;
+ while (*end != 0) {
+ if ((*end == ' ') && (IS_BLANK_CH(end[1]))) {
+ col = end - start;
+ break;
+ } else if ((*end == 0xa) || (*end == 0x9) || (*end == 0xd)) {
+ col = end - start;
+ break;
+ }
+ end++;
+ }
+ if (col == 0) {
+ f = end;
+ end--;
+ while ((end > start) && (IS_BLANK_CH(*end))) end--;
+ end++;
+ if ((start == value) && (f == end)) return(NULL);
+ return(xmlStrndup(start, end - start));
+ }
+ start = xmlStrdup(start);
+ if (start == NULL) return(NULL);
+ g = (xmlChar *) (start + col);
+ end = g;
+ while (*end != 0) {
+ if (IS_BLANK_CH(*end)) {
+ end++;
+ while (IS_BLANK_CH(*end)) end++;
+ if (*end != 0)
+ *g++ = ' ';
+ } else
+ *g++ = *end++;
+ }
+ *g = 0;
+ return((xmlChar *) start);
+}
+
+/**
+ * xmlSchemaValAtomicListNode:
+ * @type: the predefined atomic type for a token in the list
+ * @value: the list value to check
+ * @ret: the return computed value
+ * @node: the node containing the value
+ *
+ * Check that a value conforms to the lexical space of the predefined
+ * list type. if true a value is computed and returned in @ret.
+ *
+ * Returns the number of items if this validates, a negative error code
+ * number otherwise
+ */
+static int
+xmlSchemaValAtomicListNode(xmlSchemaTypePtr type, const xmlChar *value,
+ xmlSchemaValPtr *ret, xmlNodePtr node) {
+ xmlChar *val, *cur, *endval;
+ int nb_values = 0;
+ int tmp = 0;
+
+ if (value == NULL) {
+ return(-1);
+ }
+ val = xmlStrdup(value);
+ if (val == NULL) {
+ return(-1);
+ }
+ cur = val;
+ /*
+ * Split the list
+ */
+ while (IS_BLANK_CH(*cur)) *cur++ = 0;
+ while (*cur != 0) {
+ if (IS_BLANK_CH(*cur)) {
+ *cur = 0;
+ cur++;
+ while (IS_BLANK_CH(*cur)) *cur++ = 0;
+ } else {
+ nb_values++;
+ cur++;
+ while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
+ }
+ }
+ if (nb_values == 0) {
+ if (ret != NULL) {
+ TODO
+ }
+ xmlFree(val);
+ return(nb_values);
+ }
+ endval = cur;
+ cur = val;
+ while ((*cur == 0) && (cur != endval)) cur++;
+ while (cur != endval) {
+ tmp = xmlSchemaValPredefTypeNode(type, cur, NULL, node);
+ if (tmp != 0)
+ break;
+ while (*cur != 0) cur++;
+ while ((*cur == 0) && (cur != endval)) cur++;
+ }
+ xmlFree(val);
+ if (ret != NULL) {
+ TODO
+ }
+ if (tmp == 0)
+ return(nb_values);
+ return(-1);
+}
+
+/**
+ * xmlSchemaParseUInt:
+ * @str: pointer to the string R/W
+ * @llo: pointer to the low result
+ * @lmi: pointer to the mid result
+ * @lhi: pointer to the high result
+ *
+ * Parse an unsigned long into 3 fields.
+ *
+ * Returns the number of chars parsed or -1 if overflow of the capacity
+ */
+static int
+xmlSchemaParseUInt(const xmlChar **str, unsigned long *llo,
+ unsigned long *lmi, unsigned long *lhi) {
+ unsigned long lo = 0, mi = 0, hi = 0;
+ const xmlChar *tmp, *cur = *str;
+ int ret = 0, i = 0;
+
+ while (*cur == '0') {
+ ret++;
+ cur++;
+ }
+ tmp = cur;
+ while ((*tmp != 0) && (*tmp >= '0') && (*tmp <= '9')) {
+ i++;tmp++;ret++;
+ }
+ if (i > 24) {
+ *str = tmp;
+ return(-1);
+ }
+ while (i > 16) {
+ hi = hi * 10 + (*cur++ - '0');
+ i--;
+ }
+ while (i > 8) {
+ mi = mi * 10 + (*cur++ - '0');
+ i--;
+ }
+ while (i > 0) {
+ lo = lo * 10 + (*cur++ - '0');
+ i--;
+ }
+
+ *str = cur;
+ *llo = lo;
+ *lmi = mi;
+ *lhi = hi;
+ return(ret);
+}
+
+/**
+ * xmlSchemaValAtomicType:
+ * @type: the predefined type
+ * @value: the value to check
+ * @val: the return computed value
+ * @node: the node containing the value
+ * flags: flags to control the vlidation
+ *
+ * Check that a value conforms to the lexical space of the atomic type.
+ * if true a value is computed and returned in @val.
+ *
+ * Returns 0 if this validates, a positive error code number otherwise
+ * and -1 in case of internal or API error.
+ */
+static int
+xmlSchemaValAtomicType(xmlSchemaTypePtr type, const xmlChar * value,
+ xmlSchemaValPtr * val, xmlNodePtr node, int flags)
+{
+ xmlSchemaValPtr v;
+ xmlChar *norm = NULL;
+ int ret = 0;
+
+ if (xmlSchemaTypesInitialized == 0)
+ return (-1);
+ if (type == NULL)
+ return (-1);
+
+ if (val != NULL)
+ *val = NULL;
+ if ((flags == 0) && (value != NULL)) {
+ if ((type->flags != XML_SCHEMAS_STRING) &&
+ (type->flags != XML_SCHEMAS_NORMSTRING)) {
+ norm = xmlSchemaCollapseString(value);
+ if (norm != NULL)
+ value = norm;
+ }
+ }
+
+ switch (type->flags) {
+ case XML_SCHEMAS_UNKNOWN:
+ if (type == xmlSchemaTypeAnyTypeDef)
+ goto return0;
+ goto error;
+ case XML_SCHEMAS_STRING:
+ goto return0;
+ case XML_SCHEMAS_NORMSTRING:{
+ const xmlChar *cur = value;
+
+ while (*cur != 0) {
+ if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) {
+ goto return1;
+ } else {
+ cur++;
+ }
+ }
+ if (val != NULL) {
+ v = xmlSchemaNewValue(XML_SCHEMAS_NORMSTRING);
+ if (v != NULL) {
+ v->value.str = xmlStrdup(value);
+ *val = v;
+ } else {
+ goto error;
+ }
+ }
+ goto return0;
+ }
+ case XML_SCHEMAS_DECIMAL:{
+ const xmlChar *cur = value, *tmp;
+ unsigned int frac = 0, len, neg = 0;
+ unsigned long base = 0;
+
+ if (cur == NULL)
+ goto return1;
+ if (*cur == '+')
+ cur++;
+ else if (*cur == '-') {
+ neg = 1;
+ cur++;
+ }
+ tmp = cur;
+ while ((*cur >= '0') && (*cur <= '9')) {
+ base = base * 10 + (*cur - '0');
+ cur++;
+ }
+ len = cur - tmp;
+ if (*cur == '.') {
+ cur++;
+ tmp = cur;
+ while ((*cur >= '0') && (*cur <= '9')) {
+ base = base * 10 + (*cur - '0');
+ cur++;
+ }
+ frac = cur - tmp;
+ }
+ if (*cur != 0)
+ goto return1;
+ if (val != NULL) {
+ v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
+ if (v != NULL) {
+ v->value.decimal.lo = base;
+ v->value.decimal.sign = neg;
+ v->value.decimal.frac = frac;
+ v->value.decimal.total = frac + len;
+ *val = v;
+ }
+ }
+ goto return0;
+ }
+ case XML_SCHEMAS_TIME:
+ case XML_SCHEMAS_GDAY:
+ case XML_SCHEMAS_GMONTH:
+ case XML_SCHEMAS_GMONTHDAY:
+ case XML_SCHEMAS_GYEAR:
+ case XML_SCHEMAS_GYEARMONTH:
+ case XML_SCHEMAS_DATE:
+ case XML_SCHEMAS_DATETIME:
+ ret = xmlSchemaValidateDates(type->flags, value, val);
+ break;
+ case XML_SCHEMAS_DURATION:
+ ret = xmlSchemaValidateDuration(type, value, val);
+ break;
+ case XML_SCHEMAS_FLOAT:
+ case XML_SCHEMAS_DOUBLE:{
+ const xmlChar *cur = value;
+ int neg = 0;
+
+ if (cur == NULL)
+ goto return1;
+ if ((cur[0] == 'N') && (cur[1] == 'a') && (cur[2] == 'N')) {
+ cur += 3;
+ if (*cur != 0)
+ goto return1;
+ if (val != NULL) {
+ if (type == xmlSchemaTypeFloatDef) {
+ v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
+ if (v != NULL) {
+ v->value.f = (float) xmlXPathNAN;
+ } else {
+ xmlSchemaFreeValue(v);
+ goto error;
+ }
+ } else {
+ v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
+ if (v != NULL) {
+ v->value.d = xmlXPathNAN;
+ } else {
+ xmlSchemaFreeValue(v);
+ goto error;
+ }
+ }
+ *val = v;
+ }
+ goto return0;
+ }
+ if (*cur == '-') {
+ neg = 1;
+ cur++;
+ }
+ if ((cur[0] == 'I') && (cur[1] == 'N') && (cur[2] == 'F')) {
+ cur += 3;
+ if (*cur != 0)
+ goto return1;
+ if (val != NULL) {
+ if (type == xmlSchemaTypeFloatDef) {
+ v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
+ if (v != NULL) {
+ if (neg)
+ v->value.f = (float) xmlXPathNINF;
+ else
+ v->value.f = (float) xmlXPathPINF;
+ } else {
+ xmlSchemaFreeValue(v);
+ goto error;
+ }
+ } else {
+ v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
+ if (v != NULL) {
+ if (neg)
+ v->value.d = xmlXPathNINF;
+ else
+ v->value.d = xmlXPathPINF;
+ } else {
+ xmlSchemaFreeValue(v);
+ goto error;
+ }
+ }
+ *val = v;
+ }
+ goto return0;
+ }
+ if ((neg == 0) && (*cur == '+'))
+ cur++;
+ if ((cur[0] == 0) || (cur[0] == '+') || (cur[0] == '-'))
+ goto return1;
+ while ((*cur >= '0') && (*cur <= '9')) {
+ cur++;
+ }
+ if (*cur == '.') {
+ cur++;
+ while ((*cur >= '0') && (*cur <= '9'))
+ cur++;
+ }
+ if ((*cur == 'e') || (*cur == 'E')) {
+ cur++;
+ if ((*cur == '-') || (*cur == '+'))
+ cur++;
+ while ((*cur >= '0') && (*cur <= '9'))
+ cur++;
+ }
+ if (*cur != 0)
+ goto return1;
+ if (val != NULL) {
+ if (type == xmlSchemaTypeFloatDef) {
+ v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
+ if (v != NULL) {
+ if (sscanf((const char *) value, "%f",
+ &(v->value.f)) == 1) {
+ *val = v;
+ } else {
+ xmlSchemaFreeValue(v);
+ goto return1;
+ }
+ } else {
+ goto error;
+ }
+ } else {
+ v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
+ if (v != NULL) {
+ if (sscanf((const char *) value, "%lf",
+ &(v->value.d)) == 1) {
+ *val = v;
+ } else {
+ xmlSchemaFreeValue(v);
+ goto return1;
+ }
+ } else {
+ goto error;
+ }
+ }
+ }
+ goto return0;
+ }
+ case XML_SCHEMAS_BOOLEAN:{
+ const xmlChar *cur = value;
+
+ if ((cur[0] == '0') && (cur[1] == 0))
+ ret = 0;
+ else if ((cur[0] == '1') && (cur[1] == 0))
+ ret = 1;
+ else if ((cur[0] == 't') && (cur[1] == 'r')
+ && (cur[2] == 'u') && (cur[3] == 'e')
+ && (cur[4] == 0))
+ ret = 1;
+ else if ((cur[0] == 'f') && (cur[1] == 'a')
+ && (cur[2] == 'l') && (cur[3] == 's')
+ && (cur[4] == 'e') && (cur[5] == 0))
+ ret = 0;
+ else
+ goto return1;
+ if (val != NULL) {
+ v = xmlSchemaNewValue(XML_SCHEMAS_BOOLEAN);
+ if (v != NULL) {
+ v->value.b = ret;
+ *val = v;
+ } else {
+ goto error;
+ }
+ }
+ goto return0;
+ }
+ case XML_SCHEMAS_TOKEN:{
+ const xmlChar *cur = value;
+
+ if (IS_BLANK_CH(*cur))
+ goto return1;
+
+ while (*cur != 0) {
+ if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) {
+ goto return1;
+ } else if (*cur == ' ') {
+ cur++;
+ if (*cur == 0)
+ goto return1;
+ if (*cur == ' ')
+ goto return1;
+ } else {
+ cur++;
+ }
+ }
+ if (val != NULL) {
+ v = xmlSchemaNewValue(XML_SCHEMAS_TOKEN);
+ if (v != NULL) {
+ v->value.str = xmlStrdup(value);
+ *val = v;
+ } else {
+ goto error;
+ }
+ }
+ goto return0;
+ }
+ case XML_SCHEMAS_LANGUAGE:
+ if (xmlCheckLanguageID(value) == 1) {
+ if (val != NULL) {
+ v = xmlSchemaNewValue(XML_SCHEMAS_LANGUAGE);
+ if (v != NULL) {
+ v->value.str = xmlStrdup(value);
+ *val = v;
+ } else {
+ goto error;
+ }
+ }
+ goto return0;
+ }
+ goto return1;
+ case XML_SCHEMAS_NMTOKEN:
+ if (xmlValidateNMToken(value, 1) == 0) {
+ if (val != NULL) {
+ v = xmlSchemaNewValue(XML_SCHEMAS_NMTOKEN);
+ if (v != NULL) {
+ v->value.str = xmlStrdup(value);
+ *val = v;
+ } else {
+ goto error;
+ }
+ }
+ goto return0;
+ }
+ goto return1;
+ case XML_SCHEMAS_NMTOKENS:
+ ret = xmlSchemaValAtomicListNode(xmlSchemaTypeNmtokenDef,
+ value, val, node);
+ if (ret > 0)
+ ret = 0;
+ else
+ ret = 1;
+ goto done;
+ case XML_SCHEMAS_NAME:
+ ret = xmlValidateName(value, 1);
+ if ((ret == 0) && (val != NULL)) {
+ TODO;
+ }
+ goto done;
+ case XML_SCHEMAS_QNAME:{
+ xmlChar *uri = NULL;
+ xmlChar *local = NULL;
+
+ ret = xmlValidateQName(value, 1);
+ if ((ret == 0) && (node != NULL)) {
+ xmlChar *prefix;
+
+ local = xmlSplitQName2(value, &prefix);
+ if (prefix != NULL) {
+ xmlNsPtr ns;
+
+ ns = xmlSearchNs(node->doc, node, prefix);
+ if (ns == NULL)
+ ret = 1;
+ else if (val != NULL)
+ uri = xmlStrdup(ns->href);
+ }
+ if ((local != NULL) && ((val == NULL) || (ret != 0)))
+ xmlFree(local);
+ if (prefix != NULL)
+ xmlFree(prefix);
+ }
+ if ((ret == 0) && (val != NULL)) {
+ v = xmlSchemaNewValue(XML_SCHEMAS_QNAME);
+ if (v != NULL) {
+ if (local != NULL)
+ v->value.qname.name = local;
+ else
+ v->value.qname.name = xmlStrdup(value);
+ if (uri != NULL)
+ v->value.qname.uri = uri;
+
+ *val = v;
+ } else {
+ if (local != NULL)
+ xmlFree(local);
+ if (uri != NULL)
+ xmlFree(uri);
+ goto error;
+ }
+ }
+ goto done;
+ }
+ case XML_SCHEMAS_NCNAME:
+ ret = xmlValidateNCName(value, 1);
+ if ((ret == 0) && (val != NULL)) {
+ v = xmlSchemaNewValue(XML_SCHEMAS_NCNAME);
+ if (v != NULL) {
+ v->value.str = xmlStrdup(value);
+ *val = v;
+ } else {
+ goto error;
+ }
+ }
+ goto done;
+ case XML_SCHEMAS_ID:
+ ret = xmlValidateNCName(value, 1);
+ if ((ret == 0) && (val != NULL)) {
+ v = xmlSchemaNewValue(XML_SCHEMAS_ID);
+ if (v != NULL) {
+ v->value.str = xmlStrdup(value);
+ *val = v;
+ } else {
+ goto error;
+ }
+ }
+ if ((ret == 0) && (node != NULL) &&
+ (node->type == XML_ATTRIBUTE_NODE)) {
+ xmlAttrPtr attr = (xmlAttrPtr) node;
+
+ /*
+ * NOTE: the IDness might have already be declared in the DTD
+ */
+ if (attr->atype != XML_ATTRIBUTE_ID) {
+ xmlIDPtr res;
+ xmlChar *strip;
+
+ strip = xmlSchemaStrip(value);
+ if (strip != NULL) {
+ res = xmlAddID(NULL, node->doc, strip, attr);
+ xmlFree(strip);
+ } else
+ res = xmlAddID(NULL, node->doc, value, attr);
+ if (res == NULL) {
+ ret = 2;
+ } else {
+ attr->atype = XML_ATTRIBUTE_ID;
+ }
+ }
+ }
+ goto done;
+ case XML_SCHEMAS_IDREF:
+ ret = xmlValidateNCName(value, 1);
+ if ((ret == 0) && (val != NULL)) {
+ TODO;
+ }
+ if ((ret == 0) && (node != NULL) &&
+ (node->type == XML_ATTRIBUTE_NODE)) {
+ xmlAttrPtr attr = (xmlAttrPtr) node;
+ xmlChar *strip;
+
+ strip = xmlSchemaStrip(value);
+ if (strip != NULL) {
+ xmlAddRef(NULL, node->doc, strip, attr);
+ xmlFree(strip);
+ } else
+ xmlAddRef(NULL, node->doc, value, attr);
+ attr->atype = XML_ATTRIBUTE_IDREF;
+ }
+ goto done;
+ case XML_SCHEMAS_IDREFS:
+ ret = xmlSchemaValAtomicListNode(xmlSchemaTypeIdrefDef,
+ value, val, node);
+ if (ret < 0)
+ ret = 2;
+ else
+ ret = 0;
+ if ((ret == 0) && (node != NULL) &&
+ (node->type == XML_ATTRIBUTE_NODE)) {
+ xmlAttrPtr attr = (xmlAttrPtr) node;
+
+ attr->atype = XML_ATTRIBUTE_IDREFS;
+ }
+ goto done;
+ case XML_SCHEMAS_ENTITY:{
+ xmlChar *strip;
+
+ ret = xmlValidateNCName(value, 1);
+ if ((node == NULL) || (node->doc == NULL))
+ ret = 3;
+ if (ret == 0) {
+ xmlEntityPtr ent;
+
+ strip = xmlSchemaStrip(value);
+ if (strip != NULL) {
+ ent = xmlGetDocEntity(node->doc, strip);
+ xmlFree(strip);
+ } else {
+ ent = xmlGetDocEntity(node->doc, value);
+ }
+ if ((ent == NULL) ||
+ (ent->etype !=
+ XML_EXTERNAL_GENERAL_UNPARSED_ENTITY))
+ ret = 4;
+ }
+ if ((ret == 0) && (val != NULL)) {
+ TODO;
+ }
+ if ((ret == 0) && (node != NULL) &&
+ (node->type == XML_ATTRIBUTE_NODE)) {
+ xmlAttrPtr attr = (xmlAttrPtr) node;
+
+ attr->atype = XML_ATTRIBUTE_ENTITY;
+ }
+ goto done;
+ }
+ case XML_SCHEMAS_ENTITIES:
+ if ((node == NULL) || (node->doc == NULL))
+ goto return3;
+ ret = xmlSchemaValAtomicListNode(xmlSchemaTypeEntityDef,
+ value, val, node);
+ if (ret <= 0)
+ ret = 1;
+ else
+ ret = 0;
+ if ((ret == 0) && (node != NULL) &&
+ (node->type == XML_ATTRIBUTE_NODE)) {
+ xmlAttrPtr attr = (xmlAttrPtr) node;
+
+ attr->atype = XML_ATTRIBUTE_ENTITIES;
+ }
+ goto done;
+ case XML_SCHEMAS_NOTATION:{
+ xmlChar *uri = NULL;
+ xmlChar *local = NULL;
+
+ ret = xmlValidateQName(value, 1);
+ if ((ret == 0) && (node != NULL)) {
+ xmlChar *prefix;
+
+ local = xmlSplitQName2(value, &prefix);
+ if (prefix != NULL) {
+ xmlNsPtr ns;
+
+ ns = xmlSearchNs(node->doc, node, prefix);
+ if (ns == NULL)
+ ret = 1;
+ else if (val != NULL)
+ uri = xmlStrdup(ns->href);
+ }
+ if ((local != NULL) && ((val == NULL) || (ret != 0)))
+ xmlFree(local);
+ if (prefix != NULL)
+ xmlFree(prefix);
+ }
+ if ((node == NULL) || (node->doc == NULL))
+ ret = 3;
+ if (ret == 0) {
+ ret = xmlValidateNotationUse(NULL, node->doc, value);
+ if (ret == 1)
+ ret = 0;
+ else
+ ret = 1;
+ }
+ if ((ret == 0) && (val != NULL)) {
+ v = xmlSchemaNewValue(XML_SCHEMAS_NOTATION);
+ if (v != NULL) {
+ if (local != NULL)
+ v->value.qname.name = local;
+ else
+ v->value.qname.name = xmlStrdup(value);
+ if (uri != NULL)
+ v->value.qname.uri = uri;
+
+ *val = v;
+ } else {
+ if (local != NULL)
+ xmlFree(local);
+ if (uri != NULL)
+ xmlFree(uri);
+ goto error;
+ }
+ }
+ goto done;
+ }
+ case XML_SCHEMAS_ANYURI:{
+ if (*value != 0) {
+ xmlURIPtr uri = xmlParseURI((const char *) value);
+ if (uri == NULL)
+ goto return1;
+ xmlFreeURI(uri);
+ }
+
+ if (val != NULL) {
+ v = xmlSchemaNewValue(XML_SCHEMAS_ANYURI);
+ if (v == NULL)
+ goto error;
+ v->value.str = xmlStrdup(value);
+ *val = v;
+ }
+ goto return0;
+ }
+ case XML_SCHEMAS_HEXBINARY:{
+ const xmlChar *cur = value;
+ xmlChar *base;
+ int total, i = 0;
+
+ if (cur == NULL)
+ goto return1;
+
+ while (((*cur >= '0') && (*cur <= '9')) ||
+ ((*cur >= 'A') && (*cur <= 'F')) ||
+ ((*cur >= 'a') && (*cur <= 'f'))) {
+ i++;
+ cur++;
+ }
+
+ if (*cur != 0)
+ goto return1;
+ if ((i % 2) != 0)
+ goto return1;
+
+ if (val != NULL) {
+
+ v = xmlSchemaNewValue(XML_SCHEMAS_HEXBINARY);
+ if (v == NULL)
+ goto error;
+
+ cur = xmlStrdup(value);
+ if (cur == NULL) {
+ xmlSchemaTypeErrMemory(node, "allocating hexbin data");
+ xmlFree(v);
+ goto return1;
+ }
+
+ total = i / 2; /* number of octets */
+
+ base = (xmlChar *) cur;
+ while (i-- > 0) {
+ if (*base >= 'a')
+ *base = *base - ('a' - 'A');
+ base++;
+ }
+
+ v->value.hex.str = (xmlChar *) cur;
+ v->value.hex.total = total;
+ *val = v;
+ }
+ goto return0;
+ }
+ case XML_SCHEMAS_BASE64BINARY:{
+ /* ISSUE:
+ *
+ * Ignore all stray characters? (yes, currently)
+ * Worry about long lines? (no, currently)
+ *
+ * rfc2045.txt:
+ *
+ * "The encoded output stream must be represented in lines of
+ * no more than 76 characters each. All line breaks or other
+ * characters not found in Table 1 must be ignored by decoding
+ * software. In base64 data, characters other than those in
+ * Table 1, line breaks, and other white space probably
+ * indicate a transmission error, about which a warning
+ * message or even a message rejection might be appropriate
+ * under some circumstances." */
+ const xmlChar *cur = value;
+ xmlChar *base;
+ int total, i = 0, pad = 0;
+
+ if (cur == NULL)
+ goto return1;
+
+ for (; *cur; ++cur) {
+ int decc;
+
+ decc = _xmlSchemaBase64Decode(*cur);
+ if (decc < 0) ;
+ else if (decc < 64)
+ i++;
+ else
+ break;
+ }
+ for (; *cur; ++cur) {
+ int decc;
+
+ decc = _xmlSchemaBase64Decode(*cur);
+ if (decc < 0) ;
+ else if (decc < 64)
+ goto return1;
+ if (decc == 64)
+ pad++;
+ }
+
+ /* rfc2045.txt: "Special processing is performed if fewer than
+ * 24 bits are available at the end of the data being encoded.
+ * A full encoding quantum is always completed at the end of a
+ * body. When fewer than 24 input bits are available in an
+ * input group, zero bits are added (on the right) to form an
+ * integral number of 6-bit groups. Padding at the end of the
+ * data is performed using the "=" character. Since all
+ * base64 input is an integral number of octets, only the
+ * following cases can arise: (1) the final quantum of
+ * encoding input is an integral multiple of 24 bits; here,
+ * the final unit of encoded output will be an integral
+ * multiple ofindent: Standard input:701: Warning:old style
+ * assignment ambiguity in "=*". Assuming "= *" 4 characters
+ * with no "=" padding, (2) the final
+ * quantum of encoding input is exactly 8 bits; here, the
+ * final unit of encoded output will be two characters
+ * followed by two "=" padding characters, or (3) the final
+ * quantum of encoding input is exactly 16 bits; here, the
+ * final unit of encoded output will be three characters
+ * followed by one "=" padding character." */
+
+ total = 3 * (i / 4);
+ if (pad == 0) {
+ if (i % 4 != 0)
+ goto return1;
+ } else if (pad == 1) {
+ int decc;
+
+ if (i % 4 != 3)
+ goto return1;
+ for (decc = _xmlSchemaBase64Decode(*cur);
+ (decc < 0) || (decc > 63);
+ decc = _xmlSchemaBase64Decode(*cur))
+ --cur;
+ /* 16bits in 24bits means 2 pad bits: nnnnnn nnmmmm mmmm00*/
+ /* 00111100 -> 0x3c */
+ if (decc & ~0x3c)
+ goto return1;
+ total += 2;
+ } else if (pad == 2) {
+ int decc;
+
+ if (i % 4 != 2)
+ goto return1;
+ for (decc = _xmlSchemaBase64Decode(*cur);
+ (decc < 0) || (decc > 63);
+ decc = _xmlSchemaBase64Decode(*cur))
+ --cur;
+ /* 8bits in 12bits means 4 pad bits: nnnnnn nn0000 */
+ /* 00110000 -> 0x30 */
+ if (decc & ~0x30)
+ goto return1;
+ total += 1;
+ } else
+ goto return1;
+
+ if (val != NULL) {
+ v = xmlSchemaNewValue(XML_SCHEMAS_BASE64BINARY);
+ if (v == NULL)
+ goto error;
+ base =
+ (xmlChar *) xmlMallocAtomic((i + pad + 1) *
+ sizeof(xmlChar));
+ if (base == NULL) {
+ xmlSchemaTypeErrMemory(node, "allocating base64 data");
+ xmlFree(v);
+ goto return1;
+ }
+ v->value.base64.str = base;
+ for (cur = value; *cur; ++cur)
+ if (_xmlSchemaBase64Decode(*cur) >= 0) {
+ *base = *cur;
+ ++base;
+ }
+ *base = 0;
+ v->value.base64.total = total;
+ *val = v;
+ }
+ goto return0;
+ }
+ case XML_SCHEMAS_INTEGER:
+ case XML_SCHEMAS_PINTEGER:
+ case XML_SCHEMAS_NPINTEGER:
+ case XML_SCHEMAS_NINTEGER:
+ case XML_SCHEMAS_NNINTEGER:{
+ const xmlChar *cur = value;
+ unsigned long lo, mi, hi;
+ int sign = 0;
+
+ if (cur == NULL)
+ goto return1;
+ if (*cur == '-') {
+ sign = 1;
+ cur++;
+ } else if (*cur == '+')
+ cur++;
+ ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
+ if (ret == 0)
+ goto return1;
+ if (*cur != 0)
+ goto return1;
+ if (type->flags == XML_SCHEMAS_NPINTEGER) {
+ if ((sign == 0) &&
+ ((hi != 0) || (mi != 0) || (lo != 0)))
+ goto return1;
+ } else if (type->flags == XML_SCHEMAS_PINTEGER) {
+ if (sign == 1)
+ goto return1;
+ if ((hi == 0) && (mi == 0) && (lo == 0))
+ goto return1;
+ } else if (type->flags == XML_SCHEMAS_NINTEGER) {
+ if (sign == 0)
+ goto return1;
+ if ((hi == 0) && (mi == 0) && (lo == 0))
+ goto return1;
+ } else if (type->flags == XML_SCHEMAS_NNINTEGER) {
+ if ((sign == 1) &&
+ ((hi != 0) || (mi != 0) || (lo != 0)))
+ goto return1;
+ }
+ /*
+ * We can store a value only if no overflow occured
+ */
+ if ((ret > 0) && (val != NULL)) {
+ v = xmlSchemaNewValue(type->flags);
+ if (v != NULL) {
+ v->value.decimal.lo = lo;
+ v->value.decimal.mi = lo;
+ v->value.decimal.hi = lo;
+ v->value.decimal.sign = sign;
+ v->value.decimal.frac = 0;
+ v->value.decimal.total = cur - value;
+ *val = v;
+ }
+ }
+ goto return0;
+ }
+ case XML_SCHEMAS_LONG:
+ case XML_SCHEMAS_BYTE:
+ case XML_SCHEMAS_SHORT:
+ case XML_SCHEMAS_INT:{
+ const xmlChar *cur = value;
+ unsigned long lo, mi, hi;
+ int total = 0;
+ int sign = 0;
+
+ if (cur == NULL)
+ goto return1;
+ if (*cur == '-') {
+ sign = 1;
+ cur++;
+ } else if (*cur == '+')
+ cur++;
+ ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
+ if (ret <= 0)
+ goto return1;
+ if (*cur != 0)
+ goto return1;
+ if (type->flags == XML_SCHEMAS_LONG) {
+ if (hi >= 922) {
+ if (hi > 922)
+ goto return1;
+ if (mi >= 33720368) {
+ if (mi > 33720368)
+ goto return1;
+ if ((sign == 0) && (lo > 54775807))
+ goto return1;
+ if ((sign == 1) && (lo > 54775808))
+ goto return1;
+ }
+ }
+ } else if (type->flags == XML_SCHEMAS_INT) {
+ if (hi != 0)
+ goto return1;
+ if (mi >= 21) {
+ if (mi > 21)
+ goto return1;
+ if ((sign == 0) && (lo > 47483647))
+ goto return1;
+ if ((sign == 1) && (lo > 47483648))
+ goto return1;
+ }
+ } else if (type->flags == XML_SCHEMAS_SHORT) {
+ if ((mi != 0) || (hi != 0))
+ goto return1;
+ if ((sign == 1) && (lo > 32768))
+ goto return1;
+ if ((sign == 0) && (lo > 32767))
+ goto return1;
+ } else if (type->flags == XML_SCHEMAS_BYTE) {
+ if ((mi != 0) || (hi != 0))
+ goto return1;
+ if ((sign == 1) && (lo > 128))
+ goto return1;
+ if ((sign == 0) && (lo > 127))
+ goto return1;
+ }
+ if (val != NULL) {
+ v = xmlSchemaNewValue(type->flags);
+ if (v != NULL) {
+ v->value.decimal.lo = lo;
+ v->value.decimal.mi = lo;
+ v->value.decimal.hi = lo;
+ v->value.decimal.sign = sign;
+ v->value.decimal.frac = 0;
+ v->value.decimal.total = total;
+ *val = v;
+ }
+ }
+ goto return0;
+ }
+ case XML_SCHEMAS_UINT:
+ case XML_SCHEMAS_ULONG:
+ case XML_SCHEMAS_USHORT:
+ case XML_SCHEMAS_UBYTE:{
+ const xmlChar *cur = value;
+ unsigned long lo, mi, hi;
+ int total = 0;
+
+ if (cur == NULL)
+ goto return1;
+ ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
+ if (ret <= 0)
+ goto return1;
+ if (*cur != 0)
+ goto return1;
+ if (type->flags == XML_SCHEMAS_ULONG) {
+ if (hi >= 1844) {
+ if (hi > 1844)
+ goto return1;
+ if (mi >= 67440737) {
+ if (mi > 67440737)
+ goto return1;
+ if (lo > 9551615)
+ goto return1;
+ }
+ }
+ } else if (type->flags == XML_SCHEMAS_UINT) {
+ if (hi != 0)
+ goto return1;
+ if (mi >= 42) {
+ if (mi > 42)
+ goto return1;
+ if (lo > 94967295)
+ goto return1;
+ }
+ } else if (type->flags == XML_SCHEMAS_USHORT) {
+ if ((mi != 0) || (hi != 0))
+ goto return1;
+ if (lo > 65535)
+ goto return1;
+ } else if (type->flags == XML_SCHEMAS_UBYTE) {
+ if ((mi != 0) || (hi != 0))
+ goto return1;
+ if (lo > 255)
+ goto return1;
+ }
+ if (val != NULL) {
+ v = xmlSchemaNewValue(type->flags);
+ if (v != NULL) {
+ v->value.decimal.lo = lo;
+ v->value.decimal.mi = mi;
+ v->value.decimal.hi = hi;
+ v->value.decimal.sign = 0;
+ v->value.decimal.frac = 0;
+ v->value.decimal.total = total;
+ *val = v;
+ }
+ }
+ goto return0;
+ }
+ }
+
+ done:
+ if (norm != NULL)
+ xmlFree(norm);
+ return (ret);
+ return3:
+ if (norm != NULL)
+ xmlFree(norm);
+ return (3);
+ return1:
+ if (norm != NULL)
+ xmlFree(norm);
+ return (1);
+ return0:
+ if (norm != NULL)
+ xmlFree(norm);
+ return (0);
+ error:
+ if (norm != NULL)
+ xmlFree(norm);
+ return (-1);
+}
+
+/**
+ * xmlSchemaValPredefTypeNode:
+ * @type: the predefined type
+ * @value: the value to check
+ * @val: the return computed value
+ * @node: the node containing the value
+ *
+ * Check that a value conforms to the lexical space of the predefined type.
+ * if true a value is computed and returned in @val.
+ *
+ * Returns 0 if this validates, a positive error code number otherwise
+ * and -1 in case of internal or API error.
+ */
+int
+xmlSchemaValPredefTypeNode(xmlSchemaTypePtr type, const xmlChar *value,
+ xmlSchemaValPtr *val, xmlNodePtr node) {
+ return(xmlSchemaValAtomicType(type, value, val, node, 0));
+}
+
+/**
+ * xmlSchemaValidatePredefinedType:
+ * @type: the predefined type
+ * @value: the value to check
+ * @val: the return computed value
+ *
+ * Check that a value conforms to the lexical space of the predefined type.
+ * if true a value is computed and returned in @val.
+ *
+ * Returns 0 if this validates, a positive error code number otherwise
+ * and -1 in case of internal or API error.
+ */
+int
+xmlSchemaValidatePredefinedType(xmlSchemaTypePtr type, const xmlChar *value,
+ xmlSchemaValPtr *val) {
+ return(xmlSchemaValPredefTypeNode(type, value, val, NULL));
+}
+
+/**
+ * xmlSchemaCompareDecimals:
+ * @x: a first decimal value
+ * @y: a second decimal value
+ *
+ * Compare 2 decimals
+ *
+ * Returns -1 if x < y, 0 if x == y, 1 if x > y and -2 in case of error
+ */
+static int
+xmlSchemaCompareDecimals(xmlSchemaValPtr x, xmlSchemaValPtr y)
+{
+ xmlSchemaValPtr swp;
+ int order = 1, p;
+ unsigned long tmp;
+
+ if ((x->value.decimal.sign) &&
+ ((x->value.decimal.lo != 0) ||
+ (x->value.decimal.mi != 0) ||
+ (x->value.decimal.hi != 0))) {
+ if ((y->value.decimal.sign) &&
+ ((y->value.decimal.lo != 0) ||
+ (y->value.decimal.mi != 0) ||
+ (y->value.decimal.hi != 0)))
+ order = -1;
+ else
+ return (-1);
+ } else if ((y->value.decimal.sign) &&
+ ((y->value.decimal.lo != 0) ||
+ (y->value.decimal.mi != 0) ||
+ (y->value.decimal.hi != 0))) {
+ return (1);
+ }
+ if (x->value.decimal.frac == y->value.decimal.frac) {
+ if (x->value.decimal.hi < y->value.decimal.hi)
+ return (-order);
+ if (x->value.decimal.hi < y->value.decimal.hi)
+ return (order);
+ if (x->value.decimal.mi < y->value.decimal.mi)
+ return (-order);
+ if (x->value.decimal.mi < y->value.decimal.mi)
+ return (order);
+ if (x->value.decimal.lo < y->value.decimal.lo)
+ return (-order);
+ if (x->value.decimal.lo > y->value.decimal.lo)
+ return(order);
+ return(0);
+ }
+ if (y->value.decimal.frac > x->value.decimal.frac) {
+ swp = y;
+ y = x;
+ x = swp;
+ order = -order;
+ }
+ p = powten[x->value.decimal.frac - y->value.decimal.frac];
+ tmp = x->value.decimal.lo / p;
+ if (tmp > y->value.decimal.lo)
+ return (order);
+ if (tmp < y->value.decimal.lo)
+ return (-order);
+ tmp = y->value.decimal.lo * p;
+ if (x->value.decimal.lo < tmp)
+ return (-order);
+ if (x->value.decimal.lo == tmp)
+ return (0);
+ return (order);
+}
+
+/**
+ * xmlSchemaCompareDurations:
+ * @x: a first duration value
+ * @y: a second duration value
+ *
+ * Compare 2 durations
+ *
+ * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
+ * case of error
+ */
+static int
+xmlSchemaCompareDurations(xmlSchemaValPtr x, xmlSchemaValPtr y)
+{
+ long carry, mon, day;
+ double sec;
+ int invert = 1;
+ long xmon, xday, myear, minday, maxday;
+ static const long dayRange [2][12] = {
+ { 0, 28, 59, 89, 120, 150, 181, 212, 242, 273, 303, 334, },
+ { 0, 31, 62, 92, 123, 153, 184, 215, 245, 276, 306, 337} };
+
+ if ((x == NULL) || (y == NULL))
+ return -2;
+
+ /* months */
+ mon = x->value.dur.mon - y->value.dur.mon;
+
+ /* seconds */
+ sec = x->value.dur.sec - y->value.dur.sec;
+ carry = (long)sec / SECS_PER_DAY;
+ sec -= (double)(carry * SECS_PER_DAY);
+
+ /* days */
+ day = x->value.dur.day - y->value.dur.day + carry;
+
+ /* easy test */
+ if (mon == 0) {
+ if (day == 0)
+ if (sec == 0.0)
+ return 0;
+ else if (sec < 0.0)
+ return -1;
+ else
+ return 1;
+ else if (day < 0)
+ return -1;
+ else
+ return 1;
+ }
+
+ if (mon > 0) {
+ if ((day >= 0) && (sec >= 0.0))
+ return 1;
+ else {
+ xmon = mon;
+ xday = -day;
+ }
+ } else if ((day <= 0) && (sec <= 0.0)) {
+ return -1;
+ } else {
+ invert = -1;
+ xmon = -mon;
+ xday = day;
+ }
+
+ myear = xmon / 12;
+ if (myear == 0) {
+ minday = 0;
+ maxday = 0;
+ } else {
+ maxday = 366 * ((myear + 3) / 4) +
+ 365 * ((myear - 1) % 4);
+ minday = maxday - 1;
+ }
+
+ xmon = xmon % 12;
+ minday += dayRange[0][xmon];
+ maxday += dayRange[1][xmon];
+
+ if ((maxday == minday) && (maxday == xday))
+ return(0); /* can this really happen ? */
+ if (maxday < xday)
+ return(-invert);
+ if (minday > xday)
+ return(invert);
+
+ /* indeterminate */
+ return 2;
+}
+
+/*
+ * macros for adding date/times and durations
+ */
+#define FQUOTIENT(a,b) (floor(((double)a/(double)b)))
+#define MODULO(a,b) (a - FQUOTIENT(a,b) * b)
+#define FQUOTIENT_RANGE(a,low,high) (FQUOTIENT((a-low),(high-low)))
+#define MODULO_RANGE(a,low,high) ((MODULO((a-low),(high-low)))+low)
+
+/**
+ * _xmlSchemaDateAdd:
+ * @dt: an #xmlSchemaValPtr
+ * @dur: an #xmlSchemaValPtr of type #XS_DURATION
+ *
+ * Compute a new date/time from @dt and @dur. This function assumes @dt
+ * is either #XML_SCHEMAS_DATETIME, #XML_SCHEMAS_DATE, #XML_SCHEMAS_GYEARMONTH,
+ * or #XML_SCHEMAS_GYEAR.
+ *
+ * Returns date/time pointer or NULL.
+ */
+static xmlSchemaValPtr
+_xmlSchemaDateAdd (xmlSchemaValPtr dt, xmlSchemaValPtr dur)
+{
+ xmlSchemaValPtr ret;
+ long carry, tempdays, temp;
+ xmlSchemaValDatePtr r, d;
+ xmlSchemaValDurationPtr u;
+
+ if ((dt == NULL) || (dur == NULL))
+ return NULL;
+
+ ret = xmlSchemaNewValue(dt->type);
+ if (ret == NULL)
+ return NULL;
+
+ r = &(ret->value.date);
+ d = &(dt->value.date);
+ u = &(dur->value.dur);
+
+ /* normalization */
+ if (d->mon == 0)
+ d->mon = 1;
+
+ /* normalize for time zone offset */
+ u->sec -= (d->tzo * 60);
+ d->tzo = 0;
+
+ /* normalization */
+ if (d->day == 0)
+ d->day = 1;
+
+ /* month */
+ carry = d->mon + u->mon;
+ r->mon = MODULO_RANGE(carry, 1, 13);
+ carry = FQUOTIENT_RANGE(carry, 1, 13);
+
+ /* year (may be modified later) */
+ r->year = d->year + carry;
+ if (r->year == 0) {
+ if (d->year > 0)
+ r->year--;
+ else
+ r->year++;
+ }
+
+ /* time zone */
+ r->tzo = d->tzo;
+ r->tz_flag = d->tz_flag;
+
+ /* seconds */
+ r->sec = d->sec + u->sec;
+ carry = FQUOTIENT((long)r->sec, 60);
+ if (r->sec != 0.0) {
+ r->sec = MODULO(r->sec, 60.0);
+ }
+
+ /* minute */
+ carry += d->min;
+ r->min = MODULO(carry, 60);
+ carry = FQUOTIENT(carry, 60);
+
+ /* hours */
+ carry += d->hour;
+ r->hour = MODULO(carry, 24);
+ carry = FQUOTIENT(carry, 24);
+
+ /*
+ * days
+ * Note we use tempdays because the temporary values may need more
+ * than 5 bits
+ */
+ if ((VALID_YEAR(r->year)) && (VALID_MONTH(r->mon)) &&
+ (d->day > MAX_DAYINMONTH(r->year, r->mon)))
+ tempdays = MAX_DAYINMONTH(r->year, r->mon);
+ else if (d->day < 1)
+ tempdays = 1;
+ else
+ tempdays = d->day;
+
+ tempdays += u->day + carry;
+
+ while (1) {
+ if (tempdays < 1) {
+ long tmon = MODULO_RANGE(r->mon-1, 1, 13);
+ long tyr = r->year + FQUOTIENT_RANGE(r->mon-1, 1, 13);
+ if (tyr == 0)
+ tyr--;
+ tempdays += MAX_DAYINMONTH(tyr, tmon);
+ carry = -1;
+ } else if (tempdays > MAX_DAYINMONTH(r->year, r->mon)) {
+ tempdays = tempdays - MAX_DAYINMONTH(r->year, r->mon);
+ carry = 1;
+ } else
+ break;
+
+ temp = r->mon + carry;
+ r->mon = MODULO_RANGE(temp, 1, 13);
+ r->year = r->year + FQUOTIENT_RANGE(temp, 1, 13);
+ if (r->year == 0) {
+ if (temp < 1)
+ r->year--;
+ else
+ r->year++;
+ }
+ }
+
+ r->day = tempdays;
+
+ /*
+ * adjust the date/time type to the date values
+ */
+ if (ret->type != XML_SCHEMAS_DATETIME) {
+ if ((r->hour) || (r->min) || (r->sec))
+ ret->type = XML_SCHEMAS_DATETIME;
+ else if (ret->type != XML_SCHEMAS_DATE) {
+ if ((r->mon != 1) && (r->day != 1))
+ ret->type = XML_SCHEMAS_DATE;
+ else if ((ret->type != XML_SCHEMAS_GYEARMONTH) && (r->mon != 1))
+ ret->type = XML_SCHEMAS_GYEARMONTH;
+ }
+ }
+
+ return ret;
+}
+
+/**
+ * xmlSchemaDupVal:
+ * @v: value to duplicate
+ *
+ * returns a duplicated value.
+ */
+static xmlSchemaValPtr
+xmlSchemaDupVal (xmlSchemaValPtr v)
+{
+ xmlSchemaValPtr ret = xmlSchemaNewValue(v->type);
+ if (ret == NULL)
+ return ret;
+
+ memcpy(ret, v, sizeof(xmlSchemaVal));
+ return ret;
+}
+
+/**
+ * xmlSchemaDateNormalize:
+ * @dt: an #xmlSchemaValPtr
+ *
+ * Normalize @dt to GMT time.
+ *
+ */
+static xmlSchemaValPtr
+xmlSchemaDateNormalize (xmlSchemaValPtr dt, double offset)
+{
+ xmlSchemaValPtr dur, ret;
+
+ if (dt == NULL)
+ return NULL;
+
+ if (((dt->type != XML_SCHEMAS_TIME) &&
+ (dt->type != XML_SCHEMAS_DATETIME)) || (dt->value.date.tzo == 0))
+ return xmlSchemaDupVal(dt);
+
+ dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
+ if (dur == NULL)
+ return NULL;
+
+ dur->value.date.sec -= offset;
+
+ ret = _xmlSchemaDateAdd(dt, dur);
+ if (ret == NULL)
+ return NULL;
+
+ xmlSchemaFreeValue(dur);
+
+ /* ret->value.date.tzo = 0; */
+ return ret;
+}
+
+/**
+ * _xmlSchemaDateCastYMToDays:
+ * @dt: an #xmlSchemaValPtr
+ *
+ * Convert mon and year of @dt to total number of days. Take the
+ * number of years since (or before) 1 AD and add the number of leap
+ * years. This is a function because negative
+ * years must be handled a little differently and there is no zero year.
+ *
+ * Returns number of days.
+ */
+static long
+_xmlSchemaDateCastYMToDays (const xmlSchemaValPtr dt)
+{
+ long ret;
+
+ if (dt->value.date.year < 0)
+ ret = (dt->value.date.year * 365) +
+ (((dt->value.date.year+1)/4)-((dt->value.date.year+1)/100)+
+ ((dt->value.date.year+1)/400)) +
+ DAY_IN_YEAR(0, dt->value.date.mon, dt->value.date.year);
+ else
+ ret = ((dt->value.date.year-1) * 365) +
+ (((dt->value.date.year-1)/4)-((dt->value.date.year-1)/100)+
+ ((dt->value.date.year-1)/400)) +
+ DAY_IN_YEAR(0, dt->value.date.mon, dt->value.date.year);
+
+ return ret;
+}
+
+/**
+ * TIME_TO_NUMBER:
+ * @dt: an #xmlSchemaValPtr
+ *
+ * Calculates the number of seconds in the time portion of @dt.
+ *
+ * Returns seconds.
+ */
+#define TIME_TO_NUMBER(dt) \
+ ((double)((dt->value.date.hour * SECS_PER_HOUR) + \
+ (dt->value.date.min * SECS_PER_MIN) + \
+ (dt->value.date.tzo * SECS_PER_MIN)) + \
+ dt->value.date.sec)
+
+/**
+ * xmlSchemaCompareDates:
+ * @x: a first date/time value
+ * @y: a second date/time value
+ *
+ * Compare 2 date/times
+ *
+ * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
+ * case of error
+ */
+static int
+xmlSchemaCompareDates (xmlSchemaValPtr x, xmlSchemaValPtr y)
+{
+ unsigned char xmask, ymask, xor_mask, and_mask;
+ xmlSchemaValPtr p1, p2, q1, q2;
+ long p1d, p2d, q1d, q2d;
+
+ if ((x == NULL) || (y == NULL))
+ return -2;
+
+ if (x->value.date.tz_flag) {
+
+ if (!y->value.date.tz_flag) {
+ p1 = xmlSchemaDateNormalize(x, 0);
+ p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
+ /* normalize y + 14:00 */
+ q1 = xmlSchemaDateNormalize(y, (14 * SECS_PER_HOUR));
+
+ q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
+ if (p1d < q1d) {
+ xmlSchemaFreeValue(p1);
+ xmlSchemaFreeValue(q1);
+ return -1;
+ } else if (p1d == q1d) {
+ double sec;
+
+ sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
+ if (sec < 0.0) {
+ xmlSchemaFreeValue(p1);
+ xmlSchemaFreeValue(q1);
+ return -1;
+ } else {
+ int ret = 0;
+ /* normalize y - 14:00 */
+ q2 = xmlSchemaDateNormalize(y, -(14 * SECS_PER_HOUR));
+ q2d = _xmlSchemaDateCastYMToDays(q2) + q2->value.date.day;
+ if (p1d > q2d)
+ ret = 1;
+ else if (p1d == q2d) {
+ sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q2);
+ if (sec > 0.0)
+ ret = 1;
+ else
+ ret = 2; /* indeterminate */
+ }
+ xmlSchemaFreeValue(p1);
+ xmlSchemaFreeValue(q1);
+ xmlSchemaFreeValue(q2);
+ if (ret != 0)
+ return(ret);
+ }
+ } else {
+ xmlSchemaFreeValue(p1);
+ xmlSchemaFreeValue(q1);
+ }
+ }
+ } else if (y->value.date.tz_flag) {
+ q1 = xmlSchemaDateNormalize(y, 0);
+ q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
+
+ /* normalize x - 14:00 */
+ p1 = xmlSchemaDateNormalize(x, -(14 * SECS_PER_HOUR));
+ p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
+
+ if (p1d < q1d) {
+ xmlSchemaFreeValue(p1);
+ xmlSchemaFreeValue(q1);
+ return -1;
+ } else if (p1d == q1d) {
+ double sec;
+
+ sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
+ if (sec < 0.0) {
+ xmlSchemaFreeValue(p1);
+ xmlSchemaFreeValue(q1);
+ return -1;
+ } else {
+ int ret = 0;
+ /* normalize x + 14:00 */
+ p2 = xmlSchemaDateNormalize(x, (14 * SECS_PER_HOUR));
+ p2d = _xmlSchemaDateCastYMToDays(p2) + p2->value.date.day;
+
+ if (p2d > q1d) {
+ ret = 1;
+ } else if (p2d == q1d) {
+ sec = TIME_TO_NUMBER(p2) - TIME_TO_NUMBER(q1);
+ if (sec > 0.0)
+ ret = 1;
+ else
+ ret = 2; /* indeterminate */
+ }
+ xmlSchemaFreeValue(p1);
+ xmlSchemaFreeValue(q1);
+ xmlSchemaFreeValue(p2);
+ if (ret != 0)
+ return(ret);
+ }
+ } else {
+ xmlSchemaFreeValue(p1);
+ xmlSchemaFreeValue(q1);
+ }
+ }
+
+ /*
+ * if the same type then calculate the difference
+ */
+ if (x->type == y->type) {
+ int ret = 0;
+ q1 = xmlSchemaDateNormalize(y, 0);
+ q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
+
+ p1 = xmlSchemaDateNormalize(x, 0);
+ p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
+
+ if (p1d < q1d) {
+ ret = -1;
+ } else if (p1d > q1d) {
+ ret = 1;
+ } else {
+ double sec;
+
+ sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
+ if (sec < 0.0)
+ ret = -1;
+ else if (sec > 0.0)
+ ret = 1;
+
+ }
+ xmlSchemaFreeValue(p1);
+ xmlSchemaFreeValue(q1);
+ return(ret);
+ }
+
+ switch (x->type) {
+ case XML_SCHEMAS_DATETIME:
+ xmask = 0xf;
+ break;
+ case XML_SCHEMAS_DATE:
+ xmask = 0x7;
+ break;
+ case XML_SCHEMAS_GYEAR:
+ xmask = 0x1;
+ break;
+ case XML_SCHEMAS_GMONTH:
+ xmask = 0x2;
+ break;
+ case XML_SCHEMAS_GDAY:
+ xmask = 0x3;
+ break;
+ case XML_SCHEMAS_GYEARMONTH:
+ xmask = 0x3;
+ break;
+ case XML_SCHEMAS_GMONTHDAY:
+ xmask = 0x6;
+ break;
+ case XML_SCHEMAS_TIME:
+ xmask = 0x8;
+ break;
+ default:
+ xmask = 0;
+ break;
+ }
+
+ switch (y->type) {
+ case XML_SCHEMAS_DATETIME:
+ ymask = 0xf;
+ break;
+ case XML_SCHEMAS_DATE:
+ ymask = 0x7;
+ break;
+ case XML_SCHEMAS_GYEAR:
+ ymask = 0x1;
+ break;
+ case XML_SCHEMAS_GMONTH:
+ ymask = 0x2;
+ break;
+ case XML_SCHEMAS_GDAY:
+ ymask = 0x3;
+ break;
+ case XML_SCHEMAS_GYEARMONTH:
+ ymask = 0x3;
+ break;
+ case XML_SCHEMAS_GMONTHDAY:
+ ymask = 0x6;
+ break;
+ case XML_SCHEMAS_TIME:
+ ymask = 0x8;
+ break;
+ default:
+ ymask = 0;
+ break;
+ }
+
+ xor_mask = xmask ^ ymask; /* mark type differences */
+ and_mask = xmask & ymask; /* mark field specification */
+
+ /* year */
+ if (xor_mask & 1)
+ return 2; /* indeterminate */
+ else if (and_mask & 1) {
+ if (x->value.date.year < y->value.date.year)
+ return -1;
+ else if (x->value.date.year > y->value.date.year)
+ return 1;
+ }
+
+ /* month */
+ if (xor_mask & 2)
+ return 2; /* indeterminate */
+ else if (and_mask & 2) {
+ if (x->value.date.mon < y->value.date.mon)
+ return -1;
+ else if (x->value.date.mon > y->value.date.mon)
+ return 1;
+ }
+
+ /* day */
+ if (xor_mask & 4)
+ return 2; /* indeterminate */
+ else if (and_mask & 4) {
+ if (x->value.date.day < y->value.date.day)
+ return -1;
+ else if (x->value.date.day > y->value.date.day)
+ return 1;
+ }
+
+ /* time */
+ if (xor_mask & 8)
+ return 2; /* indeterminate */
+ else if (and_mask & 8) {
+ if (x->value.date.hour < y->value.date.hour)
+ return -1;
+ else if (x->value.date.hour > y->value.date.hour)
+ return 1;
+ else if (x->value.date.min < y->value.date.min)
+ return -1;
+ else if (x->value.date.min > y->value.date.min)
+ return 1;
+ else if (x->value.date.sec < y->value.date.sec)
+ return -1;
+ else if (x->value.date.sec > y->value.date.sec)
+ return 1;
+ }
+
+ return 0;
+}
+
+/**
+ * xmlSchemaCompareNormStrings:
+ * @x: a first string value
+ * @y: a second string value
+ *
+ * Compare 2 string for their normalized values.
+ *
+ * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
+ * case of error
+ */
+static int
+xmlSchemaCompareNormStrings(xmlSchemaValPtr x, xmlSchemaValPtr y) {
+ const xmlChar *utf1;
+ const xmlChar *utf2;
+ int tmp;
+
+ if ((x == NULL) || (y == NULL))
+ return(-2);
+ utf1 = x->value.str;
+ utf2 = y->value.str;
+
+ while (IS_BLANK_CH(*utf1)) utf1++;
+ while (IS_BLANK_CH(*utf2)) utf2++;
+ while ((*utf1 != 0) && (*utf2 != 0)) {
+ if (IS_BLANK_CH(*utf1)) {
+ if (!IS_BLANK_CH(*utf2)) {
+ tmp = *utf1 - *utf2;
+ return(tmp);
+ }
+ while (IS_BLANK_CH(*utf1)) utf1++;
+ while (IS_BLANK_CH(*utf2)) utf2++;
+ } else {
+ tmp = *utf1++ - *utf2++;
+ if (tmp < 0)
+ return(-1);
+ if (tmp > 0)
+ return(1);
+ }
+ }
+ if (*utf1 != 0) {
+ while (IS_BLANK_CH(*utf1)) utf1++;
+ if (*utf1 != 0)
+ return(1);
+ }
+ if (*utf2 != 0) {
+ while (IS_BLANK_CH(*utf2)) utf2++;
+ if (*utf2 != 0)
+ return(-1);
+ }
+ return(0);
+}
+
+/**
+ * xmlSchemaCompareFloats:
+ * @x: a first float or double value
+ * @y: a second float or double value
+ *
+ * Compare 2 values
+ *
+ * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
+ * case of error
+ */
+static int
+xmlSchemaCompareFloats(xmlSchemaValPtr x, xmlSchemaValPtr y) {
+ double d1, d2;
+
+ if ((x == NULL) || (y == NULL))
+ return(-2);
+
+ /*
+ * Cast everything to doubles.
+ */
+ if (x->type == XML_SCHEMAS_DOUBLE)
+ d1 = x->value.d;
+ else if (x->type == XML_SCHEMAS_FLOAT)
+ d1 = x->value.f;
+ else
+ return(-2);
+
+ if (y->type == XML_SCHEMAS_DOUBLE)
+ d2 = y->value.d;
+ else if (y->type == XML_SCHEMAS_FLOAT)
+ d2 = y->value.f;
+ else
+ return(-2);
+
+ /*
+ * Check for special cases.
+ */
+ if (xmlXPathIsNaN(d1)) {
+ if (xmlXPathIsNaN(d2))
+ return(0);
+ return(1);
+ }
+ if (xmlXPathIsNaN(d2))
+ return(-1);
+ if (d1 == xmlXPathPINF) {
+ if (d2 == xmlXPathPINF)
+ return(0);
+ return(1);
+ }
+ if (d2 == xmlXPathPINF)
+ return(-1);
+ if (d1 == xmlXPathNINF) {
+ if (d2 == xmlXPathNINF)
+ return(0);
+ return(-1);
+ }
+ if (d2 == xmlXPathNINF)
+ return(1);
+
+ /*
+ * basic tests, the last one we should have equality, but
+ * portability is more important than speed and handling
+ * NaN or Inf in a portable way is always a challenge, so ...
+ */
+ if (d1 < d2)
+ return(-1);
+ if (d1 > d2)
+ return(1);
+ if (d1 == d2)
+ return(0);
+ return(2);
+}
+
+/**
+ * xmlSchemaCompareValues:
+ * @x: a first value
+ * @y: a second value
+ *
+ * Compare 2 values
+ *
+ * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
+ * case of error
+ */
+int
+xmlSchemaCompareValues(xmlSchemaValPtr x, xmlSchemaValPtr y) {
+ if ((x == NULL) || (y == NULL))
+ return(-2);
+
+ switch (x->type) {
+ case XML_SCHEMAS_UNKNOWN:
+ return(-2);
+ case XML_SCHEMAS_INTEGER:
+ case XML_SCHEMAS_NPINTEGER:
+ case XML_SCHEMAS_NINTEGER:
+ case XML_SCHEMAS_NNINTEGER:
+ case XML_SCHEMAS_PINTEGER:
+ case XML_SCHEMAS_INT:
+ case XML_SCHEMAS_UINT:
+ case XML_SCHEMAS_LONG:
+ case XML_SCHEMAS_ULONG:
+ case XML_SCHEMAS_SHORT:
+ case XML_SCHEMAS_USHORT:
+ case XML_SCHEMAS_BYTE:
+ case XML_SCHEMAS_UBYTE:
+ case XML_SCHEMAS_DECIMAL:
+ if (y->type == x->type)
+ return(xmlSchemaCompareDecimals(x, y));
+ if ((y->type == XML_SCHEMAS_DECIMAL) ||
+ (y->type == XML_SCHEMAS_INTEGER) ||
+ (y->type == XML_SCHEMAS_NPINTEGER) ||
+ (y->type == XML_SCHEMAS_NINTEGER) ||
+ (y->type == XML_SCHEMAS_NNINTEGER) ||
+ (y->type == XML_SCHEMAS_PINTEGER) ||
+ (y->type == XML_SCHEMAS_INT) ||
+ (y->type == XML_SCHEMAS_UINT) ||
+ (y->type == XML_SCHEMAS_LONG) ||
+ (y->type == XML_SCHEMAS_ULONG) ||
+ (y->type == XML_SCHEMAS_SHORT) ||
+ (y->type == XML_SCHEMAS_USHORT) ||
+ (y->type == XML_SCHEMAS_BYTE) ||
+ (y->type == XML_SCHEMAS_UBYTE))
+ return(xmlSchemaCompareDecimals(x, y));
+ return(-2);
+ case XML_SCHEMAS_DURATION:
+ if (y->type == XML_SCHEMAS_DURATION)
+ return(xmlSchemaCompareDurations(x, y));
+ return(-2);
+ case XML_SCHEMAS_TIME:
+ case XML_SCHEMAS_GDAY:
+ case XML_SCHEMAS_GMONTH:
+ case XML_SCHEMAS_GMONTHDAY:
+ case XML_SCHEMAS_GYEAR:
+ case XML_SCHEMAS_GYEARMONTH:
+ case XML_SCHEMAS_DATE:
+ case XML_SCHEMAS_DATETIME:
+ if ((y->type == XML_SCHEMAS_DATETIME) ||
+ (y->type == XML_SCHEMAS_TIME) ||
+ (y->type == XML_SCHEMAS_GDAY) ||
+ (y->type == XML_SCHEMAS_GMONTH) ||
+ (y->type == XML_SCHEMAS_GMONTHDAY) ||
+ (y->type == XML_SCHEMAS_GYEAR) ||
+ (y->type == XML_SCHEMAS_DATE) ||
+ (y->type == XML_SCHEMAS_GYEARMONTH))
+ return (xmlSchemaCompareDates(x, y));
+ return (-2);
+ case XML_SCHEMAS_NORMSTRING:
+ case XML_SCHEMAS_TOKEN:
+ case XML_SCHEMAS_LANGUAGE:
+ case XML_SCHEMAS_NMTOKEN:
+ case XML_SCHEMAS_NAME:
+ case XML_SCHEMAS_NCNAME:
+ case XML_SCHEMAS_ID:
+ case XML_SCHEMAS_IDREF:
+ case XML_SCHEMAS_ENTITY:
+ case XML_SCHEMAS_NOTATION:
+ case XML_SCHEMAS_ANYURI:
+ if ((y->type == XML_SCHEMAS_NORMSTRING) ||
+ (y->type == XML_SCHEMAS_TOKEN) ||
+ (y->type == XML_SCHEMAS_LANGUAGE) ||
+ (y->type == XML_SCHEMAS_NMTOKEN) ||
+ (y->type == XML_SCHEMAS_NAME) ||
+ (y->type == XML_SCHEMAS_QNAME) ||
+ (y->type == XML_SCHEMAS_NCNAME) ||
+ (y->type == XML_SCHEMAS_ID) ||
+ (y->type == XML_SCHEMAS_IDREF) ||
+ (y->type == XML_SCHEMAS_ENTITY) ||
+ (y->type == XML_SCHEMAS_NOTATION) ||
+ (y->type == XML_SCHEMAS_ANYURI))
+ return (xmlSchemaCompareNormStrings(x, y));
+ return (-2);
+ case XML_SCHEMAS_QNAME:
+ if (y->type == XML_SCHEMAS_QNAME) {
+ if ((xmlStrEqual(x->value.qname.name, y->value.qname.name)) &&
+ (xmlStrEqual(x->value.qname.uri, y->value.qname.uri)))
+ return(0);
+ return(2);
+ }
+ return (-2);
+ case XML_SCHEMAS_FLOAT:
+ case XML_SCHEMAS_DOUBLE:
+ if ((y->type == XML_SCHEMAS_FLOAT) ||
+ (y->type == XML_SCHEMAS_DOUBLE))
+ return (xmlSchemaCompareFloats(x, y));
+ return (-2);
+ case XML_SCHEMAS_BOOLEAN:
+ if (y->type == XML_SCHEMAS_BOOLEAN) {
+ if (x->value.b == y->value.b)
+ return(0);
+ if (x->value.b == 0)
+ return(-1);
+ return(1);
+ }
+ return (-2);
+ case XML_SCHEMAS_HEXBINARY:
+ if (y->type == XML_SCHEMAS_HEXBINARY) {
+ if (x->value.hex.total == y->value.hex.total) {
+ int ret = xmlStrcmp(x->value.hex.str, y->value.hex.str);
+ if (ret > 0)
+ return(1);
+ else if (ret == 0)
+ return(0);
+ }
+ else if (x->value.hex.total > y->value.hex.total)
+ return(1);
+
+ return(-1);
+ }
+ return (-2);
+ case XML_SCHEMAS_BASE64BINARY:
+ if (y->type == XML_SCHEMAS_BASE64BINARY) {
+ if (x->value.base64.total == y->value.base64.total) {
+ int ret = xmlStrcmp(x->value.base64.str,
+ y->value.base64.str);
+ if (ret > 0)
+ return(1);
+ else if (ret == 0)
+ return(0);
+ }
+ else if (x->value.base64.total > y->value.base64.total)
+ return(1);
+ else
+ return(-1);
+ }
+ return (-2);
+ case XML_SCHEMAS_STRING:
+ case XML_SCHEMAS_IDREFS:
+ case XML_SCHEMAS_ENTITIES:
+ case XML_SCHEMAS_NMTOKENS:
+ TODO
+ break;
+ }
+ return -2;
+}
+
+/**
+ * xmlSchemaNormLen:
+ * @value: a string
+ *
+ * Computes the UTF8 length of the normalized value of the string
+ *
+ * Returns the length or -1 in case of error.
+ */
+static int
+xmlSchemaNormLen(const xmlChar *value) {
+ const xmlChar *utf;
+ int ret = 0;
+
+ if (value == NULL)
+ return(-1);
+ utf = value;
+ while (IS_BLANK_CH(*utf)) utf++;
+ while (*utf != 0) {
+ if (utf[0] & 0x80) {
+ if ((utf[1] & 0xc0) != 0x80)
+ return(-1);
+ if ((utf[0] & 0xe0) == 0xe0) {
+ if ((utf[2] & 0xc0) != 0x80)
+ return(-1);
+ if ((utf[0] & 0xf0) == 0xf0) {
+ if ((utf[0] & 0xf8) != 0xf0 || (utf[3] & 0xc0) != 0x80)
+ return(-1);
+ utf += 4;
+ } else {
+ utf += 3;
+ }
+ } else {
+ utf += 2;
+ }
+ } else if (IS_BLANK_CH(*utf)) {
+ while (IS_BLANK_CH(*utf)) utf++;
+ if (*utf == 0)
+ break;
+ } else {
+ utf++;
+ }
+ ret++;
+ }
+ return(ret);
+}
+
+/**
+ * xmlSchemaValidateFacet:
+ * @base: the base type
+ * @facet: the facet to check
+ * @value: the lexical repr of the value to validate
+ * @val: the precomputed value
+ *
+ * Check a value against a facet condition
+ *
+ * Returns 0 if the element is schemas valid, a positive error code
+ * number otherwise and -1 in case of internal or API error.
+ */
+int
+xmlSchemaValidateFacet(xmlSchemaTypePtr base ATTRIBUTE_UNUSED,
+ xmlSchemaFacetPtr facet,
+ const xmlChar *value, xmlSchemaValPtr val)
+{
+ int ret;
+
+ switch (facet->type) {
+ case XML_SCHEMA_FACET_PATTERN:
+ ret = xmlRegexpExec(facet->regexp, value);
+ if (ret == 1)
+ return(0);
+ if (ret == 0) {
+ /* TODO error code */
+ return(1);
+ }
+ return(ret);
+ case XML_SCHEMA_FACET_MAXEXCLUSIVE:
+ ret = xmlSchemaCompareValues(val, facet->val);
+ if (ret == -2) {
+ /* TODO error code */
+ return(-1);
+ }
+ if (ret == -1)
+ return(0);
+ /* error code */
+ return(1);
+ case XML_SCHEMA_FACET_MAXINCLUSIVE:
+ ret = xmlSchemaCompareValues(val, facet->val);
+ if (ret == -2) {
+ /* TODO error code */
+ return(-1);
+ }
+ if ((ret == -1) || (ret == 0))
+ return(0);
+ /* error code */
+ return(1);
+ case XML_SCHEMA_FACET_MINEXCLUSIVE:
+ ret = xmlSchemaCompareValues(val, facet->val);
+ if (ret == -2) {
+ /* TODO error code */
+ return(-1);
+ }
+ if (ret == 1)
+ return(0);
+ /* error code */
+ return(1);
+ case XML_SCHEMA_FACET_MININCLUSIVE:
+ ret = xmlSchemaCompareValues(val, facet->val);
+ if (ret == -2) {
+ /* TODO error code */
+ return(-1);
+ }
+ if ((ret == 1) || (ret == 0))
+ return(0);
+ /* error code */
+ return(1);
+ case XML_SCHEMA_FACET_WHITESPACE:
+ /* TODO whitespaces */
+ return(0);
+ case XML_SCHEMA_FACET_ENUMERATION:
+ if ((facet->value != NULL) &&
+ (xmlStrEqual(facet->value, value)))
+ return(0);
+ return(1);
+ case XML_SCHEMA_FACET_LENGTH:
+ case XML_SCHEMA_FACET_MAXLENGTH:
+ case XML_SCHEMA_FACET_MINLENGTH: {
+ unsigned int len = 0;
+
+ if ((facet->val == NULL) ||
+ ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
+ (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
+ (facet->val->value.decimal.frac != 0)) {
+ return(-1);
+ }
+ if ((val != NULL) && (val->type == XML_SCHEMAS_HEXBINARY))
+ len = val->value.hex.total;
+ else if ((val != NULL) && (val->type == XML_SCHEMAS_BASE64BINARY))
+ len = val->value.base64.total;
+ else {
+ switch (base->flags) {
+ case XML_SCHEMAS_IDREF:
+ case XML_SCHEMAS_NORMSTRING:
+ case XML_SCHEMAS_TOKEN:
+ case XML_SCHEMAS_LANGUAGE:
+ case XML_SCHEMAS_NMTOKEN:
+ case XML_SCHEMAS_NAME:
+ case XML_SCHEMAS_NCNAME:
+ case XML_SCHEMAS_ID:
+ len = xmlSchemaNormLen(value);
+ break;
+ case XML_SCHEMAS_STRING:
+ if (value != NULL)
+ len = xmlUTF8Strlen(value);
+ break;
+ default:
+ TODO
+ }
+ }
+ if (facet->type == XML_SCHEMA_FACET_LENGTH) {
+ if (len != facet->val->value.decimal.lo)
+ return(1);
+ } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
+ if (len < facet->val->value.decimal.lo)
+ return(1);
+ } else {
+ if (len > facet->val->value.decimal.lo)
+ return(1);
+ }
+ break;
+ }
+ case XML_SCHEMA_FACET_TOTALDIGITS:
+ case XML_SCHEMA_FACET_FRACTIONDIGITS:
+
+ if ((facet->val == NULL) ||
+ ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
+ (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
+ (facet->val->value.decimal.frac != 0)) {
+ return(-1);
+ }
+ if ((val == NULL) ||
+ ((val->type != XML_SCHEMAS_DECIMAL) &&
+ (val->type != XML_SCHEMAS_INTEGER) &&
+ (val->type != XML_SCHEMAS_NPINTEGER) &&
+ (val->type != XML_SCHEMAS_NINTEGER) &&
+ (val->type != XML_SCHEMAS_NNINTEGER) &&
+ (val->type != XML_SCHEMAS_PINTEGER) &&
+ (val->type != XML_SCHEMAS_INT) &&
+ (val->type != XML_SCHEMAS_UINT) &&
+ (val->type != XML_SCHEMAS_LONG) &&
+ (val->type != XML_SCHEMAS_ULONG) &&
+ (val->type != XML_SCHEMAS_SHORT) &&
+ (val->type != XML_SCHEMAS_USHORT) &&
+ (val->type != XML_SCHEMAS_BYTE) &&
+ (val->type != XML_SCHEMAS_UBYTE))) {
+ return(-1);
+ }
+ if (facet->type == XML_SCHEMA_FACET_TOTALDIGITS) {
+ if (val->value.decimal.total > facet->val->value.decimal.lo)
+ return(1);
+
+ } else if (facet->type == XML_SCHEMA_FACET_FRACTIONDIGITS) {
+ if (val->value.decimal.frac > facet->val->value.decimal.lo)
+ return(1);
+ }
+ break;
+ default:
+ TODO
+ }
+ return(0);
+
+}
+
+#endif /* LIBXML_SCHEMAS_ENABLED */