Coverage Report

Created: 2024-01-20 12:31

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