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