1
0
mirror of https://gitlab.gnome.org/GNOME/libxml2.git synced 2025-10-21 14:53:44 +03:00

enhanced the parsing of XML_SCHEMAS_DECIMAL and much of the routine

* xmlschemastypes.c: enhanced the parsing of XML_SCHEMAS_DECIMAL
  and much of the routine xmlSchemaCompareDecimals.  The
  changes were necessary to fix a problem reported on the
  mailing list by John Hockaday.
This commit is contained in:
William M. Brack
2005-03-11 15:55:14 +00:00
parent b474fa409c
commit 273670f435
2 changed files with 144 additions and 63 deletions

View File

@@ -1,3 +1,10 @@
Fri Mar 11 23:53:13 HKT 2005 William Brack <wbrack@mmm.com.hk>
* xmlschemastypes.c: enhanced the parsing of XML_SCHEMAS_DECIMAL
and much of the routine xmlSchemaCompareDecimals. The
changes were necessary to fix a problem reported on the
mailing list by John Hockaday.
Fri Mar 11 13:22:52 CET 2005 Kasimier Buchcik <libxml2-cvs@cazic.net> Fri Mar 11 13:22:52 CET 2005 Kasimier Buchcik <libxml2-cvs@cazic.net>
* xmlschemas.c: The schema parser will stop if components could * xmlschemas.c: The schema parser will stop if components could

View File

