1
0
mirror of https://gitlab.gnome.org/GNOME/libxml2.git synced 2025-02-02 21:47:01 +03:00

patch Charles Bozeman for validation of all the date, time, and duration

* xmlschemastypes.c: patch Charles Bozeman for validation of
  all the date, time, and duration types
* test/schemas/dur_0* result/schemas/dur_0*: associated tests
* configure.in: fixed an error pointed by an user
* xml2-config.in: fixed an error pointed by an user
Daniel
This commit is contained in:
Daniel Veillard 2002-05-03 07:29:38 +00:00
parent e6d8e20c97
commit 070803b315
8 changed files with 1115 additions and 40 deletions

View File

@ -1,3 +1,11 @@
Fri May 3 09:20:41 CEST 2002 Daniel Veillard <daniel@veillard.com>
* xmlschemastypes.c: patch Charles Bozeman for validation of
all the date, time, and duration types
* test/schemas/dur_0* result/schemas/dur_0*: associated tests
* configure.in: fixed an error pointed by an user
* xml2-config.in: fixed an error pointed by an user
Wed 01 May 2002 11:29:27 AM PDT Aleksey Sanin <aleksey@aleksey.com>
* include/libxml/xmlIO.h win32/dsp/libxml2.def.src

View File

@ -425,6 +425,7 @@ if test "$with_xpath" = "no" ; then
echo Disabling XPATH support
with_xptr="no"
with_c14n="no"
with_xinclude="no"
WITH_XPATH=0
XPATH_OBJ=
else

1
result/schemas/dur_0_0 Normal file
View File

@ -0,0 +1 @@
./test/schemas/dur_0.xml validates

196
result/schemas/dur_0_0.err Normal file
View File

