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