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