@ -0,0 +1,196 @@
compilation error: file ./test/schemas/dur_0.xsd line 67 element minOccurs
Restriction restriction 16 has unexpected content
compilation error
Schemas: element year2 have both type and subtype
compilation error
Schemas: element second1 have both type and subtype
compilation error
Schemas: element second2 have both type and subtype
compilation error
Schemas: element month1 have both type and subtype
compilation error
Schemas: element month2 have both type and subtype
compilation error
Schemas: element year1 have both type and subtype
Type of restriction 15 : ./test/schemas/dur_0.xsd:55 :empty
Type of restriction 5 : ./test/schemas/dur_0.xsd:14 :empty
Type of simpletype14 : ./test/schemas/dur_0.xsd:54 :simple
Type of restriction 16 : ./test/schemas/dur_0.xsd:66 :empty
Type of choice 3 : ./test/schemas/dur_0.xsd:11 :elements
Type of simpletype4 : ./test/schemas/dur_0.xsd:13 :simple
Type of restriction 7 : ./test/schemas/dur_0.xsd:22 :empty
Type of simpletype6 : ./test/schemas/dur_0.xsd:21 :simple
Type of restriction 9 : ./test/schemas/dur_0.xsd:30 :empty
Type of simpletype8 : ./test/schemas/dur_0.xsd:29 :simple
Type of restriction 11 : ./test/schemas/dur_0.xsd:38 :empty
Type of sequence 2 : ./test/schemas/dur_0.xsd:10 :elements
Type of anontype1 : ./test/schemas/dur_0.xsd:9 :elements
Type of simpletype10 : ./test/schemas/dur_0.xsd:37 :simple
Type of restriction 13 : ./test/schemas/dur_0.xsd:47 :empty
Type of MSD : ./test/schemas/dur_0.xsd:65 :simple
Type of sequence 2 : ./test/schemas/dur_0.xsd:10 :elements
Type of simpletype12 : ./test/schemas/dur_0.xsd:46 :simple
Building content model for duration
Content model of duration:
regexp: '(null)'
7 atoms:
00 atom: string once 'second1'
01 atom: string once 'second2'
02 atom: string once 'month1'
03 atom: string once 'month2'
04 atom: string once 'month3'
05 atom: string once 'year1'
06 atom: string once 'year2'
10 states:
state: 0, 7 transitions:
trans: atom 0, to 3
trans: atom 1, to 4
trans: atom 2, to 5
trans: atom 3, to 6
trans: atom 4, to 7
trans: atom 5, to 8
trans: atom 6, to 9
state: FINAL 1, 0 transitions:
state: 2, 9 transitions:
trans: removed
trans: count based 0, epsilon to 1
trans: counted 0, atom 0, to 3
trans: counted 0, atom 1, to 4
trans: counted 0, atom 2, to 5
trans: counted 0, atom 3, to 6
trans: counted 0, atom 4, to 7
trans: counted 0, atom 5, to 8
trans: counted 0, atom 6, to 9
state: 3, 16 transitions:
trans: removed
trans: counted 0, atom 0, to 3
trans: counted 0, atom 1, to 4
trans: counted 0, atom 2, to 5
trans: counted 0, atom 3, to 6
trans: counted 0, atom 4, to 7
trans: counted 0, atom 5, to 8
trans: counted 0, atom 6, to 9
trans: count based 0, epsilon to 1
trans: counted 0, atom 0, to 3
trans: counted 0, atom 1, to 4
trans: counted 0, atom 2, to 5
trans: counted 0, atom 3, to 6
trans: counted 0, atom 4, to 7
trans: counted 0, atom 5, to 8
trans: counted 0, atom 6, to 9
state: 4, 16 transitions:
trans: removed
trans: counted 0, atom 0, to 3
trans: counted 0, atom 1, to 4
trans: counted 0, atom 2, to 5
trans: counted 0, atom 3, to 6
trans: counted 0, atom 4, to 7
trans: counted 0, atom 5, to 8
trans: counted 0, atom 6, to 9
trans: count based 0, epsilon to 1
trans: counted 0, atom 0, to 3
trans: counted 0, atom 1, to 4
trans: counted 0, atom 2, to 5
trans: counted 0, atom 3, to 6
trans: counted 0, atom 4, to 7
trans: counted 0, atom 5, to 8
trans: counted 0, atom 6, to 9
state: 5, 16 transitions:
trans: removed
trans: counted 0, atom 0, to 3
trans: counted 0, atom 1, to 4
trans: counted 0, atom 2, to 5
trans: counted 0, atom 3, to 6
trans: counted 0, atom 4, to 7
trans: counted 0, atom 5, to 8
trans: counted 0, atom 6, to 9
trans: count based 0, epsilon to 1
trans: counted 0, atom 0, to 3
trans: counted 0, atom 1, to 4
trans: counted 0, atom 2, to 5
trans: counted 0, atom 3, to 6
trans: counted 0, atom 4, to 7
trans: counted 0, atom 5, to 8
trans: counted 0, atom 6, to 9
state: 6, 16 transitions:
trans: removed
trans: counted 0, atom 0, to 3
trans: counted 0, atom 1, to 4
trans: counted 0, atom 2, to 5
trans: counted 0, atom 3, to 6
trans: counted 0, atom 4, to 7
trans: counted 0, atom 5, to 8
trans: counted 0, atom 6, to 9
trans: count based 0, epsilon to 1
trans: counted 0, atom 0, to 3
trans: counted 0, atom 1, to 4
trans: counted 0, atom 2, to 5
trans: counted 0, atom 3, to 6
trans: counted 0, atom 4, to 7
trans: counted 0, atom 5, to 8
trans: counted 0, atom 6, to 9
state: 7, 16 transitions:
trans: removed
trans: counted 0, atom 0, to 3
trans: counted 0, atom 1, to 4
trans: counted 0, atom 2, to 5
trans: counted 0, atom 3, to 6
trans: counted 0, atom 4, to 7
trans: counted 0, atom 5, to 8
trans: counted 0, atom 6, to 9
trans: count based 0, epsilon to 1
trans: counted 0, atom 0, to 3
trans: counted 0, atom 1, to 4
trans: counted 0, atom 2, to 5
trans: counted 0, atom 3, to 6
trans: counted 0, atom 4, to 7
trans: counted 0, atom 5, to 8
trans: counted 0, atom 6, to 9
state: 8, 16 transitions:
trans: removed
trans: counted 0, atom 0, to 3
trans: counted 0, atom 1, to 4
trans: counted 0, atom 2, to 5
trans: counted 0, atom 3, to 6
trans: counted 0, atom 4, to 7
trans: counted 0, atom 5, to 8
trans: counted 0, atom 6, to 9
trans: count based 0, epsilon to 1
trans: counted 0, atom 0, to 3
trans: counted 0, atom 1, to 4
trans: counted 0, atom 2, to 5
trans: counted 0, atom 3, to 6
trans: counted 0, atom 4, to 7
trans: counted 0, atom 5, to 8
trans: counted 0, atom 6, to 9
state: 9, 16 transitions:
trans: removed
trans: counted 0, atom 0, to 3
trans: counted 0, atom 1, to 4
trans: counted 0, atom 2, to 5
trans: counted 0, atom 3, to 6
trans: counted 0, atom 4, to 7
trans: counted 0, atom 5, to 8
trans: counted 0, atom 6, to 9
trans: count based 0, epsilon to 1
trans: counted 0, atom 0, to 3
trans: counted 0, atom 1, to 4
trans: counted 0, atom 2, to 5
trans: counted 0, atom 3, to 6
trans: counted 0, atom 4, to 7
trans: counted 0, atom 5, to 8
trans: counted 0, atom 6, to 9
1 counters:
0: min 0 max 1073741823
xmlSchemaValidateCallback: second1, second1, second1
xmlSchemaValidateCallback: second2, second2, second2
xmlSchemaValidateCallback: second2, second2, second2
xmlSchemaValidateCallback: month1, month1, month1
xmlSchemaValidateCallback: month1, month1, month1
xmlSchemaValidateCallback: month2, month2, month2
xmlSchemaValidateCallback: year1, year1, year1
xmlSchemaValidateCallback: year1, year1, year1
Unimplemented block at xmlschemastypes.c:1253
xmlSchemaValidateCallback: year2, year2, year2
xmlSchemaValidateCallback: month3, month3, month3
Element duration content check succeeded

