Coverage Report

Created: 2025-08-29 06:38

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