xpcom/glue/nsTextFormatter.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

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;
  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;
  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;
  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;
  1030 		break;
  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;
  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;
  1056 	    rv = (*ss->stuff)(ss, &u.ch, 1);
  1057 	    if (rv < 0) {
  1058 		return rv;
  1060             if (flags & _LEFT) {
  1061                 while (width-- > 1) {
  1062                     rv = (*ss->stuff)(ss, &space, 1);
  1063                     if (rv < 0) {
  1064                         return rv;
  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;
  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;
  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;
  1105 	    break;
  1107         case 'n':
  1108 	    u.ip = va_arg(ap, int*);
  1109 	    if (u.ip) {
  1110 		*u.ip = ss->cur - ss->base;
  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;
  1124 	    rv = (*ss->stuff)(ss, fmt - 1, 1);
  1125 	    if (rv < 0) {
  1126 		return rv;
  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 );
  1140     return rv;
  1143 /************************************************************************/
  1145 static int
  1146 StringStuff(SprintfState* ss, const char16_t* sp, uint32_t len)
  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;
  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)
  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));
  1181 	if (!newbase) {
  1182 	    /* Ran out of memory */
  1183 	    return -1;
  1185 	ss->base = newbase;
  1186 	ss->maxlen = newlen;
  1187 	ss->cur = ss->base + off;
  1190     /* Copy data */
  1191     while (len) {
  1192 	--len;
  1193 	*ss->cur++ = *sp++;
  1195     PR_ASSERT((uint32_t)(ss->cur - ss->base) <= ss->maxlen);
  1196     return 0;
  1199 /*
  1200 ** sprintf into a malloc'd buffer
  1201 */
  1202 char16_t * nsTextFormatter::smprintf(const char16_t *fmt, ...)
  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;
  1213 uint32_t nsTextFormatter::ssprintf(nsAString& out, const char16_t* fmt, ...)
  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;
  1224 uint32_t nsTextFormatter::vssprintf(nsAString& out, const char16_t* fmt, va_list ap)
  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;
  1238 char16_t * nsTextFormatter::vsmprintf(const char16_t *fmt, va_list ap)
  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);
  1252 	return 0;
  1254     return ss.base;
  1257 /*
  1258 ** Stuff routine that discards overflow data
  1259 */
  1260 static int LimitStuff(SprintfState *ss, const char16_t *sp, uint32_t len)
  1262     uint32_t limit = ss->maxlen - (ss->cur - ss->base);
  1264     if (len > limit) {
  1265 	len = limit;
  1267     while (len) {
  1268 	--len;
  1269 	*ss->cur++ = *sp++;
  1271     return 0;
  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, ...)
  1280     va_list ap;
  1281     uint32_t rv;
  1283     PR_ASSERT((int32_t)outlen > 0);
  1284     if ((int32_t)outlen <= 0) {
  1285 	return 0;
  1288     va_start(ap, fmt);
  1289     rv = nsTextFormatter::vsnprintf(out, outlen, fmt, ap);
  1290     va_end(ap);
  1291     return rv;
  1294 uint32_t nsTextFormatter::vsnprintf(char16_t *out, uint32_t outlen,const char16_t *fmt,
  1295                                     va_list ap)
  1297     SprintfState ss;
  1298     uint32_t n;
  1300     PR_ASSERT((int32_t)outlen > 0);
  1301     if ((int32_t)outlen <= 0) {
  1302 	return 0;
  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;
  1319 /*
  1320  * Free memory allocated, for the caller, by smprintf
  1321  */
  1322 void nsTextFormatter::smprintf_free(char16_t *mem)
  1324     nsMemory::Free(mem);

mercurial