/*
* **** Start temp insert ****
*
- * The following two routines (xsltUTF8Size and xsltUTF8Charcmp)
- * will be replaced with calls to the corresponding libxml routines
- * at a later date (when other inter-library dependencies require it)
+ * The following routine xsltUTF8Charcmp will be replaced with calls to
+ * the corresponding libxml routine at a later date (when other
+ * inter-library dependencies require it).
*/
-/**
- * xsltUTF8Size:
- * @utf: pointer to the UTF8 character
- *
- * returns the numbers of bytes in the character, -1 on format error
- */
-static int
-xsltUTF8Size(xmlChar *utf) {
- xmlChar mask;
- int len;
-
- if (utf == NULL)
- return -1;
- if (*utf < 0x80)
- return 1;
- /* check valid UTF8 character */
- if (!(*utf & 0x40))
- return -1;
- /* determine number of bytes in char */
- len = 2;
- for (mask=0x20; mask != 0; mask>>=1) {
- if (!(*utf & mask))
- return len;
- len++;
- }
- return -1;
-}
-
/**
* xsltUTF8Charcmp
* @utf1: pointer to first UTF8 char
*/
static int
xsltUTF8Charcmp(xmlChar *utf1, xmlChar *utf2) {
+ int len = xmlUTF8Strsize(utf1, 1);
+ if (len < 1)
+ return -1;
if (utf1 == NULL ) {
if (utf2 == NULL)
return 0;
return -1;
}
- return xmlStrncmp(utf1, utf2, xsltUTF8Size(utf1));
+ return xmlStrncmp(utf1, utf2, len);
}
/***** Stop temp insert *****/
}
if (i < 0)
xsltGenericError(xsltGenericErrorContext,
- "xsltNumberFormatDecimal: Internal buffer size exceeded");
+ "xsltNumberFormatDecimal: Internal buffer size exceeded\n");
xmlBufferCat(buffer, pointer);
}
static void
-xsltNumberFormatAlpha(xmlBufferPtr buffer,
+xsltNumberFormatAlpha(xsltNumberDataPtr data,
+ xmlBufferPtr buffer,
double number,
int is_upper)
{
char *alpha_list;
double alpha_size = (double)(sizeof(alpha_upper_list) - 1);
+ /*
+ * XSLT 1.0 isn't clear on how to handle zero, but XSLT 2.0 says:
+ *
+ * For all format tokens other than the first kind above (one that
+ * consists of decimal digits), there may be implementation-defined
+ * lower and upper bounds on the range of numbers that can be
+ * formatted using this format token; indeed, for some numbering
+ * sequences there may be intrinsic limits. [...] Numbers that fall
+ * outside this range must be formatted using the format token 1.
+ *
+ * The "a" token has an intrinsic lower limit of 1.
+ */
+ if (number < 1.0) {
+ xsltNumberFormatDecimal(buffer, number, '0', 1,
+ data->digitsPerGroup,
+ data->groupingCharacter,
+ data->groupingCharacterLen);
+ return;
+ }
+
/* Build buffer from back */
pointer = &temp_string[sizeof(temp_string)];
*(--pointer) = 0;
number--;
*(--pointer) = alpha_list[((int)fmod(number, alpha_size))];
number /= alpha_size;
- if (fabs(number) < 1.0)
+ if (number < 1.0)
break; /* for */
}
xmlBufferCCat(buffer, pointer);
}
static void
-xsltNumberFormatRoman(xmlBufferPtr buffer,
+xsltNumberFormatRoman(xsltNumberDataPtr data,
+ xmlBufferPtr buffer,
double number,
int is_upper)
{
+ /*
+ * See discussion in xsltNumberFormatAlpha. Also use a reasonable upper
+ * bound to avoid denial of service.
+ */
+ if (number < 1.0 || number > 5000.0) {
+ xsltNumberFormatDecimal(buffer, number, '0', 1,
+ data->digitsPerGroup,
+ data->groupingCharacter,
+ data->groupingCharacterLen);
+ return;
+ }
+
/*
* Based on an example by Jim Walsh
*/
for (i = 0; i < numbers_max; i++) {
/* Insert number */
number = numbers[(numbers_max - 1) - i];
+ /* Round to nearest like XSLT 2.0 */
+ number = floor(number + 0.5);
+ /*
+ * XSLT 1.0 isn't clear on how to handle negative numbers, but XSLT
+ * 2.0 says:
+ *
+ * It is a non-recoverable dynamic error if any undiscarded item
+ * in the atomized sequence supplied as the value of the value
+ * attribute of xsl:number cannot be converted to an integer, or
+ * if the resulting integer is less than 0 (zero).
+ */
+ if (number < 0.0) {
+ xsltTransformError(NULL, NULL, NULL,
+ "xsl-number : negative value\n");
+ /* Recover by treating negative values as zero. */
+ number = 0.0;
+ }
if (i < tokens->nTokens) {
/*
* The "n"th format token will be used to format the "n"th
switch (token->token) {
case 'A':
- xsltNumberFormatAlpha(buffer,
- number,
- TRUE);
-
+ xsltNumberFormatAlpha(data, buffer, number, TRUE);
break;
case 'a':
- xsltNumberFormatAlpha(buffer,
- number,
- FALSE);
-
+ xsltNumberFormatAlpha(data, buffer, number, FALSE);
break;
case 'I':
- xsltNumberFormatRoman(buffer,
- number,
- TRUE);
-
+ xsltNumberFormatRoman(data, buffer, number, TRUE);
break;
case 'i':
- xsltNumberFormatRoman(buffer,
- number,
- FALSE);
-
+ xsltNumberFormatRoman(data, buffer, number, FALSE);
break;
default:
if (IS_DIGIT_ZERO(token->token)) {
}
+static int
+xsltTestCompMatchCount(xsltTransformContextPtr context,
+ xmlNodePtr node,
+ xsltCompMatchPtr countPat,
+ xmlNodePtr cur)
+{
+ if (countPat != NULL) {
+ return xsltTestCompMatchList(context, node, countPat);
+ }
+ else {
+ /*
+ * 7.7 Numbering
+ *
+ * If count attribute is not specified, then it defaults to the
+ * pattern that matches any node with the same node type as the
+ * current node and, if the current node has an expanded-name, with
+ * the same expanded-name as the current node.
+ */
+ if (node->type != cur->type)
+ return 0;
+ if (node->type == XML_NAMESPACE_DECL)
+ /*
+ * Namespace nodes have no preceding siblings and no parents
+ * that are namespace nodes. This means that node == cur.
+ */
+ return 1;
+ /* TODO: Skip node types without expanded names like text nodes. */
+ if (!xmlStrEqual(node->name, cur->name))
+ return 0;
+ if (node->ns == cur->ns)
+ return 1;
+ if ((node->ns == NULL) || (cur->ns == NULL))
+ return 0;
+ return (xmlStrEqual(node->ns->href, cur->ns->href));
+ }
+}
+
static int
xsltNumberFormatGetAnyLevel(xsltTransformContextPtr context,
xmlNodePtr node,
xsltCompMatchPtr countPat,
xsltCompMatchPtr fromPat,
- double *array,
- xmlDocPtr doc,
- xmlNodePtr elem)
+ double *array)
{
int amount = 0;
int cnt = 0;
- xmlNodePtr cur;
-
- /* select the starting node */
- switch (node->type) {
- case XML_ELEMENT_NODE:
- cur = node;
- break;
- case XML_ATTRIBUTE_NODE:
- cur = ((xmlAttrPtr) node)->parent;
- break;
- case XML_TEXT_NODE:
- case XML_PI_NODE:
- case XML_COMMENT_NODE:
- cur = node->parent;
- break;
- default:
- cur = NULL;
- break;
- }
+ xmlNodePtr cur = node;
while (cur != NULL) {
/* process current node */
- if (countPat == NULL) {
- if ((node->type == cur->type) &&
- /* FIXME: must use expanded-name instead of local name */
- xmlStrEqual(node->name, cur->name)) {
- if ((node->ns == cur->ns) ||
- ((node->ns != NULL) &&
- (cur->ns != NULL) &&
- (xmlStrEqual(node->ns->href,
- cur->ns->href) )))
- cnt++;
- }
- } else {
- if (xsltTestCompMatchList(context, cur, countPat))
- cnt++;
- }
+ if (xsltTestCompMatchCount(context, cur, countPat, node))
+ cnt++;
if ((fromPat != NULL) &&
xsltTestCompMatchList(context, cur, fromPat)) {
break; /* while */
(cur->type == XML_HTML_DOCUMENT_NODE))
break; /* while */
- while ((cur->prev != NULL) && ((cur->prev->type == XML_DTD_NODE) ||
- (cur->prev->type == XML_XINCLUDE_START) ||
- (cur->prev->type == XML_XINCLUDE_END)))
- cur = cur->prev;
- if (cur->prev != NULL) {
- for (cur = cur->prev; cur->last != NULL; cur = cur->last);
- } else {
- cur = cur->parent;
- }
-
+ if (cur->type == XML_NAMESPACE_DECL) {
+ /*
+ * The XPath module stores the parent of a namespace node in
+ * the ns->next field.
+ */
+ cur = (xmlNodePtr) ((xmlNsPtr) cur)->next;
+ } else if (cur->type == XML_ATTRIBUTE_NODE) {
+ cur = cur->parent;
+ } else {
+ while ((cur->prev != NULL) && ((cur->prev->type == XML_DTD_NODE) ||
+ (cur->prev->type == XML_XINCLUDE_START) ||
+ (cur->prev->type == XML_XINCLUDE_END)))
+ cur = cur->prev;
+ if (cur->prev != NULL) {
+ for (cur = cur->prev; cur->last != NULL; cur = cur->last);
+ } else {
+ cur = cur->parent;
+ }
+ }
}
array[amount++] = (double) cnt;
xsltCompMatchPtr countPat,
xsltCompMatchPtr fromPat,
double *array,
- int max,
- xmlDocPtr doc,
- xmlNodePtr elem)
+ int max)
{
int amount = 0;
int cnt;
xsltTestCompMatchList(context, ancestor, fromPat))
break; /* for */
- if ((countPat == NULL && node->type == ancestor->type &&
- xmlStrEqual(node->name, ancestor->name)) ||
- xsltTestCompMatchList(context, ancestor, countPat)) {
+ if (xsltTestCompMatchCount(context, ancestor, countPat, node)) {
/* count(preceding-sibling::*) */
- cnt = 0;
- for (preceding = ancestor;
+ cnt = 1;
+ for (preceding =
+ xmlXPathNextPrecedingSibling(parser, ancestor);
preceding != NULL;
preceding =
xmlXPathNextPrecedingSibling(parser, preceding)) {
- if (countPat == NULL) {
- if ((preceding->type == ancestor->type) &&
- xmlStrEqual(preceding->name, ancestor->name)){
- if ((preceding->ns == ancestor->ns) ||
- ((preceding->ns != NULL) &&
- (ancestor->ns != NULL) &&
- (xmlStrEqual(preceding->ns->href,
- ancestor->ns->href) )))
- cnt++;
- }
- } else {
- if (xsltTestCompMatchList(context, preceding,
- countPat))
- cnt++;
- }
+
+ if (xsltTestCompMatchCount(context, preceding, countPat,
+ node))
+ cnt++;
}
array[amount++] = (double)cnt;
if (amount >= max)
int amount, i;
double number;
xsltFormat tokens;
- int tempformat = 0;
- if ((data->format == NULL) && (data->has_format != 0)) {
- data->format = xsltEvalAttrValueTemplate(ctxt, data->node,
+ if (data->format != NULL) {
+ xsltNumberFormatTokenize(data->format, &tokens);
+ }
+ else {
+ xmlChar *format;
+
+ /* The format needs to be recomputed each time */
+ if (data->has_format == 0)
+ return;
+ format = xsltEvalAttrValueTemplate(ctxt, data->node,
(const xmlChar *) "format",
XSLT_NAMESPACE);
- tempformat = 1;
- }
- if (data->format == NULL) {
- return;
+ if (format == NULL)
+ return;
+ xsltNumberFormatTokenize(format, &tokens);
+ xmlFree(format);
}
output = xmlBufferCreate();
if (output == NULL)
goto XSLT_NUMBER_FORMAT_END;
- xsltNumberFormatTokenize(data->format, &tokens);
-
/*
* Evaluate the XPath expression to find the value(s)
*/
data->countPat,
data->fromPat,
&number,
- 1,
- data->doc,
- data->node);
+ 1);
if (amount == 1) {
xsltNumberFormatInsertNumbers(data,
&number,
data->countPat,
data->fromPat,
numarray,
- max,
- data->doc,
- data->node);
+ max);
if (amount > 0) {
xsltNumberFormatInsertNumbers(data,
numarray,
node,
data->countPat,
data->fromPat,
- &number,
- data->doc,
- data->node);
+ &number);
if (amount > 0) {
xsltNumberFormatInsertNumbers(data,
&number,
/* Insert number as text node */
xsltCopyTextString(ctxt, ctxt->insert, xmlBufferContent(output), 0);
+ xmlBufferFree(output);
+
+XSLT_NUMBER_FORMAT_END:
if (tokens.start != NULL)
xmlFree(tokens.start);
if (tokens.end != NULL)
if (tokens.tokens[i].separator != NULL)
xmlFree(tokens.tokens[i].separator);
}
-
-XSLT_NUMBER_FORMAT_END:
- if (tempformat == 1) {
- /* The format need to be recomputed each time */
- data->format = NULL;
- }
- if (output != NULL)
- xmlBufferFree(output);
}
static int
}
}
- if ((len=xsltUTF8Size(*format)) < 1)
+ if ((len=xmlUTF8Strsize(*format, 1)) < 1)
return -1;
count += len;
*format += len;
} else
break; /* while */
- if ((len=xsltUTF8Size(the_format)) < 1) {
+ if ((len=xmlUTF8Strsize(the_format, 1)) < 1) {
found_error = 1;
goto OUTPUT_NUMBER;
}
}
/* We have finished the integer part, now work on fraction */
- if (xsltUTF8Charcmp(the_format, self->decimalPoint) == 0) {
+ if ( (*the_format != 0) &&
+ (xsltUTF8Charcmp(the_format, self->decimalPoint) == 0) ) {
format_info.add_decimal = TRUE;
- the_format += xsltUTF8Size(the_format); /* Skip over the decimal */
+ if ((len = xmlUTF8Strsize(the_format, 1)) < 1) {
+ found_error = 1;
+ goto OUTPUT_NUMBER;
+ }
+ the_format += len; /* Skip over the decimal */
}
while (*the_format != 0) {
goto OUTPUT_NUMBER;
}
delayed_multiplier = 100;
- if ((len = xsltUTF8Size(the_format)) < 1) {
+ if ((len = xmlUTF8Strsize(the_format, 1)) < 1) {
found_error = 1;
goto OUTPUT_NUMBER;
}
goto OUTPUT_NUMBER;
}
delayed_multiplier = 1000;
- if ((len = xsltUTF8Size(the_format)) < 1) {
+ if ((len = xmlUTF8Strsize(the_format, 1)) < 1) {
found_error = 1;
goto OUTPUT_NUMBER;
}
} else if (xsltUTF8Charcmp(the_format, self->grouping) != 0) {
break; /* while */
}
- if ((len = xsltUTF8Size(the_format)) < 1) {
+ if ((len = xmlUTF8Strsize(the_format, 1)) < 1) {
found_error = 1;
goto OUTPUT_NUMBER;
}
delayed_multiplier = 0;
else
break; /* while */
- if ((len = xsltUTF8Size(the_format)) < 1) {
+ if ((len = xmlUTF8Strsize(the_format, 1)) < 1) {
found_error = 1;
goto OUTPUT_NUMBER;
}
/* Ready to output our number. First see if "default sign" is required */
if (default_sign != 0)
- xmlBufferAdd(buffer, self->minusSign, xsltUTF8Size(self->minusSign));
+ xmlBufferAdd(buffer, self->minusSign, xmlUTF8Strsize(self->minusSign, 1));
/* Put the prefix into the buffer */
for (j = 0; j < prefix_length; j++) {
if ((pchar = *prefix++) == SYMBOL_QUOTE) {
- len = xsltUTF8Size(prefix);
+ len = xmlUTF8Strsize(prefix, 1);
xmlBufferAdd(buffer, prefix, len);
prefix += len;
j += len - 1; /* length of symbol less length of quote */
/* Add leading zero, if required */
if ((floor(number) == 0) &&
(format_info.integer_digits + format_info.frac_digits == 0)) {
- xmlBufferAdd(buffer, self->zeroDigit, xsltUTF8Size(self->zeroDigit));
+ xmlBufferAdd(buffer, self->zeroDigit, xmlUTF8Strsize(self->zeroDigit, 1));
}
/* Next the fractional part, if required */
if (format_info.frac_digits + format_info.frac_hash == 0) {
if (format_info.add_decimal)
xmlBufferAdd(buffer, self->decimalPoint,
- xsltUTF8Size(self->decimalPoint));
+ xmlUTF8Strsize(self->decimalPoint, 1));
}
else {
number -= floor(number);
if ((number != 0) || (format_info.frac_digits != 0)) {
xmlBufferAdd(buffer, self->decimalPoint,
- xsltUTF8Size(self->decimalPoint));
+ xmlUTF8Strsize(self->decimalPoint, 1));
number = floor(scale * number + 0.5);
for (j = format_info.frac_hash; j > 0; j--) {
if (fmod(number, 10.0) >= 1.0)
/* Put the suffix into the buffer */
for (j = 0; j < suffix_length; j++) {
if ((pchar = *suffix++) == SYMBOL_QUOTE) {
- len = xsltUTF8Size(suffix);
+ len = xmlUTF8Strsize(suffix, 1);
xmlBufferAdd(buffer, suffix, len);
suffix += len;
j += len - 1; /* length of symbol less length of escape */