@@ -50,13 +50,6 @@ extern double xmlXPathNINF;
#define IS_WSP_SPACE_CH(c) ((c) == 0x20) #define IS_WSP_SPACE_CH(c) ((c) == 0x20)
static unsigned long powten[10] = {
1, 10, 100, 1000, 10000, 100000, 1000000, 10000000L,
100000000L, 1000000000L
};
/* Date value */ /* Date value */
typedef struct _xmlSchemaValDate xmlSchemaValDate; typedef struct _xmlSchemaValDate xmlSchemaValDate;
typedef xmlSchemaValDate *xmlSchemaValDatePtr; typedef xmlSchemaValDate *xmlSchemaValDatePtr;
@@ -1890,42 +1883,76 @@ xmlSchemaValAtomicType(xmlSchemaTypePtr type, const xmlChar * value,
goto return0; goto return0;
} }
case XML_SCHEMAS_DECIMAL:{ case XML_SCHEMAS_DECIMAL:{
const xmlChar *cur = value, *tmp; const xmlChar *cur = value;
unsigned int frac = 0, len, neg = 0; unsigned int len, neg = 0;
unsigned long base = 0; xmlChar cval[25];
xmlChar *cptr = cval;
int dec = -1;
if (cur == NULL) if (cur == NULL)
goto return1; goto return1;
/* First we handle an optional sign */
if (*cur == '+') if (*cur == '+')
cur++; cur++;
else if (*cur == '-') { else if (*cur == '-') {
neg = 1; neg = 1;
cur++; cur++;
} }
tmp = cur; /*
while ((*cur >= '0') && (*cur <= '9')) { * Next we "pre-parse" the number, in preparation for calling
base = base * 10 + (*cur - '0'); * the common routine xmlSchemaParseUInt. We get rid of any
cur++; * leading zeroes (because we have reserved only 25 chars),
* and note the position of any decimal point.
*/
len = 0;
while (len < 24) {
if ((*cur >= '0') && (*cur <= '9')) {
*cptr++ = *cur;
len++;
} else if (*cur == '.') {
if (dec != -1)
goto return1; /* multiple decimal points */
if (!len) { /* num starts with '.' */
*cptr++ = '0';
len++;
} }
len = cur - tmp; dec = len++;
if (*cur == '.') { } else
break;
cur++; cur++;
tmp = cur;
while ((*cur >= '0') && (*cur <= '9')) {
base = base * 10 + (*cur - '0');
cur++;
}
frac = cur - tmp;
} }
if (*cur != 0) if (*cur != 0)
goto return1; goto return1; /* error if any extraneous chars */
if (val != NULL) { if (val != NULL) {
v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL); v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
if (v != NULL) { if (v != NULL) {
v->value.decimal.lo = base; /*
* If a mixed decimal, get rid of trailing zeroes
*/
if (dec) {
while ((cptr > cval) && (*(cptr-1) == '0')) {
cptr--;
len--;
}
}
*cptr = 0; /* Terminate our (preparsed) string */
cptr = cval;
/*
* Now evaluate the significant digits of the number
*/
xmlSchemaParseUInt((const xmlChar **)&cptr,
&v->value.decimal.lo,
&v->value.decimal.mi,
&v->value.decimal.hi);
v->value.decimal.sign = neg; v->value.decimal.sign = neg;
v->value.decimal.frac = frac; if (dec == -1) {
v->value.decimal.total = frac + len; v->value.decimal.frac = 0;
v->value.decimal.total = len;
} else {
v->value.decimal.frac = len - dec - 1;
v->value.decimal.total = len - 1;
}
*val = v; *val = v;
} }
} }
@@ -2879,59 +2906,106 @@ static int
xmlSchemaCompareDecimals(xmlSchemaValPtr x, xmlSchemaValPtr y) xmlSchemaCompareDecimals(xmlSchemaValPtr x, xmlSchemaValPtr y)
{ {
xmlSchemaValPtr swp; xmlSchemaValPtr swp;
int order = 1, p; int order = 1, integx, integy, dlen;
unsigned long tmp; unsigned long hi, mi, lo;
/*
* First test: If x is -ve and not zero
*/
if ((x->value.decimal.sign) && if ((x->value.decimal.sign) &&
((x->value.decimal.lo != 0) || ((x->value.decimal.lo != 0) ||
(x->value.decimal.mi != 0) || (x->value.decimal.mi != 0) ||
(x->value.decimal.hi != 0))) { (x->value.decimal.hi != 0))) {
/*
* Then if y is -ve and not zero reverse the compare
*/
if ((y->value.decimal.sign) && if ((y->value.decimal.sign) &&
((y->value.decimal.lo != 0) || ((y->value.decimal.lo != 0) ||
(y->value.decimal.mi != 0) || (y->value.decimal.mi != 0) ||
(y->value.decimal.hi != 0))) (y->value.decimal.hi != 0)))
order = -1; order = -1;
/*
* Otherwise (y >= 0) we have the answer
*/
else else
return (-1); return (-1);
/*
* If x is not -ve and y is -ve we have the answer
*/
} else if ((y->value.decimal.sign) && } else if ((y->value.decimal.sign) &&
((y->value.decimal.lo != 0) || ((y->value.decimal.lo != 0) ||
(y->value.decimal.mi != 0) || (y->value.decimal.mi != 0) ||
(y->value.decimal.hi != 0))) { (y->value.decimal.hi != 0))) {
return (1); return (1);
} }
if (x->value.decimal.frac == y->value.decimal.frac) { /*
if (x->value.decimal.hi < y->value.decimal.hi) * If it's not simply determined by a difference in sign,
return (-order); * then we need to compare the actual values of the two nums.
if (x->value.decimal.hi > y->value.decimal.hi) * To do this, we start by looking at the integral parts.
return (order); * If the number of integral digits differ, then we have our
if (x->value.decimal.mi < y->value.decimal.mi) * answer.
return (-order); */
if (x->value.decimal.mi > y->value.decimal.mi) integx = x->value.decimal.total - x->value.decimal.frac;
return (order); integy = y->value.decimal.total - y->value.decimal.frac;
if (x->value.decimal.lo < y->value.decimal.lo) if (integx > integy)
return (-order); return order;
if (x->value.decimal.lo > y->value.decimal.lo) else if (integy > integx)
return(order); return -order;
return(0); /*
} * If the number of integral digits is the same for both numbers,
if (y->value.decimal.frac > x->value.decimal.frac) { * then things get a little more complicated. We need to "normalize"
swp = y; * the numbers in order to properly compare them. To do this, we
y = x; * look at the total length of each number (length => number of
x = swp; * significant digits), and divide the "shorter" by 10 (decreasing
* the length) until they are of equal length.
*/
dlen = x->value.decimal.total - y->value.decimal.total;
if (dlen < 0) { /* y has more digits than x */
swp = x;
hi = y->value.decimal.hi;
mi = y->value.decimal.mi;
lo = y->value.decimal.lo;
dlen = -dlen;
order = -order; order = -order;
} else { /* x has more digits than y */
swp = y;
hi = x->value.decimal.hi;
mi = x->value.decimal.mi;
lo = x->value.decimal.lo;
} }
p = powten[x->value.decimal.frac - y->value.decimal.frac]; while (dlen > 8) { /* in effect, right shift by 10**8 */
tmp = x->value.decimal.lo / p; lo = mi;
if (tmp > y->value.decimal.lo) mi = hi;
return (order); hi = 0;
if (tmp < y->value.decimal.lo) dlen -= 8;
return (-order); }
tmp = y->value.decimal.lo * p; while (dlen > 0) {
if (x->value.decimal.lo < tmp) unsigned long rem1, rem2;
return (-order); rem1 = (hi % 10) * 100000000L;
if (x->value.decimal.lo == tmp) hi = hi / 10;
return (0); rem2 = (mi % 10) * 100000000L;
return (order); mi = (mi + rem1) / 10;
lo = (lo + rem2) / 10;
dlen--;
}
if (hi > swp->value.decimal.hi) {
return order;
} else if (hi == swp->value.decimal.hi) {
if (mi > swp->value.decimal.mi) {
return order;
} else if (mi == swp->value.decimal.mi) {
if (lo > swp->value.decimal.lo) {
return order;
} else if (lo == swp->value.decimal.lo) {
if (x->value.decimal.total == y->value.decimal.total) {
return 0;
} else {
return order;
}
}
}
}
return -order;
} }
/** /**