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