Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 /*
7 * Portable safe sprintf code.
8 *
9 * Code based on mozilla/nsprpub/src/io/prprf.c rev 3.7
10 *
11 * Contributor(s):
12 * Kipp E.B. Hickman <kipp@netscape.com> (original author)
13 * Frank Yung-Fong Tang <ftang@netscape.com>
14 * Daniele Nicolodi <daniele@grinta.net>
15 */
17 /*
18 * Copied from xpcom/ds/nsTextFormatter.cpp r1.22
19 * Changed to use nsMemory and Frozen linkage
20 * -- Prasad <prasad@medhas.org>
21 */
23 #include <stdarg.h>
24 #include <stddef.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include "prdtoa.h"
28 #include "prlog.h"
29 #include "prprf.h"
30 #include "prmem.h"
31 #include "nsCRTGlue.h"
32 #include "nsTextFormatter.h"
33 #include "nsMemory.h"
35 /*
36 ** Note: on some platforms va_list is defined as an array,
37 ** and requires array notation.
38 */
40 #ifdef HAVE_VA_COPY
41 #define VARARGS_ASSIGN(foo, bar) VA_COPY(foo,bar)
42 #elif defined(HAVE_VA_LIST_AS_ARRAY)
43 #define VARARGS_ASSIGN(foo, bar) foo[0] = bar[0]
44 #else
45 #define VARARGS_ASSIGN(foo, bar) (foo) = (bar)
46 #endif
48 typedef struct SprintfStateStr SprintfState;
50 struct SprintfStateStr {
51 int (*stuff)(SprintfState *ss, const char16_t *sp, uint32_t len);
53 char16_t *base;
54 char16_t *cur;
55 uint32_t maxlen;
57 void *stuffclosure;
58 };
60 /*
61 ** Numbered Arguement State
62 */
63 struct NumArgState{
64 int type; /* type of the current ap */
65 va_list ap; /* point to the corresponding position on ap */
67 enum Type {
68 INT16,
69 UINT16,
70 INTN,
71 UINTN,
72 INT32,
73 UINT32,
74 INT64,
75 UINT64,
76 STRING,
77 DOUBLE,
78 INTSTR,
79 UNISTRING,
80 UNKNOWN
81 };
82 };
84 #define NAS_DEFAULT_NUM 20 /* default number of NumberedArgumentState array */
86 #define _LEFT 0x1
87 #define _SIGNED 0x2
88 #define _SPACED 0x4
89 #define _ZEROS 0x8
90 #define _NEG 0x10
92 #define ELEMENTS_OF(array_) (sizeof(array_) / sizeof(array_[0]))
94 /*
95 ** Fill into the buffer using the data in src
96 */
97 static int fill2(SprintfState *ss, const char16_t *src, int srclen,
98 int width, int flags)
99 {
100 char16_t space = ' ';
101 int rv;
103 width -= srclen;
104 /* Right adjusting */
105 if ((width > 0) && ((flags & _LEFT) == 0)) {
106 if (flags & _ZEROS) {
107 space = '0';
108 }
109 while (--width >= 0) {
110 rv = (*ss->stuff)(ss, &space, 1);
111 if (rv < 0) {
112 return rv;
113 }
114 }
115 }
117 /* Copy out the source data */
118 rv = (*ss->stuff)(ss, src, srclen);
119 if (rv < 0) {
120 return rv;
121 }
123 /* Left adjusting */
124 if ((width > 0) && ((flags & _LEFT) != 0)) {
125 while (--width >= 0) {
126 rv = (*ss->stuff)(ss, &space, 1);
127 if (rv < 0) {
128 return rv;
129 }
130 }
131 }
132 return 0;
133 }
135 /*
136 ** Fill a number. The order is: optional-sign zero-filling conversion-digits
137 */
138 static int fill_n(SprintfState *ss, const char16_t *src, int srclen,
139 int width, int prec, int type, int flags)
140 {
141 int zerowidth = 0;
142 int precwidth = 0;
143 int signwidth = 0;
144 int leftspaces = 0;
145 int rightspaces = 0;
146 int cvtwidth;
147 int rv;
148 char16_t sign;
149 char16_t space = ' ';
150 char16_t zero = '0';
152 if ((type & 1) == 0) {
153 if (flags & _NEG) {
154 sign = '-';
155 signwidth = 1;
156 } else if (flags & _SIGNED) {
157 sign = '+';
158 signwidth = 1;
159 } else if (flags & _SPACED) {
160 sign = ' ';
161 signwidth = 1;
162 }
163 }
164 cvtwidth = signwidth + srclen;
166 if (prec > 0) {
167 if (prec > srclen) {
168 /* Need zero filling */
169 precwidth = prec - srclen;
170 cvtwidth += precwidth;
171 }
172 }
174 if ((flags & _ZEROS) && (prec < 0)) {
175 if (width > cvtwidth) {
176 /* Zero filling */
177 zerowidth = width - cvtwidth;
178 cvtwidth += zerowidth;
179 }
180 }
182 if (flags & _LEFT) {
183 if (width > cvtwidth) {
184 /* Space filling on the right (i.e. left adjusting) */
185 rightspaces = width - cvtwidth;
186 }
187 } else {
188 if (width > cvtwidth) {
189 /* Space filling on the left (i.e. right adjusting) */
190 leftspaces = width - cvtwidth;
191 }
192 }
193 while (--leftspaces >= 0) {
194 rv = (*ss->stuff)(ss, &space, 1);
195 if (rv < 0) {
196 return rv;
197 }
198 }
199 if (signwidth) {
200 rv = (*ss->stuff)(ss, &sign, 1);
201 if (rv < 0) {
202 return rv;
203 }
204 }
205 while (--precwidth >= 0) {
206 rv = (*ss->stuff)(ss, &space, 1);
207 if (rv < 0) {
208 return rv;
209 }
210 }
211 while (--zerowidth >= 0) {
212 rv = (*ss->stuff)(ss, &zero, 1);
213 if (rv < 0) {
214 return rv;
215 }
216 }
217 rv = (*ss->stuff)(ss, src, srclen);
218 if (rv < 0) {
219 return rv;
220 }
221 while (--rightspaces >= 0) {
222 rv = (*ss->stuff)(ss, &space, 1);
223 if (rv < 0) {
224 return rv;
225 }
226 }
227 return 0;
228 }
230 /*
231 ** Convert a long into its printable form
232 */
233 static int cvt_l(SprintfState *ss, long num, int width, int prec,
234 int radix, int type, int flags, const char16_t *hexp)
235 {
236 char16_t cvtbuf[100];
237 char16_t *cvt;
238 int digits;
240 /* according to the man page this needs to happen */
241 if ((prec == 0) && (num == 0)) {
242 return 0;
243 }
245 /*
246 ** Converting decimal is a little tricky. In the unsigned case we
247 ** need to stop when we hit 10 digits. In the signed case, we can
248 ** stop when the number is zero.
249 */
250 cvt = &cvtbuf[0] + ELEMENTS_OF(cvtbuf);
251 digits = 0;
252 while (num) {
253 int digit = (((unsigned long)num) % radix) & 0xF;
254 *--cvt = hexp[digit];
255 digits++;
256 num = (long)(((unsigned long)num) / radix);
257 }
258 if (digits == 0) {
259 *--cvt = '0';
260 digits++;
261 }
263 /*
264 ** Now that we have the number converted without its sign, deal with
265 ** the sign and zero padding.
266 */
267 return fill_n(ss, cvt, digits, width, prec, type, flags);
268 }
270 /*
271 ** Convert a 64-bit integer into its printable form
272 */
273 static int cvt_ll(SprintfState *ss, int64_t num, int width, int prec,
274 int radix, int type, int flags, const char16_t *hexp)
275 {
276 char16_t cvtbuf[100];
277 char16_t *cvt;
278 int digits;
279 int64_t rad;
281 /* according to the man page this needs to happen */
282 if (prec == 0 && num == 0) {
283 return 0;
284 }
286 /*
287 ** Converting decimal is a little tricky. In the unsigned case we
288 ** need to stop when we hit 10 digits. In the signed case, we can
289 ** stop when the number is zero.
290 */
291 rad = radix;
292 cvt = &cvtbuf[0] + ELEMENTS_OF(cvtbuf);
293 digits = 0;
294 while (num != 0) {
295 *--cvt = hexp[int32_t(num % rad) & 0xf];
296 digits++;
297 num /= rad;
298 }
299 if (digits == 0) {
300 *--cvt = '0';
301 digits++;
302 }
304 /*
305 ** Now that we have the number converted without its sign, deal with
306 ** the sign and zero padding.
307 */
308 return fill_n(ss, cvt, digits, width, prec, type, flags);
309 }
311 /*
312 ** Convert a double precision floating point number into its printable
313 ** form.
314 */
315 static int cvt_f(SprintfState *ss, double d, int width, int prec,
316 const char16_t type, int flags)
317 {
318 int mode = 2;
319 int decpt;
320 int sign;
321 char buf[256];
322 char * bufp = buf;
323 int bufsz = 256;
324 char num[256];
325 char * nump;
326 char * endnum;
327 int numdigits = 0;
328 char exp = 'e';
330 if (prec == -1) {
331 prec = 6;
332 } else if (prec > 50) {
333 // limit precision to avoid PR_dtoa bug 108335
334 // and to prevent buffers overflows
335 prec = 50;
336 }
338 switch (type) {
339 case 'f':
340 numdigits = prec;
341 mode = 3;
342 break;
343 case 'E':
344 exp = 'E';
345 // no break
346 case 'e':
347 numdigits = prec + 1;
348 mode = 2;
349 break;
350 case 'G':
351 exp = 'E';
352 // no break
353 case 'g':
354 if (prec == 0) {
355 prec = 1;
356 }
357 numdigits = prec;
358 mode = 2;
359 break;
360 default:
361 NS_ERROR("invalid type passed to cvt_f");
362 }
364 if (PR_dtoa(d, mode, numdigits, &decpt, &sign, &endnum, num, bufsz) == PR_FAILURE) {
365 buf[0] = '\0';
366 return -1;
367 }
368 numdigits = endnum - num;
369 nump = num;
371 if (sign) {
372 *bufp++ = '-';
373 } else if (flags & _SIGNED) {
374 *bufp++ = '+';
375 }
377 if (decpt == 9999) {
378 while ((*bufp++ = *nump++)) { }
379 } else {
381 switch (type) {
383 case 'E':
384 case 'e':
386 *bufp++ = *nump++;
387 if (prec > 0) {
388 *bufp++ = '.';
389 while (*nump) {
390 *bufp++ = *nump++;
391 prec--;
392 }
393 while (prec-- > 0) {
394 *bufp++ = '0';
395 }
396 }
397 *bufp++ = exp;
398 PR_snprintf(bufp, bufsz - (bufp - buf), "%+03d", decpt-1);
399 break;
401 case 'f':
403 if (decpt < 1) {
404 *bufp++ = '0';
405 if (prec > 0) {
406 *bufp++ = '.';
407 while (decpt++ && prec-- > 0) {
408 *bufp++ = '0';
409 }
410 while (*nump && prec-- > 0) {
411 *bufp++ = *nump++;
412 }
413 while (prec-- > 0) {
414 *bufp++ = '0';
415 }
416 }
417 } else {
418 while (*nump && decpt-- > 0) {
419 *bufp++ = *nump++;
420 }
421 while (decpt-- > 0) {
422 *bufp++ = '0';
423 }
424 if (prec > 0) {
425 *bufp++ = '.';
426 while (*nump && prec-- > 0) {
427 *bufp++ = *nump++;
428 }
429 while (prec-- > 0) {
430 *bufp++ = '0';
431 }
432 }
433 }
434 *bufp = '\0';
435 break;
437 case 'G':
438 case 'g':
440 if ((decpt < -3) || ((decpt - 1) >= prec)) {
441 *bufp++ = *nump++;
442 numdigits--;
443 if (numdigits > 0) {
444 *bufp++ = '.';
445 while (*nump) {
446 *bufp++ = *nump++;
447 }
448 }
449 *bufp++ = exp;
450 PR_snprintf(bufp, bufsz - (bufp - buf), "%+03d", decpt-1);
451 } else {
452 if (decpt < 1) {
453 *bufp++ = '0';
454 if (prec > 0) {
455 *bufp++ = '.';
456 while (decpt++) {
457 *bufp++ = '0';
458 }
459 while (*nump) {
460 *bufp++ = *nump++;
461 }
462 }
463 } else {
464 while (*nump && decpt-- > 0) {
465 *bufp++ = *nump++;
466 numdigits--;
467 }
468 while (decpt-- > 0) {
469 *bufp++ = '0';
470 }
471 if (numdigits > 0) {
472 *bufp++ = '.';
473 while (*nump) {
474 *bufp++ = *nump++;
475 }
476 }
477 }
478 *bufp = '\0';
479 }
480 }
481 }
483 char16_t rbuf[256];
484 char16_t *rbufp = rbuf;
485 bufp = buf;
486 // cast to char16_t
487 while ((*rbufp++ = *bufp++)) { }
488 *rbufp = '\0';
490 return fill2(ss, rbuf, NS_strlen(rbuf), width, flags);
491 }
493 /*
494 ** Convert a string into its printable form. "width" is the output
495 ** width. "prec" is the maximum number of characters of "s" to output,
496 ** where -1 means until NUL.
497 */
498 static int cvt_S(SprintfState *ss, const char16_t *s, int width,
499 int prec, int flags)
500 {
501 int slen;
503 if (prec == 0) {
504 return 0;
505 }
507 /* Limit string length by precision value */
508 slen = s ? NS_strlen(s) : 6;
509 if (prec > 0) {
510 if (prec < slen) {
511 slen = prec;
512 }
513 }
515 /* and away we go */
516 return fill2(ss, s ? s : MOZ_UTF16("(null)"), slen, width, flags);
517 }
519 /*
520 ** Convert a string into its printable form. "width" is the output
521 ** width. "prec" is the maximum number of characters of "s" to output,
522 ** where -1 means until NUL.
523 */
524 static int cvt_s(SprintfState *ss, const char *s, int width,
525 int prec, int flags)
526 {
527 NS_ConvertUTF8toUTF16 utf16Val(s);
528 return cvt_S(ss, utf16Val.get(), width, prec, flags);
529 }
531 /*
532 ** BuildArgArray stands for Numbered Argument list Sprintf
533 ** for example,
534 ** fmp = "%4$i, %2$d, %3s, %1d";
535 ** the number must start from 1, and no gap among them
536 */
538 static struct NumArgState* BuildArgArray(const char16_t *fmt,
539 va_list ap, int * rv,
540 struct NumArgState * nasArray)
541 {
542 int number = 0, cn = 0, i;
543 const char16_t* p;
544 char16_t c;
545 struct NumArgState* nas;
547 /*
548 ** first pass:
549 ** detemine how many legal % I have got, then allocate space
550 */
551 p = fmt;
552 *rv = 0;
553 i = 0;
554 while ((c = *p++) != 0) {
555 if (c != '%') {
556 continue;
557 }
558 /* skip %% case */
559 if ((c = *p++) == '%') {
560 continue;
561 }
563 while( c != 0 ){
564 if (c > '9' || c < '0') {
565 /* numbered argument csae */
566 if (c == '$') {
567 if (i > 0) {
568 *rv = -1;
569 return nullptr;
570 }
571 number++;
572 break;
574 } else {
575 /* non-numbered argument case */
576 if (number > 0) {
577 *rv = -1;
578 return nullptr;
579 }
580 i = 1;
581 break;
582 }
583 }
584 c = *p++;
585 }
586 }
588 if (number == 0) {
589 return nullptr;
590 }
592 if (number > NAS_DEFAULT_NUM) {
593 nas = (struct NumArgState*)nsMemory::Alloc(number * sizeof(struct NumArgState));
594 if (!nas) {
595 *rv = -1;
596 return nullptr;
597 }
598 } else {
599 nas = nasArray;
600 }
602 for (i = 0; i < number; i++) {
603 nas[i].type = NumArgState::UNKNOWN;
604 }
606 /*
607 ** second pass:
608 ** set nas[].type
609 */
610 p = fmt;
611 while ((c = *p++) != 0) {
612 if (c != '%') {
613 continue;
614 }
615 c = *p++;
616 if (c == '%') {
617 continue;
618 }
619 cn = 0;
620 /* should imporve error check later */
621 while (c && c != '$') {
622 cn = cn*10 + c - '0';
623 c = *p++;
624 }
626 if (!c || cn < 1 || cn > number) {
627 *rv = -1;
628 break;
629 }
631 /* nas[cn] starts from 0, and make sure
632 nas[cn].type is not assigned */
633 cn--;
634 if (nas[cn].type != NumArgState::UNKNOWN) {
635 continue;
636 }
638 c = *p++;
640 /* width */
641 if (c == '*') {
642 /* not supported feature, for the argument is not numbered */
643 *rv = -1;
644 break;
645 } else {
646 while ((c >= '0') && (c <= '9')) {
647 c = *p++;
648 }
649 }
651 /* precision */
652 if (c == '.') {
653 c = *p++;
654 if (c == '*') {
655 /* not supported feature, for the argument is not numbered */
656 *rv = -1;
657 break;
658 } else {
659 while ((c >= '0') && (c <= '9')) {
660 c = *p++;
661 }
662 }
663 }
665 /* size */
666 nas[cn].type = NumArgState::INTN;
667 if (c == 'h') {
668 nas[cn].type = NumArgState::INT16;
669 c = *p++;
670 } else if (c == 'L') {
671 /* XXX not quite sure here */
672 nas[cn].type = NumArgState::INT64;
673 c = *p++;
674 } else if (c == 'l') {
675 nas[cn].type = NumArgState::INT32;
676 c = *p++;
677 if (c == 'l') {
678 nas[cn].type = NumArgState::INT64;
679 c = *p++;
680 }
681 }
683 /* format */
684 switch (c) {
685 case 'd':
686 case 'c':
687 case 'i':
688 case 'o':
689 case 'u':
690 case 'x':
691 case 'X':
692 break;
694 case 'e':
695 case 'f':
696 case 'g':
697 nas[cn].type = NumArgState::DOUBLE;
698 break;
700 case 'p':
701 /* XXX should use cpp */
702 if (sizeof(void *) == sizeof(int32_t)) {
703 nas[cn].type = NumArgState::UINT32;
704 } else if (sizeof(void *) == sizeof(int64_t)) {
705 nas[cn].type = NumArgState::UINT64;
706 } else if (sizeof(void *) == sizeof(int)) {
707 nas[cn].type = NumArgState::UINTN;
708 } else {
709 nas[cn].type = NumArgState::UNKNOWN;
710 }
711 break;
713 case 'C':
714 /* XXX not supported I suppose */
715 PR_ASSERT(0);
716 nas[cn].type = NumArgState::UNKNOWN;
717 break;
719 case 'S':
720 nas[cn].type = NumArgState::UNISTRING;
721 break;
723 case 's':
724 nas[cn].type = NumArgState::STRING;
725 break;
727 case 'n':
728 nas[cn].type = NumArgState::INTSTR;
729 break;
731 default:
732 PR_ASSERT(0);
733 nas[cn].type = NumArgState::UNKNOWN;
734 break;
735 }
737 /* get a legal para. */
738 if (nas[cn].type == NumArgState::UNKNOWN) {
739 *rv = -1;
740 break;
741 }
742 }
745 /*
746 ** third pass
747 ** fill the nas[cn].ap
748 */
749 if (*rv < 0) {
750 if( nas != nasArray ) {
751 PR_DELETE(nas);
752 }
753 return nullptr;
754 }
756 cn = 0;
757 while (cn < number) {
758 if (nas[cn].type == NumArgState::UNKNOWN) {
759 cn++;
760 continue;
761 }
763 VARARGS_ASSIGN(nas[cn].ap, ap);
765 switch (nas[cn].type) {
766 case NumArgState::INT16:
767 case NumArgState::UINT16:
768 case NumArgState::INTN:
769 case NumArgState::UINTN: (void)va_arg(ap, int); break;
771 case NumArgState::INT32: (void)va_arg(ap, int32_t); break;
773 case NumArgState::UINT32: (void)va_arg(ap, uint32_t); break;
775 case NumArgState::INT64: (void)va_arg(ap, int64_t); break;
777 case NumArgState::UINT64: (void)va_arg(ap, uint64_t); break;
779 case NumArgState::STRING: (void)va_arg(ap, char*); break;
781 case NumArgState::INTSTR: (void)va_arg(ap, int*); break;
783 case NumArgState::DOUBLE: (void)va_arg(ap, double); break;
785 case NumArgState::UNISTRING: (void)va_arg(ap, char16_t*); break;
787 default:
788 if( nas != nasArray ) {
789 PR_DELETE( nas );
790 }
791 *rv = -1;
792 return nullptr;
793 }
794 cn++;
795 }
796 return nas;
797 }
799 /*
800 ** The workhorse sprintf code.
801 */
802 static int dosprintf(SprintfState *ss, const char16_t *fmt, va_list ap)
803 {
804 char16_t c;
805 int flags, width, prec, radix, type;
806 union {
807 char16_t ch;
808 int i;
809 long l;
810 int64_t ll;
811 double d;
812 const char *s;
813 const char16_t *S;
814 int *ip;
815 } u;
816 char16_t space = ' ';
818 nsAutoString hex;
819 hex.AssignLiteral("0123456789abcdef");
821 nsAutoString HEX;
822 HEX.AssignLiteral("0123456789ABCDEF");
824 const char16_t *hexp;
825 int rv, i;
826 struct NumArgState* nas = nullptr;
827 struct NumArgState nasArray[NAS_DEFAULT_NUM];
830 /*
831 ** build an argument array, IF the fmt is numbered argument
832 ** list style, to contain the Numbered Argument list pointers
833 */
834 nas = BuildArgArray (fmt, ap, &rv, nasArray);
835 if (rv < 0) {
836 /* the fmt contains error Numbered Argument format, jliu@netscape.com */
837 PR_ASSERT(0);
838 return rv;
839 }
841 while ((c = *fmt++) != 0) {
842 if (c != '%') {
843 rv = (*ss->stuff)(ss, fmt - 1, 1);
844 if (rv < 0) {
845 return rv;
846 }
847 continue;
848 }
850 /*
851 ** Gobble up the % format string. Hopefully we have handled all
852 ** of the strange cases!
853 */
854 flags = 0;
855 c = *fmt++;
856 if (c == '%') {
857 /* quoting a % with %% */
858 rv = (*ss->stuff)(ss, fmt - 1, 1);
859 if (rv < 0) {
860 return rv;
861 }
862 continue;
863 }
865 if (nas != nullptr) {
866 /* the fmt contains the Numbered Arguments feature */
867 i = 0;
868 /* should imporve error check later */
869 while (c && c != '$') {
870 i = (i * 10) + (c - '0');
871 c = *fmt++;
872 }
874 if (nas[i-1].type == NumArgState::UNKNOWN) {
875 if (nas && (nas != nasArray)) {
876 PR_DELETE(nas);
877 }
878 return -1;
879 }
881 VARARGS_ASSIGN(ap, nas[i-1].ap);
882 c = *fmt++;
883 }
885 /*
886 * Examine optional flags. Note that we do not implement the
887 * '#' flag of sprintf(). The ANSI C spec. of the '#' flag is
888 * somewhat ambiguous and not ideal, which is perhaps why
889 * the various sprintf() implementations are inconsistent
890 * on this feature.
891 */
892 while ((c == '-') || (c == '+') || (c == ' ') || (c == '0')) {
893 if (c == '-') flags |= _LEFT;
894 if (c == '+') flags |= _SIGNED;
895 if (c == ' ') flags |= _SPACED;
896 if (c == '0') flags |= _ZEROS;
897 c = *fmt++;
898 }
899 if (flags & _SIGNED) flags &= ~_SPACED;
900 if (flags & _LEFT) flags &= ~_ZEROS;
902 /* width */
903 if (c == '*') {
904 c = *fmt++;
905 width = va_arg(ap, int);
906 } else {
907 width = 0;
908 while ((c >= '0') && (c <= '9')) {
909 width = (width * 10) + (c - '0');
910 c = *fmt++;
911 }
912 }
914 /* precision */
915 prec = -1;
916 if (c == '.') {
917 c = *fmt++;
918 if (c == '*') {
919 c = *fmt++;
920 prec = va_arg(ap, int);
921 } else {
922 prec = 0;
923 while ((c >= '0') && (c <= '9')) {
924 prec = (prec * 10) + (c - '0');
925 c = *fmt++;
926 }
927 }
928 }
930 /* size */
931 type = NumArgState::INTN;
932 if (c == 'h') {
933 type = NumArgState::INT16;
934 c = *fmt++;
935 } else if (c == 'L') {
936 /* XXX not quite sure here */
937 type = NumArgState::INT64;
938 c = *fmt++;
939 } else if (c == 'l') {
940 type = NumArgState::INT32;
941 c = *fmt++;
942 if (c == 'l') {
943 type = NumArgState::INT64;
944 c = *fmt++;
945 }
946 }
948 /* format */
949 hexp = hex.get();
950 switch (c) {
951 case 'd':
952 case 'i': /* decimal/integer */
953 radix = 10;
954 goto fetch_and_convert;
956 case 'o': /* octal */
957 radix = 8;
958 type |= 1;
959 goto fetch_and_convert;
961 case 'u': /* unsigned decimal */
962 radix = 10;
963 type |= 1;
964 goto fetch_and_convert;
966 case 'x': /* unsigned hex */
967 radix = 16;
968 type |= 1;
969 goto fetch_and_convert;
971 case 'X': /* unsigned HEX */
972 radix = 16;
973 hexp = HEX.get();
974 type |= 1;
975 goto fetch_and_convert;
977 fetch_and_convert:
978 switch (type) {
979 case NumArgState::INT16:
980 u.l = va_arg(ap, int);
981 if (u.l < 0) {
982 u.l = -u.l;
983 flags |= _NEG;
984 }
985 goto do_long;
986 case NumArgState::UINT16:
987 u.l = va_arg(ap, int) & 0xffff;
988 goto do_long;
989 case NumArgState::INTN:
990 u.l = va_arg(ap, int);
991 if (u.l < 0) {
992 u.l = -u.l;
993 flags |= _NEG;
994 }
995 goto do_long;
996 case NumArgState::UINTN:
997 u.l = (long)va_arg(ap, unsigned int);
998 goto do_long;
1000 case NumArgState::INT32:
1001 u.l = va_arg(ap, int32_t);
1002 if (u.l < 0) {
1003 u.l = -u.l;
1004 flags |= _NEG;
1005 }
1006 goto do_long;
1007 case NumArgState::UINT32:
1008 u.l = (long)va_arg(ap, uint32_t);
1009 do_long:
1010 rv = cvt_l(ss, u.l, width, prec, radix, type, flags, hexp);
1011 if (rv < 0) {
1012 return rv;
1013 }
1014 break;
1016 case NumArgState::INT64:
1017 u.ll = va_arg(ap, int64_t);
1018 if (u.ll < 0) {
1019 u.ll = -u.ll;
1020 flags |= _NEG;
1021 }
1022 goto do_longlong;
1023 case NumArgState::UINT64:
1024 u.ll = va_arg(ap, uint64_t);
1025 do_longlong:
1026 rv = cvt_ll(ss, u.ll, width, prec, radix, type, flags, hexp);
1027 if (rv < 0) {
1028 return rv;
1029 }
1030 break;
1031 }
1032 break;
1034 case 'e':
1035 case 'E':
1036 case 'f':
1037 case 'g':
1038 case 'G':
1039 u.d = va_arg(ap, double);
1040 rv = cvt_f(ss, u.d, width, prec, c, flags);
1041 if (rv < 0) {
1042 return rv;
1043 }
1044 break;
1046 case 'c':
1047 u.ch = va_arg(ap, int);
1048 if ((flags & _LEFT) == 0) {
1049 while (width-- > 1) {
1050 rv = (*ss->stuff)(ss, &space, 1);
1051 if (rv < 0) {
1052 return rv;
1053 }
1054 }
1055 }
1056 rv = (*ss->stuff)(ss, &u.ch, 1);
1057 if (rv < 0) {
1058 return rv;
1059 }
1060 if (flags & _LEFT) {
1061 while (width-- > 1) {
1062 rv = (*ss->stuff)(ss, &space, 1);
1063 if (rv < 0) {
1064 return rv;
1065 }
1066 }
1067 }
1068 break;
1070 case 'p':
1071 if (sizeof(void *) == sizeof(int32_t)) {
1072 type = NumArgState::UINT32;
1073 } else if (sizeof(void *) == sizeof(int64_t)) {
1074 type = NumArgState::UINT64;
1075 } else if (sizeof(void *) == sizeof(int)) {
1076 type = NumArgState::UINTN;
1077 } else {
1078 PR_ASSERT(0);
1079 break;
1080 }
1081 radix = 16;
1082 goto fetch_and_convert;
1084 #if 0
1085 case 'C':
1086 /* XXX not supported I suppose */
1087 PR_ASSERT(0);
1088 break;
1089 #endif
1091 case 'S':
1092 u.S = va_arg(ap, const char16_t*);
1093 rv = cvt_S(ss, u.S, width, prec, flags);
1094 if (rv < 0) {
1095 return rv;
1096 }
1097 break;
1099 case 's':
1100 u.s = va_arg(ap, const char*);
1101 rv = cvt_s(ss, u.s, width, prec, flags);
1102 if (rv < 0) {
1103 return rv;
1104 }
1105 break;
1107 case 'n':
1108 u.ip = va_arg(ap, int*);
1109 if (u.ip) {
1110 *u.ip = ss->cur - ss->base;
1111 }
1112 break;
1114 default:
1115 /* Not a % token after all... skip it */
1116 #if 0
1117 PR_ASSERT(0);
1118 #endif
1119 char16_t perct = '%';
1120 rv = (*ss->stuff)(ss, &perct, 1);
1121 if (rv < 0) {
1122 return rv;
1123 }
1124 rv = (*ss->stuff)(ss, fmt - 1, 1);
1125 if (rv < 0) {
1126 return rv;
1127 }
1128 }
1129 }
1131 /* Stuff trailing NUL */
1132 char16_t null = '\0';
1134 rv = (*ss->stuff)(ss, &null, 1);
1136 if( nas && ( nas != nasArray ) ){
1137 PR_DELETE( nas );
1138 }
1140 return rv;
1141 }
1143 /************************************************************************/
1145 static int
1146 StringStuff(SprintfState* ss, const char16_t* sp, uint32_t len)
1147 {
1148 if (*sp == '\0')
1149 return 0;
1151 ptrdiff_t off = ss->cur - ss->base;
1153 nsAString* str = static_cast<nsAString*>(ss->stuffclosure);
1154 str->Append(sp, len);
1156 ss->base = str->BeginWriting();
1157 ss->cur = ss->base + off;
1159 return 0;
1160 }
1162 /*
1163 ** Stuff routine that automatically grows the malloc'd output buffer
1164 ** before it overflows.
1165 */
1166 static int GrowStuff(SprintfState *ss, const char16_t *sp, uint32_t len)
1167 {
1168 ptrdiff_t off;
1169 char16_t *newbase;
1170 uint32_t newlen;
1172 off = ss->cur - ss->base;
1173 if (off + len >= ss->maxlen) {
1174 /* Grow the buffer */
1175 newlen = ss->maxlen + ((len > 32) ? len : 32);
1176 if (ss->base) {
1177 newbase = (char16_t*) nsMemory::Realloc(ss->base, newlen*sizeof(char16_t));
1178 } else {
1179 newbase = (char16_t*) nsMemory::Alloc(newlen*sizeof(char16_t));
1180 }
1181 if (!newbase) {
1182 /* Ran out of memory */
1183 return -1;
1184 }
1185 ss->base = newbase;
1186 ss->maxlen = newlen;
1187 ss->cur = ss->base + off;
1188 }
1190 /* Copy data */
1191 while (len) {
1192 --len;
1193 *ss->cur++ = *sp++;
1194 }
1195 PR_ASSERT((uint32_t)(ss->cur - ss->base) <= ss->maxlen);
1196 return 0;
1197 }
1199 /*
1200 ** sprintf into a malloc'd buffer
1201 */
1202 char16_t * nsTextFormatter::smprintf(const char16_t *fmt, ...)
1203 {
1204 va_list ap;
1205 char16_t *rv;
1207 va_start(ap, fmt);
1208 rv = nsTextFormatter::vsmprintf(fmt, ap);
1209 va_end(ap);
1210 return rv;
1211 }
1213 uint32_t nsTextFormatter::ssprintf(nsAString& out, const char16_t* fmt, ...)
1214 {
1215 va_list ap;
1216 uint32_t rv;
1218 va_start(ap, fmt);
1219 rv = nsTextFormatter::vssprintf(out, fmt, ap);
1220 va_end(ap);
1221 return rv;
1222 }
1224 uint32_t nsTextFormatter::vssprintf(nsAString& out, const char16_t* fmt, va_list ap)
1225 {
1226 SprintfState ss;
1227 ss.stuff = StringStuff;
1228 ss.base = 0;
1229 ss.cur = 0;
1230 ss.maxlen = 0;
1231 ss.stuffclosure = &out;
1233 out.Truncate();
1234 int n = dosprintf(&ss, fmt, ap);
1235 return n ? n - 1 : n;
1236 }
1238 char16_t * nsTextFormatter::vsmprintf(const char16_t *fmt, va_list ap)
1239 {
1240 SprintfState ss;
1241 int rv;
1243 ss.stuff = GrowStuff;
1244 ss.base = 0;
1245 ss.cur = 0;
1246 ss.maxlen = 0;
1247 rv = dosprintf(&ss, fmt, ap);
1248 if (rv < 0) {
1249 if (ss.base) {
1250 PR_DELETE(ss.base);
1251 }
1252 return 0;
1253 }
1254 return ss.base;
1255 }
1257 /*
1258 ** Stuff routine that discards overflow data
1259 */
1260 static int LimitStuff(SprintfState *ss, const char16_t *sp, uint32_t len)
1261 {
1262 uint32_t limit = ss->maxlen - (ss->cur - ss->base);
1264 if (len > limit) {
1265 len = limit;
1266 }
1267 while (len) {
1268 --len;
1269 *ss->cur++ = *sp++;
1270 }
1271 return 0;
1272 }
1274 /*
1275 ** sprintf into a fixed size buffer. Make sure there is a NUL at the end
1276 ** when finished.
1277 */
1278 uint32_t nsTextFormatter::snprintf(char16_t *out, uint32_t outlen, const char16_t *fmt, ...)
1279 {
1280 va_list ap;
1281 uint32_t rv;
1283 PR_ASSERT((int32_t)outlen > 0);
1284 if ((int32_t)outlen <= 0) {
1285 return 0;
1286 }
1288 va_start(ap, fmt);
1289 rv = nsTextFormatter::vsnprintf(out, outlen, fmt, ap);
1290 va_end(ap);
1291 return rv;
1292 }
1294 uint32_t nsTextFormatter::vsnprintf(char16_t *out, uint32_t outlen,const char16_t *fmt,
1295 va_list ap)
1296 {
1297 SprintfState ss;
1298 uint32_t n;
1300 PR_ASSERT((int32_t)outlen > 0);
1301 if ((int32_t)outlen <= 0) {
1302 return 0;
1303 }
1305 ss.stuff = LimitStuff;
1306 ss.base = out;
1307 ss.cur = out;
1308 ss.maxlen = outlen;
1309 (void) dosprintf(&ss, fmt, ap);
1311 /* If we added chars, and we didn't append a null, do it now. */
1312 if( (ss.cur != ss.base) && (*(ss.cur - 1) != '\0') )
1313 *(--ss.cur) = '\0';
1315 n = ss.cur - ss.base;
1316 return n ? n - 1 : n;
1317 }
1319 /*
1320 * Free memory allocated, for the caller, by smprintf
1321 */
1322 void nsTextFormatter::smprintf_free(char16_t *mem)
1323 {
1324 nsMemory::Free(mem);
1325 }