xref: /reactos/dll/3rdparty/libxslt/numbers.c (revision 40462c92)
1 /*
2  * numbers.c: Implementation of the XSLT number functions
3  *
4  * Reference:
5  *   http://www.w3.org/TR/1999/REC-xslt-19991116
6  *
7  * See Copyright for the status of this software.
8  *
9  * daniel@veillard.com
10  * Bjorn Reese <breese@users.sourceforge.net>
11  */
12 
13 #include "precomp.h"
14 
15 #ifndef FALSE
16 # define FALSE (0 == 1)
17 # define TRUE (1 == 1)
18 #endif
19 
20 #define SYMBOL_QUOTE		((xmlChar)'\'')
21 
22 #define DEFAULT_TOKEN		'0'
23 #define DEFAULT_SEPARATOR	"."
24 
25 #define MAX_TOKENS		1024
26 
27 typedef struct _xsltFormatToken xsltFormatToken;
28 typedef xsltFormatToken *xsltFormatTokenPtr;
29 struct _xsltFormatToken {
30     xmlChar	*separator;
31     int		 token;
32     int		 width;
33 };
34 
35 typedef struct _xsltFormat xsltFormat;
36 typedef xsltFormat *xsltFormatPtr;
37 struct _xsltFormat {
38     xmlChar		*start;
39     xsltFormatToken	 tokens[MAX_TOKENS];
40     int			 nTokens;
41     xmlChar		*end;
42 };
43 
44 static char alpha_upper_list[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
45 static char alpha_lower_list[] = "abcdefghijklmnopqrstuvwxyz";
46 static xsltFormatToken default_token;
47 
48 /*
49  * **** Start temp insert ****
50  *
51  * The following routine xsltUTF8Charcmp will be replaced with calls to
52  * the corresponding libxml routine at a later date (when other
53  * inter-library dependencies require it).
54  */
55 
56 /**
57  * xsltUTF8Charcmp
58  * @utf1: pointer to first UTF8 char
59  * @utf2: pointer to second UTF8 char
60  *
61  * returns result of comparing the two UCS4 values
62  * as with xmlStrncmp
63  */
64 static int
65 xsltUTF8Charcmp(xmlChar *utf1, xmlChar *utf2) {
66     int len = xmlUTF8Strsize(utf1, 1);
67 
68     if (len < 1)
69         return -1;
70     if (utf1 == NULL ) {
71         if (utf2 == NULL)
72             return 0;
73         return -1;
74     }
75     return xmlStrncmp(utf1, utf2, len);
76 }
77 
78 /***** Stop temp insert *****/
79 /************************************************************************
80  *									*
81  *			Utility functions				*
82  *									*
83  ************************************************************************/
84 
85 #define IS_SPECIAL(self,letter)			\
86     ((xsltUTF8Charcmp((letter), (self)->zeroDigit) == 0)	    ||	\
87      (xsltUTF8Charcmp((letter), (self)->digit) == 0)	    ||	\
88      (xsltUTF8Charcmp((letter), (self)->decimalPoint) == 0)  ||	\
89      (xsltUTF8Charcmp((letter), (self)->grouping) == 0)	    ||	\
90      (xsltUTF8Charcmp((letter), (self)->patternSeparator) == 0))
91 
92 #define IS_DIGIT_ZERO(x) xsltIsDigitZero(x)
93 #define IS_DIGIT_ONE(x) xsltIsDigitZero((x)-1)
94 
95 static int
96 xsltIsDigitZero(unsigned int ch)
97 {
98     /*
99      * Reference: ftp://ftp.unicode.org/Public/UNIDATA/UnicodeData.txt
100      *
101      * There a many more digit ranges in newer Unicode versions. These
102      * are only the zeros that match Digit in XML 1.0 (IS_DIGIT macro).
103      */
104     switch (ch) {
105     case 0x0030: case 0x0660: case 0x06F0: case 0x0966:
106     case 0x09E6: case 0x0A66: case 0x0AE6: case 0x0B66:
107     case 0x0C66: case 0x0CE6: case 0x0D66: case 0x0E50:
108     case 0x0ED0: case 0x0F20:
109 	return TRUE;
110     default:
111 	return FALSE;
112     }
113 }
114 
115 static void
116 xsltNumberFormatDecimal(xmlBufferPtr buffer,
117 			double number,
118 			int digit_zero,
119 			int width,
120 			int digitsPerGroup,
121 			int groupingCharacter,
122 			int groupingCharacterLen)
123 {
124     /*
125      * This used to be
126      *  xmlChar temp_string[sizeof(double) * CHAR_BIT * sizeof(xmlChar) + 4];
127      * which would be length 68 on x86 arch.  It was changed to be a longer,
128      * fixed length in order to try to cater for (reasonable) UTF8
129      * separators and numeric characters.  The max UTF8 char size will be
130      * 6 or less, so the value used [500] should be *much* larger than needed
131      */
132     xmlChar temp_string[500];
133     xmlChar *pointer;
134     xmlChar temp_char[6];
135     int i;
136     int val;
137     int len;
138 
139     /* Build buffer from back */
140     pointer = &temp_string[sizeof(temp_string)] - 1;	/* last char */
141     *pointer = 0;
142     i = 0;
143     while (pointer > temp_string) {
144 	if ((i >= width) && (fabs(number) < 1.0))
145 	    break; /* for */
146 	if ((i > 0) && (groupingCharacter != 0) &&
147 	    (digitsPerGroup > 0) &&
148 	    ((i % digitsPerGroup) == 0)) {
149 	    if (pointer - groupingCharacterLen < temp_string) {
150 	        i = -1;		/* flag error */
151 		break;
152 	    }
153 	    pointer -= groupingCharacterLen;
154 	    xmlCopyCharMultiByte(pointer, groupingCharacter);
155 	}
156 
157 	val = digit_zero + (int)fmod(number, 10.0);
158 	if (val < 0x80) {			/* shortcut if ASCII */
159 	    if (pointer <= temp_string) {	/* Check enough room */
160 	        i = -1;
161 		break;
162 	    }
163 	    *(--pointer) = val;
164 	}
165 	else {
166 	/*
167 	 * Here we have a multibyte character.  It's a little messy,
168 	 * because until we generate the char we don't know how long
169 	 * it is.  So, we generate it into the buffer temp_char, then
170 	 * copy from there into temp_string.
171 	 */
172 	    len = xmlCopyCharMultiByte(temp_char, val);
173 	    if ( (pointer - len) < temp_string ) {
174 	        i = -1;
175 		break;
176 	    }
177 	    pointer -= len;
178 	    memcpy(pointer, temp_char, len);
179 	}
180 	number /= 10.0;
181 	++i;
182     }
183     if (i < 0)
184         xsltGenericError(xsltGenericErrorContext,
185 		"xsltNumberFormatDecimal: Internal buffer size exceeded\n");
186     xmlBufferCat(buffer, pointer);
187 }
188 
189 static void
190 xsltNumberFormatAlpha(xsltNumberDataPtr data,
191 		      xmlBufferPtr buffer,
192 		      double number,
193 		      int is_upper)
194 {
195     char temp_string[sizeof(double) * CHAR_BIT * sizeof(xmlChar) + 1];
196     char *pointer;
197     int i;
198     char *alpha_list;
199     double alpha_size = (double)(sizeof(alpha_upper_list) - 1);
200 
201     /*
202      * XSLT 1.0 isn't clear on how to handle zero, but XSLT 2.0 says:
203      *
204      *     For all format tokens other than the first kind above (one that
205      *     consists of decimal digits), there may be implementation-defined
206      *     lower and upper bounds on the range of numbers that can be
207      *     formatted using this format token; indeed, for some numbering
208      *     sequences there may be intrinsic limits. [...] Numbers that fall
209      *     outside this range must be formatted using the format token 1.
210      *
211      * The "a" token has an intrinsic lower limit of 1.
212      */
213     if (number < 1.0) {
214         xsltNumberFormatDecimal(buffer, number, '0', 1,
215                                 data->digitsPerGroup,
216                                 data->groupingCharacter,
217                                 data->groupingCharacterLen);
218         return;
219     }
220 
221     /* Build buffer from back */
222     pointer = &temp_string[sizeof(temp_string)];
223     *(--pointer) = 0;
224     alpha_list = (is_upper) ? alpha_upper_list : alpha_lower_list;
225 
226     for (i = 1; i < (int)sizeof(temp_string); i++) {
227 	number--;
228 	*(--pointer) = alpha_list[((int)fmod(number, alpha_size))];
229 	number /= alpha_size;
230 	if (number < 1.0)
231 	    break; /* for */
232     }
233     xmlBufferCCat(buffer, pointer);
234 }
235 
236 static void
237 xsltNumberFormatRoman(xsltNumberDataPtr data,
238 		      xmlBufferPtr buffer,
239 		      double number,
240 		      int is_upper)
241 {
242     /*
243      * See discussion in xsltNumberFormatAlpha. Also use a reasonable upper
244      * bound to avoid denial of service.
245      */
246     if (number < 1.0 || number > 5000.0) {
247         xsltNumberFormatDecimal(buffer, number, '0', 1,
248                                 data->digitsPerGroup,
249                                 data->groupingCharacter,
250                                 data->groupingCharacterLen);
251         return;
252     }
253 
254     /*
255      * Based on an example by Jim Walsh
256      */
257     while (number >= 1000.0) {
258 	xmlBufferCCat(buffer, (is_upper) ? "M" : "m");
259 	number -= 1000.0;
260     }
261     if (number >= 900.0) {
262 	xmlBufferCCat(buffer, (is_upper) ? "CM" : "cm");
263 	number -= 900.0;
264     }
265     while (number >= 500.0) {
266 	xmlBufferCCat(buffer, (is_upper) ? "D" : "d");
267 	number -= 500.0;
268     }
269     if (number >= 400.0) {
270 	xmlBufferCCat(buffer, (is_upper) ? "CD" : "cd");
271 	number -= 400.0;
272     }
273     while (number >= 100.0) {
274 	xmlBufferCCat(buffer, (is_upper) ? "C" : "c");
275 	number -= 100.0;
276     }
277     if (number >= 90.0) {
278 	xmlBufferCCat(buffer, (is_upper) ? "XC" : "xc");
279 	number -= 90.0;
280     }
281     while (number >= 50.0) {
282 	xmlBufferCCat(buffer, (is_upper) ? "L" : "l");
283 	number -= 50.0;
284     }
285     if (number >= 40.0) {
286 	xmlBufferCCat(buffer, (is_upper) ? "XL" : "xl");
287 	number -= 40.0;
288     }
289     while (number >= 10.0) {
290 	xmlBufferCCat(buffer, (is_upper) ? "X" : "x");
291 	number -= 10.0;
292     }
293     if (number >= 9.0) {
294 	xmlBufferCCat(buffer, (is_upper) ? "IX" : "ix");
295 	number -= 9.0;
296     }
297     while (number >= 5.0) {
298 	xmlBufferCCat(buffer, (is_upper) ? "V" : "v");
299 	number -= 5.0;
300     }
301     if (number >= 4.0) {
302 	xmlBufferCCat(buffer, (is_upper) ? "IV" : "iv");
303 	number -= 4.0;
304     }
305     while (number >= 1.0) {
306 	xmlBufferCCat(buffer, (is_upper) ? "I" : "i");
307 	number--;
308     }
309 }
310 
311 static void
312 xsltNumberFormatTokenize(const xmlChar *format,
313 			 xsltFormatPtr tokens)
314 {
315     int ix = 0;
316     int j;
317     int val;
318     int len;
319 
320     default_token.token = DEFAULT_TOKEN;
321     default_token.width = 1;
322     default_token.separator = BAD_CAST(DEFAULT_SEPARATOR);
323 
324 
325     tokens->start = NULL;
326     tokens->tokens[0].separator = NULL;
327     tokens->end = NULL;
328 
329     /*
330      * Insert initial non-alphanumeric token.
331      * There is always such a token in the list, even if NULL
332      */
333     while (! (IS_LETTER(val=xmlStringCurrentChar(NULL, format+ix, &len)) ||
334 	      IS_DIGIT(val)) ) {
335 	if (format[ix] == 0)		/* if end of format string */
336 	    break; /* while */
337 	ix += len;
338     }
339     if (ix > 0)
340 	tokens->start = xmlStrndup(format, ix);
341 
342 
343     for (tokens->nTokens = 0; tokens->nTokens < MAX_TOKENS;
344 	 tokens->nTokens++) {
345 	if (format[ix] == 0)
346 	    break; /* for */
347 
348 	/*
349 	 * separator has already been parsed (except for the first
350 	 * number) in tokens->end, recover it.
351 	 */
352 	if (tokens->nTokens > 0) {
353 	    tokens->tokens[tokens->nTokens].separator = tokens->end;
354 	    tokens->end = NULL;
355 	}
356 
357 	val = xmlStringCurrentChar(NULL, format+ix, &len);
358 	if (IS_DIGIT_ONE(val) ||
359 		 IS_DIGIT_ZERO(val)) {
360 	    tokens->tokens[tokens->nTokens].width = 1;
361 	    while (IS_DIGIT_ZERO(val)) {
362 		tokens->tokens[tokens->nTokens].width++;
363 		ix += len;
364 		val = xmlStringCurrentChar(NULL, format+ix, &len);
365 	    }
366 	    if (IS_DIGIT_ONE(val)) {
367 		tokens->tokens[tokens->nTokens].token = val - 1;
368 		ix += len;
369 		val = xmlStringCurrentChar(NULL, format+ix, &len);
370 	    } else {
371                 tokens->tokens[tokens->nTokens].token = '0';
372                 tokens->tokens[tokens->nTokens].width = 1;
373             }
374 	} else if ( (val == 'A') ||
375 		    (val == 'a') ||
376 		    (val == 'I') ||
377 		    (val == 'i') ) {
378 	    tokens->tokens[tokens->nTokens].token = val;
379 	    ix += len;
380 	    val = xmlStringCurrentChar(NULL, format+ix, &len);
381 	} else {
382 	    /* XSLT section 7.7
383 	     * "Any other format token indicates a numbering sequence
384 	     *  that starts with that token. If an implementation does
385 	     *  not support a numbering sequence that starts with that
386 	     *  token, it must use a format token of 1."
387 	     */
388 	    tokens->tokens[tokens->nTokens].token = '0';
389 	    tokens->tokens[tokens->nTokens].width = 1;
390 	}
391 	/*
392 	 * Skip over remaining alphanumeric characters from the Nd
393 	 * (Number, decimal digit), Nl (Number, letter), No (Number,
394 	 * other), Lu (Letter, uppercase), Ll (Letter, lowercase), Lt
395 	 * (Letters, titlecase), Lm (Letters, modifiers), and Lo
396 	 * (Letters, other (uncased)) Unicode categories. This happens
397 	 * to correspond to the Letter and Digit classes from XML (and
398 	 * one wonders why XSLT doesn't refer to these instead).
399 	 */
400 	while (IS_LETTER(val) || IS_DIGIT(val)) {
401 	    ix += len;
402 	    val = xmlStringCurrentChar(NULL, format+ix, &len);
403 	}
404 
405 	/*
406 	 * Insert temporary non-alphanumeric final tooken.
407 	 */
408 	j = ix;
409 	while (! (IS_LETTER(val) || IS_DIGIT(val))) {
410 	    if (val == 0)
411 		break; /* while */
412 	    ix += len;
413 	    val = xmlStringCurrentChar(NULL, format+ix, &len);
414 	}
415 	if (ix > j)
416 	    tokens->end = xmlStrndup(&format[j], ix - j);
417     }
418 }
419 
420 static void
421 xsltNumberFormatInsertNumbers(xsltNumberDataPtr data,
422 			      double *numbers,
423 			      int numbers_max,
424 			      xsltFormatPtr tokens,
425 			      xmlBufferPtr buffer)
426 {
427     int i = 0;
428     double number;
429     xsltFormatTokenPtr token;
430 
431     /*
432      * Handle initial non-alphanumeric token
433      */
434     if (tokens->start != NULL)
435 	 xmlBufferCat(buffer, tokens->start);
436 
437     for (i = 0; i < numbers_max; i++) {
438 	/* Insert number */
439 	number = numbers[(numbers_max - 1) - i];
440         /* Round to nearest like XSLT 2.0 */
441         number = floor(number + 0.5);
442         /*
443          * XSLT 1.0 isn't clear on how to handle negative numbers, but XSLT
444          * 2.0 says:
445          *
446          *     It is a non-recoverable dynamic error if any undiscarded item
447          *     in the atomized sequence supplied as the value of the value
448          *     attribute of xsl:number cannot be converted to an integer, or
449          *     if the resulting integer is less than 0 (zero).
450          */
451         if (number < 0.0) {
452             xsltTransformError(NULL, NULL, NULL,
453                     "xsl-number : negative value\n");
454             /* Recover by treating negative values as zero. */
455             number = 0.0;
456         }
457 	if (i < tokens->nTokens) {
458 	  /*
459 	   * The "n"th format token will be used to format the "n"th
460 	   * number in the list
461 	   */
462 	  token = &(tokens->tokens[i]);
463 	} else if (tokens->nTokens > 0) {
464 	  /*
465 	   * If there are more numbers than format tokens, then the
466 	   * last format token will be used to format the remaining
467 	   * numbers.
468 	   */
469 	  token = &(tokens->tokens[tokens->nTokens - 1]);
470 	} else {
471 	  /*
472 	   * If there are no format tokens, then a format token of
473 	   * 1 is used to format all numbers.
474 	   */
475 	  token = &default_token;
476 	}
477 
478 	/* Print separator, except for the first number */
479 	if (i > 0) {
480 	    if (token->separator != NULL)
481 		xmlBufferCat(buffer, token->separator);
482 	    else
483 		xmlBufferCCat(buffer, DEFAULT_SEPARATOR);
484 	}
485 
486 	switch (xmlXPathIsInf(number)) {
487 	case -1:
488 	    xmlBufferCCat(buffer, "-Infinity");
489 	    break;
490 	case 1:
491 	    xmlBufferCCat(buffer, "Infinity");
492 	    break;
493 	default:
494 	    if (xmlXPathIsNaN(number)) {
495 		xmlBufferCCat(buffer, "NaN");
496 	    } else {
497 
498 		switch (token->token) {
499 		case 'A':
500 		    xsltNumberFormatAlpha(data, buffer, number, TRUE);
501 		    break;
502 		case 'a':
503 		    xsltNumberFormatAlpha(data, buffer, number, FALSE);
504 		    break;
505 		case 'I':
506 		    xsltNumberFormatRoman(data, buffer, number, TRUE);
507 		    break;
508 		case 'i':
509 		    xsltNumberFormatRoman(data, buffer, number, FALSE);
510 		    break;
511 		default:
512 		    if (IS_DIGIT_ZERO(token->token)) {
513 			xsltNumberFormatDecimal(buffer,
514 						number,
515 						token->token,
516 						token->width,
517 						data->digitsPerGroup,
518 						data->groupingCharacter,
519 						data->groupingCharacterLen);
520 		    }
521 		    break;
522 		}
523 	    }
524 
525 	}
526     }
527 
528     /*
529      * Handle final non-alphanumeric token
530      */
531     if (tokens->end != NULL)
532 	 xmlBufferCat(buffer, tokens->end);
533 
534 }
535 
536 static int
537 xsltTestCompMatchCount(xsltTransformContextPtr context,
538                        xmlNodePtr node,
539                        xsltCompMatchPtr countPat,
540                        xmlNodePtr cur)
541 {
542     if (countPat != NULL) {
543         return xsltTestCompMatchList(context, node, countPat);
544     }
545     else {
546         /*
547          * 7.7 Numbering
548          *
549          * If count attribute is not specified, then it defaults to the
550          * pattern that matches any node with the same node type as the
551          * current node and, if the current node has an expanded-name, with
552          * the same expanded-name as the current node.
553          */
554         if (node->type != cur->type)
555             return 0;
556         if (node->type == XML_NAMESPACE_DECL)
557             /*
558              * Namespace nodes have no preceding siblings and no parents
559              * that are namespace nodes. This means that node == cur.
560              */
561             return 1;
562         /* TODO: Skip node types without expanded names like text nodes. */
563         if (!xmlStrEqual(node->name, cur->name))
564             return 0;
565         if (node->ns == cur->ns)
566             return 1;
567         if ((node->ns == NULL) || (cur->ns == NULL))
568             return 0;
569         return (xmlStrEqual(node->ns->href, cur->ns->href));
570     }
571 }
572 
573 static int
574 xsltNumberFormatGetAnyLevel(xsltTransformContextPtr context,
575 			    xmlNodePtr node,
576 			    xsltCompMatchPtr countPat,
577 			    xsltCompMatchPtr fromPat,
578 			    double *array)
579 {
580     int amount = 0;
581     int cnt = 0;
582     xmlNodePtr cur = node;
583 
584     while (cur != NULL) {
585 	/* process current node */
586 	if (xsltTestCompMatchCount(context, cur, countPat, node))
587 	    cnt++;
588 	if ((fromPat != NULL) &&
589 	    xsltTestCompMatchList(context, cur, fromPat)) {
590 	    break; /* while */
591 	}
592 
593 	/* Skip to next preceding or ancestor */
594 	if ((cur->type == XML_DOCUMENT_NODE) ||
595 #ifdef LIBXML_DOCB_ENABLED
596             (cur->type == XML_DOCB_DOCUMENT_NODE) ||
597 #endif
598             (cur->type == XML_HTML_DOCUMENT_NODE))
599 	    break; /* while */
600 
601         if (cur->type == XML_NAMESPACE_DECL) {
602             /*
603             * The XPath module stores the parent of a namespace node in
604             * the ns->next field.
605             */
606             cur = (xmlNodePtr) ((xmlNsPtr) cur)->next;
607         } else if (cur->type == XML_ATTRIBUTE_NODE) {
608             cur = cur->parent;
609         } else {
610             while ((cur->prev != NULL) && ((cur->prev->type == XML_DTD_NODE) ||
611                    (cur->prev->type == XML_XINCLUDE_START) ||
612                    (cur->prev->type == XML_XINCLUDE_END)))
613                 cur = cur->prev;
614             if (cur->prev != NULL) {
615                 for (cur = cur->prev; cur->last != NULL; cur = cur->last);
616             } else {
617                 cur = cur->parent;
618             }
619         }
620     }
621 
622     array[amount++] = (double) cnt;
623 
624     return(amount);
625 }
626 
627 static int
628 xsltNumberFormatGetMultipleLevel(xsltTransformContextPtr context,
629 				 xmlNodePtr node,
630 				 xsltCompMatchPtr countPat,
631 				 xsltCompMatchPtr fromPat,
632 				 double *array,
633 				 int max)
634 {
635     int amount = 0;
636     int cnt;
637     xmlNodePtr oldCtxtNode;
638     xmlNodePtr ancestor;
639     xmlNodePtr preceding;
640     xmlXPathParserContextPtr parser;
641 
642     oldCtxtNode = context->xpathCtxt->node;
643     parser = xmlXPathNewParserContext(NULL, context->xpathCtxt);
644     if (parser) {
645 	/* ancestor-or-self::*[count] */
646 	ancestor = node;
647 	while ((ancestor != NULL) && (ancestor->type != XML_DOCUMENT_NODE)) {
648 	    if ((fromPat != NULL) &&
649 		xsltTestCompMatchList(context, ancestor, fromPat))
650 		break; /* for */
651 
652             /*
653              * The xmlXPathNext* iterators require that the context node is
654              * set to the start node. Calls to xsltTestCompMatch* may also
655              * leave the context node in an undefined state, so make sure
656              * that the context node is reset before each iterator invocation.
657              */
658 
659 	    if (xsltTestCompMatchCount(context, ancestor, countPat, node)) {
660 		/* count(preceding-sibling::*) */
661 		cnt = 1;
662                 context->xpathCtxt->node = ancestor;
663                 preceding = xmlXPathNextPrecedingSibling(parser, ancestor);
664                 while (preceding != NULL) {
665 	            if (xsltTestCompMatchCount(context, preceding, countPat,
666                                                node))
667 			cnt++;
668                     context->xpathCtxt->node = ancestor;
669                     preceding =
670                         xmlXPathNextPrecedingSibling(parser, preceding);
671 		}
672 		array[amount++] = (double)cnt;
673 		if (amount >= max)
674 		    break; /* for */
675 	    }
676             context->xpathCtxt->node = node;
677             ancestor = xmlXPathNextAncestor(parser, ancestor);
678 	}
679 	xmlXPathFreeParserContext(parser);
680     }
681     context->xpathCtxt->node = oldCtxtNode;
682     return amount;
683 }
684 
685 static int
686 xsltNumberFormatGetValue(xmlXPathContextPtr context,
687 			 xmlNodePtr node,
688 			 const xmlChar *value,
689 			 double *number)
690 {
691     int amount = 0;
692     xmlBufferPtr pattern;
693     xmlXPathObjectPtr obj;
694 
695     pattern = xmlBufferCreate();
696     if (pattern != NULL) {
697 	xmlBufferCCat(pattern, "number(");
698 	xmlBufferCat(pattern, value);
699 	xmlBufferCCat(pattern, ")");
700 	context->node = node;
701 	obj = xmlXPathEvalExpression(xmlBufferContent(pattern),
702 				     context);
703 	if (obj != NULL) {
704 	    *number = obj->floatval;
705 	    amount++;
706 	    xmlXPathFreeObject(obj);
707 	}
708 	xmlBufferFree(pattern);
709     }
710     return amount;
711 }
712 
713 /**
714  * xsltNumberFormat:
715  * @ctxt: the XSLT transformation context
716  * @data: the formatting information
717  * @node: the data to format
718  *
719  * Convert one number.
720  */
721 void
722 xsltNumberFormat(xsltTransformContextPtr ctxt,
723 		 xsltNumberDataPtr data,
724 		 xmlNodePtr node)
725 {
726     xmlBufferPtr output = NULL;
727     int amount, i;
728     double number;
729     xsltFormat tokens;
730 
731     if (data->format != NULL) {
732         xsltNumberFormatTokenize(data->format, &tokens);
733     }
734     else {
735         xmlChar *format;
736 
737 	/* The format needs to be recomputed each time */
738         if (data->has_format == 0)
739             return;
740 	format = xsltEvalAttrValueTemplate(ctxt, data->node,
741 					     (const xmlChar *) "format",
742 					     XSLT_NAMESPACE);
743         if (format == NULL)
744             return;
745         xsltNumberFormatTokenize(format, &tokens);
746 	xmlFree(format);
747     }
748 
749     output = xmlBufferCreate();
750     if (output == NULL)
751 	goto XSLT_NUMBER_FORMAT_END;
752 
753     /*
754      * Evaluate the XPath expression to find the value(s)
755      */
756     if (data->value) {
757 	amount = xsltNumberFormatGetValue(ctxt->xpathCtxt,
758 					  node,
759 					  data->value,
760 					  &number);
761 	if (amount == 1) {
762 	    xsltNumberFormatInsertNumbers(data,
763 					  &number,
764 					  1,
765 					  &tokens,
766 					  output);
767 	}
768 
769     } else if (data->level) {
770 
771 	if (xmlStrEqual(data->level, (const xmlChar *) "single")) {
772 	    amount = xsltNumberFormatGetMultipleLevel(ctxt,
773 						      node,
774 						      data->countPat,
775 						      data->fromPat,
776 						      &number,
777 						      1);
778 	    if (amount == 1) {
779 		xsltNumberFormatInsertNumbers(data,
780 					      &number,
781 					      1,
782 					      &tokens,
783 					      output);
784 	    }
785 	} else if (xmlStrEqual(data->level, (const xmlChar *) "multiple")) {
786 	    double numarray[1024];
787 	    int max = sizeof(numarray)/sizeof(numarray[0]);
788 	    amount = xsltNumberFormatGetMultipleLevel(ctxt,
789 						      node,
790 						      data->countPat,
791 						      data->fromPat,
792 						      numarray,
793 						      max);
794 	    if (amount > 0) {
795 		xsltNumberFormatInsertNumbers(data,
796 					      numarray,
797 					      amount,
798 					      &tokens,
799 					      output);
800 	    }
801 	} else if (xmlStrEqual(data->level, (const xmlChar *) "any")) {
802 	    amount = xsltNumberFormatGetAnyLevel(ctxt,
803 						 node,
804 						 data->countPat,
805 						 data->fromPat,
806 						 &number);
807 	    if (amount > 0) {
808 		xsltNumberFormatInsertNumbers(data,
809 					      &number,
810 					      1,
811 					      &tokens,
812 					      output);
813 	    }
814 	}
815 
816         /*
817          * Unlike `match` patterns, `count` and `from` patterns can contain
818          * variable references, so we have to clear the pattern match
819          * cache if the "direct" matching algorithm was used.
820          */
821         if (data->countPat != NULL)
822             xsltCompMatchClearCache(ctxt, data->countPat);
823         if (data->fromPat != NULL)
824             xsltCompMatchClearCache(ctxt, data->fromPat);
825     }
826     /* Insert number as text node */
827     xsltCopyTextString(ctxt, ctxt->insert, xmlBufferContent(output), 0);
828 
829     xmlBufferFree(output);
830 
831 XSLT_NUMBER_FORMAT_END:
832     if (tokens.start != NULL)
833 	xmlFree(tokens.start);
834     if (tokens.end != NULL)
835 	xmlFree(tokens.end);
836     for (i = 0;i < tokens.nTokens;i++) {
837 	if (tokens.tokens[i].separator != NULL)
838 	    xmlFree(tokens.tokens[i].separator);
839     }
840 }
841 
842 static int
843 xsltFormatNumberPreSuffix(xsltDecimalFormatPtr self, xmlChar **format, xsltFormatNumberInfoPtr info)
844 {
845     /* will hold total length of prefix/suffix without quote characters */
846     int	count=0;
847     int len;
848 
849     while (1) {
850 	/*
851 	 * prefix / suffix ends at end of string or at
852 	 * first 'special' character
853 	 */
854 	if (**format == 0)
855 	    return count;
856 	/* if next character 'escaped' just count it */
857 	if (**format == SYMBOL_QUOTE) {
858 	    if (*++(*format) == 0)
859 		return -1;
860 	}
861 	else if (IS_SPECIAL(self, *format))
862 	    return count;
863 	/*
864 	 * else treat percent/per-mille as special cases,
865 	 * depending on whether +ve or -ve
866 	 */
867 	else {
868 	    /*
869 	     * for +ve prefix/suffix, allow only a
870 	     * single occurence of either
871 	     */
872 	    if (xsltUTF8Charcmp(*format, self->percent) == 0) {
873 		if (info->is_multiplier_set)
874 		    return -1;
875 		info->multiplier = 100;
876 		info->is_multiplier_set = TRUE;
877 	    } else if (xsltUTF8Charcmp(*format, self->permille) == 0) {
878 		if (info->is_multiplier_set)
879 		    return -1;
880 		info->multiplier = 1000;
881 		info->is_multiplier_set = TRUE;
882 	    }
883 	}
884 
885 	if ((len=xmlUTF8Strsize(*format, 1)) < 1)
886 	    return -1;
887 	count += len;
888 	*format += len;
889     }
890 }
891 
892 /**
893  * xsltFormatNumberConversion:
894  * @self: the decimal format
895  * @format: the format requested
896  * @number: the value to format
897  * @result: the place to output the result
898  *
899  * format-number() uses the JDK 1.1 DecimalFormat class:
900  *
901  * http://java.sun.com/products/jdk/1.1/docs/api/java.text.DecimalFormat.html
902  *
903  * Structure:
904  *
905  *   pattern    := subpattern{;subpattern}
906  *   subpattern := {prefix}integer{.fraction}{suffix}
907  *   prefix     := '\\u0000'..'\\uFFFD' - specialCharacters
908  *   suffix     := '\\u0000'..'\\uFFFD' - specialCharacters
909  *   integer    := '#'* '0'* '0'
910  *   fraction   := '0'* '#'*
911  *
912  *   Notation:
913  *    X*       0 or more instances of X
914  *    (X | Y)  either X or Y.
915  *    X..Y     any character from X up to Y, inclusive.
916  *    S - T    characters in S, except those in T
917  *
918  * Special Characters:
919  *
920  *   Symbol Meaning
921  *   0      a digit
922  *   #      a digit, zero shows as absent
923  *   .      placeholder for decimal separator
924  *   ,      placeholder for grouping separator.
925  *   ;      separates formats.
926  *   -      default negative prefix.
927  *   %      multiply by 100 and show as percentage
928  *   ?      multiply by 1000 and show as per mille
929  *   X      any other characters can be used in the prefix or suffix
930  *   '      used to quote special characters in a prefix or suffix.
931  *
932  * Returns a possible XPath error
933  */
934 xmlXPathError
935 xsltFormatNumberConversion(xsltDecimalFormatPtr self,
936 			   xmlChar *format,
937 			   double number,
938 			   xmlChar **result)
939 {
940     xmlXPathError status = XPATH_EXPRESSION_OK;
941     xmlBufferPtr buffer;
942     xmlChar *the_format, *prefix = NULL, *suffix = NULL;
943     xmlChar *nprefix, *nsuffix = NULL;
944     int	    prefix_length, suffix_length = 0, nprefix_length, nsuffix_length;
945     double  scale;
946     int	    j, len;
947     int     self_grouping_len;
948     xsltFormatNumberInfo format_info;
949     /*
950      * delayed_multiplier allows a 'trailing' percent or
951      * permille to be treated as suffix
952      */
953     int		delayed_multiplier = 0;
954     /* flag to show no -ve format present for -ve number */
955     char	default_sign = 0;
956     /* flag to show error found, should use default format */
957     char	found_error = 0;
958 
959     if (xmlStrlen(format) <= 0) {
960 	xsltTransformError(NULL, NULL, NULL,
961                 "xsltFormatNumberConversion : "
962 		"Invalid format (0-length)\n");
963     }
964     *result = NULL;
965     switch (xmlXPathIsInf(number)) {
966 	case -1:
967 	    if (self->minusSign == NULL)
968 		*result = xmlStrdup(BAD_CAST "-");
969 	    else
970 		*result = xmlStrdup(self->minusSign);
971 	    /* Intentional fall-through */
972 	case 1:
973 	    if ((self == NULL) || (self->infinity == NULL))
974 		*result = xmlStrcat(*result, BAD_CAST "Infinity");
975 	    else
976 		*result = xmlStrcat(*result, self->infinity);
977 	    return(status);
978 	default:
979 	    if (xmlXPathIsNaN(number)) {
980 		if ((self == NULL) || (self->noNumber == NULL))
981 		    *result = xmlStrdup(BAD_CAST "NaN");
982 		else
983 		    *result = xmlStrdup(self->noNumber);
984 		return(status);
985 	    }
986     }
987 
988     buffer = xmlBufferCreate();
989     if (buffer == NULL) {
990 	return XPATH_MEMORY_ERROR;
991     }
992 
993     format_info.integer_hash = 0;
994     format_info.integer_digits = 0;
995     format_info.frac_digits = 0;
996     format_info.frac_hash = 0;
997     format_info.group = -1;
998     format_info.multiplier = 1;
999     format_info.add_decimal = FALSE;
1000     format_info.is_multiplier_set = FALSE;
1001     format_info.is_negative_pattern = FALSE;
1002 
1003     the_format = format;
1004 
1005     /*
1006      * First we process the +ve pattern to get percent / permille,
1007      * as well as main format
1008      */
1009     prefix = the_format;
1010     prefix_length = xsltFormatNumberPreSuffix(self, &the_format, &format_info);
1011     if (prefix_length < 0) {
1012 	found_error = 1;
1013 	goto OUTPUT_NUMBER;
1014     }
1015 
1016     /*
1017      * Here we process the "number" part of the format.  It gets
1018      * a little messy because of the percent/per-mille - if that
1019      * appears at the end, it may be part of the suffix instead
1020      * of part of the number, so the variable delayed_multiplier
1021      * is used to handle it
1022      */
1023     self_grouping_len = xmlStrlen(self->grouping);
1024     while ((*the_format != 0) &&
1025 	   (xsltUTF8Charcmp(the_format, self->decimalPoint) != 0) &&
1026 	   (xsltUTF8Charcmp(the_format, self->patternSeparator) != 0)) {
1027 
1028 	if (delayed_multiplier != 0) {
1029 	    format_info.multiplier = delayed_multiplier;
1030 	    format_info.is_multiplier_set = TRUE;
1031 	    delayed_multiplier = 0;
1032 	}
1033 	if (xsltUTF8Charcmp(the_format, self->digit) == 0) {
1034 	    if (format_info.integer_digits > 0) {
1035 		found_error = 1;
1036 		goto OUTPUT_NUMBER;
1037 	    }
1038 	    format_info.integer_hash++;
1039 	    if (format_info.group >= 0)
1040 		format_info.group++;
1041 	} else if (xsltUTF8Charcmp(the_format, self->zeroDigit) == 0) {
1042 	    format_info.integer_digits++;
1043 	    if (format_info.group >= 0)
1044 		format_info.group++;
1045 	} else if ((self_grouping_len > 0) &&
1046 	    (!xmlStrncmp(the_format, self->grouping, self_grouping_len))) {
1047 	    /* Reset group count */
1048 	    format_info.group = 0;
1049 	    the_format += self_grouping_len;
1050 	    continue;
1051 	} else if (xsltUTF8Charcmp(the_format, self->percent) == 0) {
1052 	    if (format_info.is_multiplier_set) {
1053 		found_error = 1;
1054 		goto OUTPUT_NUMBER;
1055 	    }
1056 	    delayed_multiplier = 100;
1057 	} else  if (xsltUTF8Charcmp(the_format, self->permille) == 0) {
1058 	    if (format_info.is_multiplier_set) {
1059 		found_error = 1;
1060 		goto OUTPUT_NUMBER;
1061 	    }
1062 	    delayed_multiplier = 1000;
1063 	} else
1064 	    break; /* while */
1065 
1066 	if ((len=xmlUTF8Strsize(the_format, 1)) < 1) {
1067 	    found_error = 1;
1068 	    goto OUTPUT_NUMBER;
1069 	}
1070 	the_format += len;
1071 
1072     }
1073 
1074     /* We have finished the integer part, now work on fraction */
1075     if ( (*the_format != 0) &&
1076          (xsltUTF8Charcmp(the_format, self->decimalPoint) == 0) ) {
1077         format_info.add_decimal = TRUE;
1078         if ((len = xmlUTF8Strsize(the_format, 1)) < 1) {
1079             found_error = 1;
1080             goto OUTPUT_NUMBER;
1081         }
1082 	the_format += len;	/* Skip over the decimal */
1083     }
1084 
1085     while (*the_format != 0) {
1086 
1087 	if (xsltUTF8Charcmp(the_format, self->zeroDigit) == 0) {
1088 	    if (format_info.frac_hash != 0) {
1089 		found_error = 1;
1090 		goto OUTPUT_NUMBER;
1091 	    }
1092 	    format_info.frac_digits++;
1093 	} else if (xsltUTF8Charcmp(the_format, self->digit) == 0) {
1094 	    format_info.frac_hash++;
1095 	} else if (xsltUTF8Charcmp(the_format, self->percent) == 0) {
1096 	    if (format_info.is_multiplier_set) {
1097 		found_error = 1;
1098 		goto OUTPUT_NUMBER;
1099 	    }
1100 	    delayed_multiplier = 100;
1101 	    if ((len = xmlUTF8Strsize(the_format, 1)) < 1) {
1102 	        found_error = 1;
1103 		goto OUTPUT_NUMBER;
1104 	    }
1105 	    the_format += len;
1106 	    continue; /* while */
1107 	} else if (xsltUTF8Charcmp(the_format, self->permille) == 0) {
1108 	    if (format_info.is_multiplier_set) {
1109 		found_error = 1;
1110 		goto OUTPUT_NUMBER;
1111 	    }
1112 	    delayed_multiplier = 1000;
1113 	    if  ((len = xmlUTF8Strsize(the_format, 1)) < 1) {
1114 	        found_error = 1;
1115 		goto OUTPUT_NUMBER;
1116 	    }
1117 	    the_format += len;
1118 	    continue; /* while */
1119 	} else if (xsltUTF8Charcmp(the_format, self->grouping) != 0) {
1120 	    break; /* while */
1121 	}
1122 	if ((len = xmlUTF8Strsize(the_format, 1)) < 1) {
1123 	    found_error = 1;
1124 	    goto OUTPUT_NUMBER;
1125 	}
1126 	the_format += len;
1127 	if (delayed_multiplier != 0) {
1128 	    format_info.multiplier = delayed_multiplier;
1129 	    delayed_multiplier = 0;
1130 	    format_info.is_multiplier_set = TRUE;
1131 	}
1132     }
1133 
1134     /*
1135      * If delayed_multiplier is set after processing the
1136      * "number" part, should be in suffix
1137      */
1138     if (delayed_multiplier != 0) {
1139 	the_format -= len;
1140 	delayed_multiplier = 0;
1141     }
1142 
1143     suffix = the_format;
1144     suffix_length = xsltFormatNumberPreSuffix(self, &the_format, &format_info);
1145     if ( (suffix_length < 0) ||
1146 	 ((*the_format != 0) &&
1147 	  (xsltUTF8Charcmp(the_format, self->patternSeparator) != 0)) ) {
1148 	found_error = 1;
1149 	goto OUTPUT_NUMBER;
1150     }
1151 
1152     /*
1153      * We have processed the +ve prefix, number part and +ve suffix.
1154      * If the number is -ve, we must substitute the -ve prefix / suffix
1155      */
1156     if (number < 0) {
1157         /*
1158 	 * Note that j is the number of UTF8 chars before the separator,
1159 	 * not the number of bytes! (bug 151975)
1160 	 */
1161         j =  xmlUTF8Strloc(format, self->patternSeparator);
1162 	if (j < 0) {
1163 	/* No -ve pattern present, so use default signing */
1164 	    default_sign = 1;
1165 	}
1166 	else {
1167 	    /* Skip over pattern separator (accounting for UTF8) */
1168 	    the_format = (xmlChar *)xmlUTF8Strpos(format, j + 1);
1169 	    /*
1170 	     * Flag changes interpretation of percent/permille
1171 	     * in -ve pattern
1172 	     */
1173 	    format_info.is_negative_pattern = TRUE;
1174 	    format_info.is_multiplier_set = FALSE;
1175 
1176 	    /* First do the -ve prefix */
1177 	    nprefix = the_format;
1178 	    nprefix_length = xsltFormatNumberPreSuffix(self,
1179 					&the_format, &format_info);
1180 	    if (nprefix_length<0) {
1181 		found_error = 1;
1182 		goto OUTPUT_NUMBER;
1183 	    }
1184 
1185 	    while (*the_format != 0) {
1186 		if ( (xsltUTF8Charcmp(the_format, (self)->percent) == 0) ||
1187 		     (xsltUTF8Charcmp(the_format, (self)->permille)== 0) ) {
1188 		    if (format_info.is_multiplier_set) {
1189 			found_error = 1;
1190 			goto OUTPUT_NUMBER;
1191 		    }
1192 		    format_info.is_multiplier_set = TRUE;
1193 		    delayed_multiplier = 1;
1194 		}
1195 		else if (IS_SPECIAL(self, the_format))
1196 		    delayed_multiplier = 0;
1197 		else
1198 		    break; /* while */
1199 		if ((len = xmlUTF8Strsize(the_format, 1)) < 1) {
1200 		    found_error = 1;
1201 		    goto OUTPUT_NUMBER;
1202 		}
1203 		the_format += len;
1204 	    }
1205 	    if (delayed_multiplier != 0) {
1206 		format_info.is_multiplier_set = FALSE;
1207 		the_format -= len;
1208 	    }
1209 
1210 	    /* Finally do the -ve suffix */
1211 	    if (*the_format != 0) {
1212 		nsuffix = the_format;
1213 		nsuffix_length = xsltFormatNumberPreSuffix(self,
1214 					&the_format, &format_info);
1215 		if (nsuffix_length < 0) {
1216 		    found_error = 1;
1217 		    goto OUTPUT_NUMBER;
1218 		}
1219 	    }
1220 	    else
1221 		nsuffix_length = 0;
1222 	    if (*the_format != 0) {
1223 		found_error = 1;
1224 		goto OUTPUT_NUMBER;
1225 	    }
1226 	    /*
1227 	     * Here's another Java peculiarity:
1228 	     * if -ve prefix/suffix == +ve ones, discard & use default
1229 	     */
1230 	    if ((nprefix_length != prefix_length) ||
1231 		(nsuffix_length != suffix_length) ||
1232 		((nprefix_length > 0) &&
1233 		 (xmlStrncmp(nprefix, prefix, prefix_length) !=0 )) ||
1234 		((nsuffix_length > 0) &&
1235 		 (xmlStrncmp(nsuffix, suffix, suffix_length) !=0 ))) {
1236 		prefix = nprefix;
1237 		prefix_length = nprefix_length;
1238 		suffix = nsuffix;
1239 		suffix_length = nsuffix_length;
1240 	    } /* else {
1241 		default_sign = 1;
1242 	    }
1243 	    */
1244 	}
1245     }
1246 
1247 OUTPUT_NUMBER:
1248     if (found_error != 0) {
1249 	xsltTransformError(NULL, NULL, NULL,
1250                 "xsltFormatNumberConversion : "
1251 		"error in format string '%s', using default\n", format);
1252 	default_sign = (number < 0.0) ? 1 : 0;
1253 	prefix_length = suffix_length = 0;
1254 	format_info.integer_hash = 0;
1255 	format_info.integer_digits = 1;
1256 	format_info.frac_digits = 1;
1257 	format_info.frac_hash = 4;
1258 	format_info.group = -1;
1259 	format_info.multiplier = 1;
1260 	format_info.add_decimal = TRUE;
1261     }
1262 
1263     /* Ready to output our number.  First see if "default sign" is required */
1264     if (default_sign != 0)
1265 	xmlBufferAdd(buffer, self->minusSign, xmlUTF8Strsize(self->minusSign, 1));
1266 
1267     /* Put the prefix into the buffer */
1268     for (j = 0; j < prefix_length; ) {
1269 	if (*prefix == SYMBOL_QUOTE)
1270             prefix++;
1271         len = xmlUTF8Strsize(prefix, 1);
1272         xmlBufferAdd(buffer, prefix, len);
1273         prefix += len;
1274         j += len;
1275     }
1276 
1277     /* Next do the integer part of the number */
1278     number = fabs(number) * (double)format_info.multiplier;
1279     scale = pow(10.0, (double)(format_info.frac_digits + format_info.frac_hash));
1280     number = floor((scale * number + 0.5)) / scale;
1281     if ((self->grouping != NULL) &&
1282         (self->grouping[0] != 0)) {
1283         int gchar;
1284 
1285 	len = xmlStrlen(self->grouping);
1286 	gchar = xsltGetUTF8Char(self->grouping, &len);
1287 	xsltNumberFormatDecimal(buffer, floor(number), self->zeroDigit[0],
1288 				format_info.integer_digits,
1289 				format_info.group,
1290 				gchar, len);
1291     } else
1292 	xsltNumberFormatDecimal(buffer, floor(number), self->zeroDigit[0],
1293 				format_info.integer_digits,
1294 				format_info.group,
1295 				',', 1);
1296 
1297     /* Special case: java treats '.#' like '.0', '.##' like '.0#', etc. */
1298     if ((format_info.integer_digits + format_info.integer_hash +
1299 	 format_info.frac_digits == 0) && (format_info.frac_hash > 0)) {
1300         ++format_info.frac_digits;
1301 	--format_info.frac_hash;
1302     }
1303 
1304     /* Add leading zero, if required */
1305     if ((floor(number) == 0) &&
1306 	(format_info.integer_digits + format_info.frac_digits == 0)) {
1307         xmlBufferAdd(buffer, self->zeroDigit, xmlUTF8Strsize(self->zeroDigit, 1));
1308     }
1309 
1310     /* Next the fractional part, if required */
1311     if (format_info.frac_digits + format_info.frac_hash == 0) {
1312         if (format_info.add_decimal)
1313 	    xmlBufferAdd(buffer, self->decimalPoint,
1314 			 xmlUTF8Strsize(self->decimalPoint, 1));
1315     }
1316     else {
1317       number -= floor(number);
1318 	if ((number != 0) || (format_info.frac_digits != 0)) {
1319 	    xmlBufferAdd(buffer, self->decimalPoint,
1320 			 xmlUTF8Strsize(self->decimalPoint, 1));
1321 	    number = floor(scale * number + 0.5);
1322 	    for (j = format_info.frac_hash; j > 0; j--) {
1323 		if (fmod(number, 10.0) >= 1.0)
1324 		    break; /* for */
1325 		number /= 10.0;
1326 	    }
1327 	    xsltNumberFormatDecimal(buffer, floor(number), self->zeroDigit[0],
1328 				format_info.frac_digits + j,
1329 				0, 0, 0);
1330 	}
1331     }
1332     /* Put the suffix into the buffer */
1333     for (j = 0; j < suffix_length; ) {
1334 	if (*suffix == SYMBOL_QUOTE)
1335             suffix++;
1336         len = xmlUTF8Strsize(suffix, 1);
1337         xmlBufferAdd(buffer, suffix, len);
1338         suffix += len;
1339         j += len;
1340     }
1341 
1342     *result = xmlStrdup(xmlBufferContent(buffer));
1343     xmlBufferFree(buffer);
1344     return status;
1345 }
1346 
1347