/* * schemastypes.c : implementation of the XML Schema Datatypes * definition and validity checking * * See Copyright for the status of this software. * * Daniel Veillard */ #define IN_LIBXML #include "libxml.h" #ifdef LIBXML_SCHEMAS_ENABLED #include #include #include #include #include #include #include #include #include #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_NMTOKEN, XML_SCHEMAS_DECIMAL, XML_SCHEMAS_, XML_SCHEMAS_XXX } xmlSchemaValType; unsigned long powten[10] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000L, 100000000L, 1000000000L }; typedef struct _xmlSchemaValDecimal xmlSchemaValDecimal; typedef xmlSchemaValDecimal *xmlSchemaValDecimalPtr; struct _xmlSchemaValDecimal { /* would use long long but not portable */ unsigned long base; unsigned int extra; int sign:1; int frac:7; int total:8; }; struct _xmlSchemaVal { xmlSchemaValType type; union { xmlSchemaValDecimal decimal; } value; }; static int xmlSchemaTypesInitialized = 0; static xmlHashTablePtr xmlSchemaTypesBank = NULL; static xmlSchemaTypePtr xmlSchemaTypeStringDef = NULL; static xmlSchemaTypePtr xmlSchemaTypeAnyTypeDef = NULL; static xmlSchemaTypePtr xmlSchemaTypeAnySimpleTypeDef = NULL; static xmlSchemaTypePtr xmlSchemaTypeDecimalDef = NULL; static xmlSchemaTypePtr xmlSchemaTypeDateDef = NULL; static xmlSchemaTypePtr xmlSchemaTypePositiveIntegerDef = NULL; static xmlSchemaTypePtr xmlSchemaTypeNonNegativeIntegerDef = NULL; static xmlSchemaTypePtr xmlSchemaTypeNmtoken = NULL; /* * xmlSchemaInitBasicType: * @name: the type name * * Initialize one default type */ static xmlSchemaTypePtr xmlSchemaInitBasicType(const char *name) { xmlSchemaTypePtr ret; ret = (xmlSchemaTypePtr) xmlMalloc(sizeof(xmlSchemaType)); if (ret == NULL) { xmlGenericError(xmlGenericErrorContext, "Could not initilize type %s: out of memory\n", name); return(NULL); } memset(ret, 0, sizeof(xmlSchemaType)); ret->name = xmlStrdup((const xmlChar *)name); ret->type = XML_SCHEMA_TYPE_BASIC; 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); xmlSchemaTypeStringDef = xmlSchemaInitBasicType("string"); xmlSchemaTypeAnyTypeDef = xmlSchemaInitBasicType("anyType"); xmlSchemaTypeAnySimpleTypeDef = xmlSchemaInitBasicType("anySimpleType"); xmlSchemaTypeDecimalDef = xmlSchemaInitBasicType("decimal"); xmlSchemaTypeDateDef = xmlSchemaInitBasicType("date"); xmlSchemaTypePositiveIntegerDef = xmlSchemaInitBasicType("positiveInteger"); xmlSchemaTypeNonNegativeIntegerDef = xmlSchemaInitBasicType("nonNegativeInteger"); xmlSchemaTypeNmtoken = xmlSchemaInitBasicType("NMTOKEN"); 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; 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)); } /** * 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) { xmlSchemaValPtr v; if (xmlSchemaTypesInitialized == 0) return(-1); if (type == NULL) return(-1); if (val != NULL) *val = NULL; if (type == xmlSchemaTypeStringDef) { return(0); } else if (type == xmlSchemaTypeAnyTypeDef) { return(0); } else if (type == xmlSchemaTypeAnySimpleTypeDef) { return(0); } else if (type == xmlSchemaTypeNmtoken) { if (xmlValidateNmtokenValue(value)) return(0); return(1); } else if (type == xmlSchemaTypeDecimalDef) { const xmlChar *cur = value, *tmp; int frac = 0, main, neg = 0; unsigned long base = 0; if (cur == NULL) return(1); if (*cur == '+') cur++; else if (*cur == '-') { neg = 1; cur++; } tmp = cur; while ((*cur >= '0') && (*cur <= '9')) { base = base * 10 + (*cur - '0'); cur++; } main = cur - tmp; if (*cur == '.') { cur++; tmp = cur; while ((*cur >= '0') && (*cur <= '9')) { base = base * 10 + (*cur - '0'); cur++; } frac = cur - tmp; } if (*cur != 0) return(1); if (val != NULL) { v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL); if (v != NULL) { v->value.decimal.base = base; v->value.decimal.sign = neg; v->value.decimal.frac = frac; v->value.decimal.total = frac + main; *val = v; } } return(0); } else if (type == xmlSchemaTypeDateDef) { const xmlChar *cur = value; if (cur == NULL) return(1); if (*cur == '-') cur++; if ((*cur < '0') || (*cur > '9')) return(1); if ((*cur < '0') || (*cur > '9')) return(1); if ((*cur < '0') || (*cur > '9')) return(1); if ((*cur < '0') || (*cur > '9')) return(1); while ((*cur >= '0') && (*cur <= '9')) cur++; if (*cur != '-') return(1); cur++; if ((*cur != '0') && (*cur != '1')) return(1); if ((*cur == '0') && (cur[1] == '0')) return(1); if ((*cur == '1') && ((cur[1] < '0') || (cur[1] > '2'))) return(1); cur += 2; if (*cur != '-') return(1); cur++; if ((*cur < '0') || (*cur > '3')) return(1); if ((*cur == '0') && (cur[1] == '0')) return(1); if ((*cur == '3') && ((cur[1] < '0') || (cur[1] > '1'))) return(1); cur += 2; if (*cur != 0) return(1); return(0); } else if (type == xmlSchemaTypePositiveIntegerDef) { const xmlChar *cur = value; unsigned long base = 0; int total = 0; if (cur == NULL) return(1); if (*cur == '+') cur++; while ((*cur >= '0') && (*cur <= '9')) { base = base * 10 + (*cur - '0'); total++; cur++; } if (*cur != 0) return(1); if (val != NULL) { v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL); if (v != NULL) { v->value.decimal.base = base; v->value.decimal.sign = 0; v->value.decimal.frac = 0; v->value.decimal.total = total; *val = v; } } return(0); } else if (type == xmlSchemaTypeNonNegativeIntegerDef) { const xmlChar *cur = value; unsigned long base = 0; int total = 0; int sign = 0; if (cur == NULL) return(1); if (*cur == '-') { sign = 1; cur++; } else if (*cur == '+') cur++; while ((*cur >= '0') && (*cur <= '9')) { base = base * 10 + (*cur - '0'); total++; cur++; } if (*cur != 0) return(1); if ((sign == 1) && (base != 0)) return(1); if (val != NULL) { v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL); if (v != NULL) { v->value.decimal.base = base; v->value.decimal.sign = 0; v->value.decimal.frac = 0; v->value.decimal.total = total; *val = v; } } return(0); } else { TODO return(0); } } /** * 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; unsigned long tmp; if ((x->value.decimal.sign) && (x->value.decimal.sign)) order = -1; else if (x->value.decimal.sign) return (-1); else if (y->value.decimal.sign) return (1); if (x->value.decimal.frac == y->value.decimal.frac) { if (x->value.decimal.base < y->value.decimal.base) return (-1); return (x->value.decimal.base > y->value.decimal.base); } if (y->value.decimal.frac > x->value.decimal.frac) { swp = y; y = x; x = swp; order = -order; } tmp = x->value.decimal.base / powten[x->value.decimal.frac - y->value.decimal.frac]; if (tmp > y->value.decimal.base) return (order); if (tmp < y->value.decimal.base) return (-order); tmp = y->value.decimal.base * powten[x->value.decimal.frac - y->value.decimal.frac]; if (x->value.decimal.base < tmp) return (-order); if (x->value.decimal.base == tmp) return (0); return (order); } /** * 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 and -2 in case of error */ static int xmlSchemaCompareValues(xmlSchemaValPtr x, xmlSchemaValPtr y) { if ((x == NULL) || (y == NULL)) return(-2); switch (x->type) { case XML_SCHEMAS_STRING: TODO case XML_SCHEMAS_DECIMAL: if (y->type == XML_SCHEMAS_DECIMAL) return(xmlSchemaCompareDecimals(x, y)); else return(-2); default: TODO } } /** * xmlSchemaValidateFacet: * @type: the type declaration * @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, 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); TODO /* error code */ return(1); case XML_SCHEMA_FACET_WHITESPACE: TODO /* whitespaces */ return(0); case XML_SCHEMA_FACET_MAXLENGTH: if ((facet->val != NULL) && (facet->val->type == XML_SCHEMAS_DECIMAL) && (facet->val->value.decimal.frac == 0)) { int len; if (facet->val->value.decimal.sign == 1) return(1); len = xmlUTF8Strlen(value); if (len > facet->val->value.decimal.base) return(1); return(0); } TODO /* error code */ return(1); case XML_SCHEMA_FACET_ENUMERATION: if ((facet->value != NULL) && (xmlStrEqual(facet->value, value))) return(0); return(1); default: TODO } return(0); } #endif /* LIBXML_SCHEMAS_ENABLED */