13
test/schemas/dur_0.xml Normal file
View File

@ -0,0 +1,13 @@
<?xml version="1.0"?>
<duration>
<second1>PT0.9S</second1>
<second2>PT0.1S</second2>
<second2>PT0.999999S</second2>
<month1>P0Y27D</month1>
<month1>P27DT23H59M59S</month1>
<month2>P0Y</month2>
<year1>P366DT23H59M59S</year1>
<year1>P12M</year1>
<year2>P12M</year2>
<month3>PT86400S</month3>
</duration>

73
test/schemas/dur_0.xsd Normal file
View File

@ -0,0 +1,73 @@
<?xml version="1.0"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:annotation>
<xsd:documentation xml:lang="en">
Testing duration data types
</xsd:documentation>
</xsd:annotation>
<xsd:element name="duration">
<xsd:complexType>
<xsd:sequence>
<xsd:choice minOccurs="1" maxOccurs="unbounded">
<xsd:element name="second1" type="xsd:duration">
<xsd:simpleType>
<xsd:restriction base="xsd:duration">
<xsd:maxExclusive value="PT1S"/>
<xsd:minExclusive value="PT0.1S"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="second2" type="xsd:duration">
<xsd:simpleType>
<xsd:restriction base="xsd:duration">
<xsd:maxInclusive value="PT1S"/>
<xsd:minInclusive value="PT0.1S"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="month1" type="xsd:duration">
<xsd:simpleType>
<xsd:restriction base="xsd:duration">
<xsd:maxExclusive value="P1M"/>
<xsd:minExclusive value="P0M"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="month2" type="xsd:duration">
<xsd:simpleType>
<xsd:restriction base="xsd:duration">
<xsd:maxInclusive value="P1M"/>
<xsd:minInclusive value="P0M"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="month3" type="MSD"/>
<xsd:element name="year1" type="xsd:duration">
<xsd:simpleType>
<xsd:restriction base="xsd:duration">
<xsd:maxExclusive value="P2Y"/>
<xsd:minExclusive value="P1Y"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="year2" type="xsd:duration">
<xsd:simpleType>
<xsd:restriction base="xsd:duration">
<xsd:maxInclusive value="P2Y"/>
<xsd:minInclusive value="P1Y"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
</xsd:choice>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:simpleType name="MSD">
<xsd:restriction base="xsd:duration">
<xsd:minOccurs value="0"/>
<xsd:maxExclusive value="PT24H"/>
<xsd:minExclusive value="-PT24H"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:schema>

