Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(150)

Side by Side Diff: third_party/libxslt/libxslt/numbers.c

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

Powered by Google App Engine
This is Rietveld 408576698