View File

@ -8,7 +8,7 @@ libdir=@libdir@
usage()
{
cat <<EOF
Usage: xml-config [OPTION]
Usage: xml2-config [OPTION]
Known values for OPTION are:
@ -38,6 +38,8 @@ while test $# -gt 0; do
case "$1" in
--prefix=*)
prefix=$optarg
includedir=$prefix/include
libdir=$prefix/lib
;;
--prefix)

View File

@ -23,6 +23,10 @@
#include <libxml/schemasInternals.h>
#include <libxml/xmlschemastypes.h>
#ifdef HAVE_MATH_H
#include <math.h>
#endif
#define DEBUG
#define TODO \
@ -38,6 +42,15 @@ typedef enum {
XML_SCHEMAS_STRING,
XML_SCHEMAS_NMTOKEN,
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_,
XML_SCHEMAS_XXX
} xmlSchemaValType;
@ -47,6 +60,29 @@ unsigned long powten[10] = {
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;
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 {
@ -62,6 +98,8 @@ struct _xmlSchemaVal {
xmlSchemaValType type;
union {
xmlSchemaValDecimal decimal;
xmlSchemaValDate date;
xmlSchemaValDuration dur;
} value;
};
@ -72,7 +110,15 @@ 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 xmlSchemaTypePositiveIntegerDef = NULL;
static xmlSchemaTypePtr xmlSchemaTypeNonNegativeIntegerDef = NULL;
static xmlSchemaTypePtr xmlSchemaTypeNmtoken = NULL;
@ -118,6 +164,14 @@ xmlSchemaInitTypes(void) {
xmlSchemaTypeAnySimpleTypeDef = xmlSchemaInitBasicType("anySimpleType");
xmlSchemaTypeDecimalDef = xmlSchemaInitBasicType("decimal");
xmlSchemaTypeDateDef = xmlSchemaInitBasicType("date");
xmlSchemaTypeDatetimeDef = xmlSchemaInitBasicType("dateTime");
xmlSchemaTypeTimeDef = xmlSchemaInitBasicType("time");
xmlSchemaTypeGYearDef = xmlSchemaInitBasicType("gYear");
xmlSchemaTypeGYearMonthDef = xmlSchemaInitBasicType("gYearMonth");
xmlSchemaTypeGMonthDef = xmlSchemaInitBasicType("gMonth");
xmlSchemaTypeGMonthDayDef = xmlSchemaInitBasicType("gMonthDay");
xmlSchemaTypeGDayDef = xmlSchemaInitBasicType("gDay");
xmlSchemaTypeDurationDef = xmlSchemaInitBasicType("duration");
xmlSchemaTypePositiveIntegerDef = xmlSchemaInitBasicType("positiveInteger");
xmlSchemaTypeNonNegativeIntegerDef =
xmlSchemaInitBasicType("nonNegativeInteger");
@ -190,6 +244,645 @@ xmlSchemaGetPredefinedType(const xmlChar *name, const xmlChar *ns) {
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 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)
/**
* _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;
break;
}
default:
return 1;
}
*str = cur;
return 0;
}
/****************************************************************
* *
* 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++; \
} \
}
/**
* xmlSchemaParseDates:
* @type: the predefined type
* @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
xmlSchemaParseDates (xmlSchemaTypePtr 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; \
if (val != NULL) \
*val = dt; \
return 0; \
} \
}
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 == '-') {
++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;
if (*cur != '-')
goto error;
cur++;
/* is it an xs:gMonth? */
if (*cur == '-') {
cur++;
RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTH);
goto error;
}
/* it should be an xs:gMonthDay */
ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
if (ret != 0)
goto error;
RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTHDAY);
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;
if (val != NULL)
*val = dt;
return 0;
error:
if (dt != NULL)
xmlSchemaFreeValue(dt);
return 1;
}
/**
* xmlSchemaParseDuration:
* @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
xmlSchemaParseDuration (xmlSchemaTypePtr type, const xmlChar *duration,
xmlSchemaValPtr *val) {
const xmlChar *cur = duration;
xmlSchemaValPtr dur;
int isneg = 0;
unsigned int seq = 0;
if (duration == NULL)
return -1;
if (*cur == '-') {
isneg = 1;
cur++;
}
/* duration must start with 'P' (after sign) */
if (*cur++ != 'P')
return 1;
dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
if (dur == NULL)
return -1;
while (*cur != 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};
/* 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;
return 0;
error:
if (dur != NULL)
xmlSchemaFreeValue(dur);
return 1;
}
/**
* xmlSchemaValidatePredefinedType:
* @type: the predefined type
@ -263,45 +956,17 @@ xmlSchemaValidatePredefinedType(xmlSchemaTypePtr type, const xmlChar *value,
}
}
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 == xmlSchemaTypeDurationDef) {
return xmlSchemaParseDuration(type, value, val);
} else if ((type == xmlSchemaTypeDatetimeDef) ||
(type == xmlSchemaTypeTimeDef) ||
(type == xmlSchemaTypeDateDef) ||
(type == xmlSchemaTypeGYearDef) ||
(type == xmlSchemaTypeGYearMonthDef) ||
(type == xmlSchemaTypeGMonthDef) ||
(type == xmlSchemaTypeGMonthDayDef) ||
(type == xmlSchemaTypeGDayDef)) {
return xmlSchemaParseDates(type, value, val);
} else if (type == xmlSchemaTypePositiveIntegerDef) {
const xmlChar *cur = value;
unsigned long base = 0;
@ -416,6 +1081,87 @@ xmlSchemaCompareDecimals(xmlSchemaValPtr x, xmlSchemaValPtr y)
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;
long xmon, xday, myear, lyear, 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 NULL;
/* 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 {
xmon = -mon;
xday = day;
}
myear = xmon / 12;
lyear = myear / 4;
minday = (myear * 365) + (lyear != 0 ? lyear - 1 : 0);
maxday = (myear * 365) + (lyear != 0 ? lyear + 1 : 0);
xmon = xmon % 12;
minday += dayRange[0][xmon];
maxday += dayRange[1][xmon];
if (maxday < xday)
return 1;
else if (minday > xday)
return -1;
/* indeterminate */
return 0;
}
/**
* xmlSchemaCompareValues:
* @x: a first value
@ -438,6 +1184,11 @@ xmlSchemaCompareValues(xmlSchemaValPtr x, xmlSchemaValPtr y) {
return(xmlSchemaCompareDecimals(x, y));
else
return(-2);
case XML_SCHEMAS_DURATION:
if (y->type == XML_SCHEMAS_DURATION)
return(xmlSchemaCompareDurations(x, y));
else
return(-2);
default:
TODO
}
@ -481,6 +1232,36 @@ xmlSchemaValidateFacet(xmlSchemaTypePtr base, xmlSchemaFacetPtr facet,
return(0);
TODO /* 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);
TODO /* 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);
TODO /* 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);
TODO /* error code */
return(1);
case XML_SCHEMA_FACET_WHITESPACE:
TODO /* whitespaces */
return(0);