1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/xpcom/glue/nsTextFormatter.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1326 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +/* 1.10 + * Portable safe sprintf code. 1.11 + * 1.12 + * Code based on mozilla/nsprpub/src/io/prprf.c rev 3.7 1.13 + * 1.14 + * Contributor(s): 1.15 + * Kipp E.B. Hickman <kipp@netscape.com> (original author) 1.16 + * Frank Yung-Fong Tang <ftang@netscape.com> 1.17 + * Daniele Nicolodi <daniele@grinta.net> 1.18 + */ 1.19 + 1.20 +/* 1.21 + * Copied from xpcom/ds/nsTextFormatter.cpp r1.22 1.22 + * Changed to use nsMemory and Frozen linkage 1.23 + * -- Prasad <prasad@medhas.org> 1.24 + */ 1.25 + 1.26 +#include <stdarg.h> 1.27 +#include <stddef.h> 1.28 +#include <stdio.h> 1.29 +#include <string.h> 1.30 +#include "prdtoa.h" 1.31 +#include "prlog.h" 1.32 +#include "prprf.h" 1.33 +#include "prmem.h" 1.34 +#include "nsCRTGlue.h" 1.35 +#include "nsTextFormatter.h" 1.36 +#include "nsMemory.h" 1.37 + 1.38 +/* 1.39 +** Note: on some platforms va_list is defined as an array, 1.40 +** and requires array notation. 1.41 +*/ 1.42 + 1.43 +#ifdef HAVE_VA_COPY 1.44 +#define VARARGS_ASSIGN(foo, bar) VA_COPY(foo,bar) 1.45 +#elif defined(HAVE_VA_LIST_AS_ARRAY) 1.46 +#define VARARGS_ASSIGN(foo, bar) foo[0] = bar[0] 1.47 +#else 1.48 +#define VARARGS_ASSIGN(foo, bar) (foo) = (bar) 1.49 +#endif 1.50 + 1.51 +typedef struct SprintfStateStr SprintfState; 1.52 + 1.53 +struct SprintfStateStr { 1.54 + int (*stuff)(SprintfState *ss, const char16_t *sp, uint32_t len); 1.55 + 1.56 + char16_t *base; 1.57 + char16_t *cur; 1.58 + uint32_t maxlen; 1.59 + 1.60 + void *stuffclosure; 1.61 +}; 1.62 + 1.63 +/* 1.64 +** Numbered Arguement State 1.65 +*/ 1.66 +struct NumArgState{ 1.67 + int type; /* type of the current ap */ 1.68 + va_list ap; /* point to the corresponding position on ap */ 1.69 + 1.70 + enum Type { 1.71 + INT16, 1.72 + UINT16, 1.73 + INTN, 1.74 + UINTN, 1.75 + INT32, 1.76 + UINT32, 1.77 + INT64, 1.78 + UINT64, 1.79 + STRING, 1.80 + DOUBLE, 1.81 + INTSTR, 1.82 + UNISTRING, 1.83 + UNKNOWN 1.84 + }; 1.85 +}; 1.86 + 1.87 +#define NAS_DEFAULT_NUM 20 /* default number of NumberedArgumentState array */ 1.88 + 1.89 +#define _LEFT 0x1 1.90 +#define _SIGNED 0x2 1.91 +#define _SPACED 0x4 1.92 +#define _ZEROS 0x8 1.93 +#define _NEG 0x10 1.94 + 1.95 +#define ELEMENTS_OF(array_) (sizeof(array_) / sizeof(array_[0])) 1.96 + 1.97 +/* 1.98 +** Fill into the buffer using the data in src 1.99 +*/ 1.100 +static int fill2(SprintfState *ss, const char16_t *src, int srclen, 1.101 + int width, int flags) 1.102 +{ 1.103 + char16_t space = ' '; 1.104 + int rv; 1.105 + 1.106 + width -= srclen; 1.107 + /* Right adjusting */ 1.108 + if ((width > 0) && ((flags & _LEFT) == 0)) { 1.109 + if (flags & _ZEROS) { 1.110 + space = '0'; 1.111 + } 1.112 + while (--width >= 0) { 1.113 + rv = (*ss->stuff)(ss, &space, 1); 1.114 + if (rv < 0) { 1.115 + return rv; 1.116 + } 1.117 + } 1.118 + } 1.119 + 1.120 + /* Copy out the source data */ 1.121 + rv = (*ss->stuff)(ss, src, srclen); 1.122 + if (rv < 0) { 1.123 + return rv; 1.124 + } 1.125 + 1.126 + /* Left adjusting */ 1.127 + if ((width > 0) && ((flags & _LEFT) != 0)) { 1.128 + while (--width >= 0) { 1.129 + rv = (*ss->stuff)(ss, &space, 1); 1.130 + if (rv < 0) { 1.131 + return rv; 1.132 + } 1.133 + } 1.134 + } 1.135 + return 0; 1.136 +} 1.137 + 1.138 +/* 1.139 +** Fill a number. The order is: optional-sign zero-filling conversion-digits 1.140 +*/ 1.141 +static int fill_n(SprintfState *ss, const char16_t *src, int srclen, 1.142 + int width, int prec, int type, int flags) 1.143 +{ 1.144 + int zerowidth = 0; 1.145 + int precwidth = 0; 1.146 + int signwidth = 0; 1.147 + int leftspaces = 0; 1.148 + int rightspaces = 0; 1.149 + int cvtwidth; 1.150 + int rv; 1.151 + char16_t sign; 1.152 + char16_t space = ' '; 1.153 + char16_t zero = '0'; 1.154 + 1.155 + if ((type & 1) == 0) { 1.156 + if (flags & _NEG) { 1.157 + sign = '-'; 1.158 + signwidth = 1; 1.159 + } else if (flags & _SIGNED) { 1.160 + sign = '+'; 1.161 + signwidth = 1; 1.162 + } else if (flags & _SPACED) { 1.163 + sign = ' '; 1.164 + signwidth = 1; 1.165 + } 1.166 + } 1.167 + cvtwidth = signwidth + srclen; 1.168 + 1.169 + if (prec > 0) { 1.170 + if (prec > srclen) { 1.171 + /* Need zero filling */ 1.172 + precwidth = prec - srclen; 1.173 + cvtwidth += precwidth; 1.174 + } 1.175 + } 1.176 + 1.177 + if ((flags & _ZEROS) && (prec < 0)) { 1.178 + if (width > cvtwidth) { 1.179 + /* Zero filling */ 1.180 + zerowidth = width - cvtwidth; 1.181 + cvtwidth += zerowidth; 1.182 + } 1.183 + } 1.184 + 1.185 + if (flags & _LEFT) { 1.186 + if (width > cvtwidth) { 1.187 + /* Space filling on the right (i.e. left adjusting) */ 1.188 + rightspaces = width - cvtwidth; 1.189 + } 1.190 + } else { 1.191 + if (width > cvtwidth) { 1.192 + /* Space filling on the left (i.e. right adjusting) */ 1.193 + leftspaces = width - cvtwidth; 1.194 + } 1.195 + } 1.196 + while (--leftspaces >= 0) { 1.197 + rv = (*ss->stuff)(ss, &space, 1); 1.198 + if (rv < 0) { 1.199 + return rv; 1.200 + } 1.201 + } 1.202 + if (signwidth) { 1.203 + rv = (*ss->stuff)(ss, &sign, 1); 1.204 + if (rv < 0) { 1.205 + return rv; 1.206 + } 1.207 + } 1.208 + while (--precwidth >= 0) { 1.209 + rv = (*ss->stuff)(ss, &space, 1); 1.210 + if (rv < 0) { 1.211 + return rv; 1.212 + } 1.213 + } 1.214 + while (--zerowidth >= 0) { 1.215 + rv = (*ss->stuff)(ss, &zero, 1); 1.216 + if (rv < 0) { 1.217 + return rv; 1.218 + } 1.219 + } 1.220 + rv = (*ss->stuff)(ss, src, srclen); 1.221 + if (rv < 0) { 1.222 + return rv; 1.223 + } 1.224 + while (--rightspaces >= 0) { 1.225 + rv = (*ss->stuff)(ss, &space, 1); 1.226 + if (rv < 0) { 1.227 + return rv; 1.228 + } 1.229 + } 1.230 + return 0; 1.231 +} 1.232 + 1.233 +/* 1.234 +** Convert a long into its printable form 1.235 +*/ 1.236 +static int cvt_l(SprintfState *ss, long num, int width, int prec, 1.237 + int radix, int type, int flags, const char16_t *hexp) 1.238 +{ 1.239 + char16_t cvtbuf[100]; 1.240 + char16_t *cvt; 1.241 + int digits; 1.242 + 1.243 + /* according to the man page this needs to happen */ 1.244 + if ((prec == 0) && (num == 0)) { 1.245 + return 0; 1.246 + } 1.247 + 1.248 + /* 1.249 + ** Converting decimal is a little tricky. In the unsigned case we 1.250 + ** need to stop when we hit 10 digits. In the signed case, we can 1.251 + ** stop when the number is zero. 1.252 + */ 1.253 + cvt = &cvtbuf[0] + ELEMENTS_OF(cvtbuf); 1.254 + digits = 0; 1.255 + while (num) { 1.256 + int digit = (((unsigned long)num) % radix) & 0xF; 1.257 + *--cvt = hexp[digit]; 1.258 + digits++; 1.259 + num = (long)(((unsigned long)num) / radix); 1.260 + } 1.261 + if (digits == 0) { 1.262 + *--cvt = '0'; 1.263 + digits++; 1.264 + } 1.265 + 1.266 + /* 1.267 + ** Now that we have the number converted without its sign, deal with 1.268 + ** the sign and zero padding. 1.269 + */ 1.270 + return fill_n(ss, cvt, digits, width, prec, type, flags); 1.271 +} 1.272 + 1.273 +/* 1.274 +** Convert a 64-bit integer into its printable form 1.275 +*/ 1.276 +static int cvt_ll(SprintfState *ss, int64_t num, int width, int prec, 1.277 + int radix, int type, int flags, const char16_t *hexp) 1.278 +{ 1.279 + char16_t cvtbuf[100]; 1.280 + char16_t *cvt; 1.281 + int digits; 1.282 + int64_t rad; 1.283 + 1.284 + /* according to the man page this needs to happen */ 1.285 + if (prec == 0 && num == 0) { 1.286 + return 0; 1.287 + } 1.288 + 1.289 + /* 1.290 + ** Converting decimal is a little tricky. In the unsigned case we 1.291 + ** need to stop when we hit 10 digits. In the signed case, we can 1.292 + ** stop when the number is zero. 1.293 + */ 1.294 + rad = radix; 1.295 + cvt = &cvtbuf[0] + ELEMENTS_OF(cvtbuf); 1.296 + digits = 0; 1.297 + while (num != 0) { 1.298 + *--cvt = hexp[int32_t(num % rad) & 0xf]; 1.299 + digits++; 1.300 + num /= rad; 1.301 + } 1.302 + if (digits == 0) { 1.303 + *--cvt = '0'; 1.304 + digits++; 1.305 + } 1.306 + 1.307 + /* 1.308 + ** Now that we have the number converted without its sign, deal with 1.309 + ** the sign and zero padding. 1.310 + */ 1.311 + return fill_n(ss, cvt, digits, width, prec, type, flags); 1.312 +} 1.313 + 1.314 +/* 1.315 +** Convert a double precision floating point number into its printable 1.316 +** form. 1.317 +*/ 1.318 +static int cvt_f(SprintfState *ss, double d, int width, int prec, 1.319 + const char16_t type, int flags) 1.320 +{ 1.321 + int mode = 2; 1.322 + int decpt; 1.323 + int sign; 1.324 + char buf[256]; 1.325 + char * bufp = buf; 1.326 + int bufsz = 256; 1.327 + char num[256]; 1.328 + char * nump; 1.329 + char * endnum; 1.330 + int numdigits = 0; 1.331 + char exp = 'e'; 1.332 + 1.333 + if (prec == -1) { 1.334 + prec = 6; 1.335 + } else if (prec > 50) { 1.336 + // limit precision to avoid PR_dtoa bug 108335 1.337 + // and to prevent buffers overflows 1.338 + prec = 50; 1.339 + } 1.340 + 1.341 + switch (type) { 1.342 + case 'f': 1.343 + numdigits = prec; 1.344 + mode = 3; 1.345 + break; 1.346 + case 'E': 1.347 + exp = 'E'; 1.348 + // no break 1.349 + case 'e': 1.350 + numdigits = prec + 1; 1.351 + mode = 2; 1.352 + break; 1.353 + case 'G': 1.354 + exp = 'E'; 1.355 + // no break 1.356 + case 'g': 1.357 + if (prec == 0) { 1.358 + prec = 1; 1.359 + } 1.360 + numdigits = prec; 1.361 + mode = 2; 1.362 + break; 1.363 + default: 1.364 + NS_ERROR("invalid type passed to cvt_f"); 1.365 + } 1.366 + 1.367 + if (PR_dtoa(d, mode, numdigits, &decpt, &sign, &endnum, num, bufsz) == PR_FAILURE) { 1.368 + buf[0] = '\0'; 1.369 + return -1; 1.370 + } 1.371 + numdigits = endnum - num; 1.372 + nump = num; 1.373 + 1.374 + if (sign) { 1.375 + *bufp++ = '-'; 1.376 + } else if (flags & _SIGNED) { 1.377 + *bufp++ = '+'; 1.378 + } 1.379 + 1.380 + if (decpt == 9999) { 1.381 + while ((*bufp++ = *nump++)) { } 1.382 + } else { 1.383 + 1.384 + switch (type) { 1.385 + 1.386 + case 'E': 1.387 + case 'e': 1.388 + 1.389 + *bufp++ = *nump++; 1.390 + if (prec > 0) { 1.391 + *bufp++ = '.'; 1.392 + while (*nump) { 1.393 + *bufp++ = *nump++; 1.394 + prec--; 1.395 + } 1.396 + while (prec-- > 0) { 1.397 + *bufp++ = '0'; 1.398 + } 1.399 + } 1.400 + *bufp++ = exp; 1.401 + PR_snprintf(bufp, bufsz - (bufp - buf), "%+03d", decpt-1); 1.402 + break; 1.403 + 1.404 + case 'f': 1.405 + 1.406 + if (decpt < 1) { 1.407 + *bufp++ = '0'; 1.408 + if (prec > 0) { 1.409 + *bufp++ = '.'; 1.410 + while (decpt++ && prec-- > 0) { 1.411 + *bufp++ = '0'; 1.412 + } 1.413 + while (*nump && prec-- > 0) { 1.414 + *bufp++ = *nump++; 1.415 + } 1.416 + while (prec-- > 0) { 1.417 + *bufp++ = '0'; 1.418 + } 1.419 + } 1.420 + } else { 1.421 + while (*nump && decpt-- > 0) { 1.422 + *bufp++ = *nump++; 1.423 + } 1.424 + while (decpt-- > 0) { 1.425 + *bufp++ = '0'; 1.426 + } 1.427 + if (prec > 0) { 1.428 + *bufp++ = '.'; 1.429 + while (*nump && prec-- > 0) { 1.430 + *bufp++ = *nump++; 1.431 + } 1.432 + while (prec-- > 0) { 1.433 + *bufp++ = '0'; 1.434 + } 1.435 + } 1.436 + } 1.437 + *bufp = '\0'; 1.438 + break; 1.439 + 1.440 + case 'G': 1.441 + case 'g': 1.442 + 1.443 + if ((decpt < -3) || ((decpt - 1) >= prec)) { 1.444 + *bufp++ = *nump++; 1.445 + numdigits--; 1.446 + if (numdigits > 0) { 1.447 + *bufp++ = '.'; 1.448 + while (*nump) { 1.449 + *bufp++ = *nump++; 1.450 + } 1.451 + } 1.452 + *bufp++ = exp; 1.453 + PR_snprintf(bufp, bufsz - (bufp - buf), "%+03d", decpt-1); 1.454 + } else { 1.455 + if (decpt < 1) { 1.456 + *bufp++ = '0'; 1.457 + if (prec > 0) { 1.458 + *bufp++ = '.'; 1.459 + while (decpt++) { 1.460 + *bufp++ = '0'; 1.461 + } 1.462 + while (*nump) { 1.463 + *bufp++ = *nump++; 1.464 + } 1.465 + } 1.466 + } else { 1.467 + while (*nump && decpt-- > 0) { 1.468 + *bufp++ = *nump++; 1.469 + numdigits--; 1.470 + } 1.471 + while (decpt-- > 0) { 1.472 + *bufp++ = '0'; 1.473 + } 1.474 + if (numdigits > 0) { 1.475 + *bufp++ = '.'; 1.476 + while (*nump) { 1.477 + *bufp++ = *nump++; 1.478 + } 1.479 + } 1.480 + } 1.481 + *bufp = '\0'; 1.482 + } 1.483 + } 1.484 + } 1.485 + 1.486 + char16_t rbuf[256]; 1.487 + char16_t *rbufp = rbuf; 1.488 + bufp = buf; 1.489 + // cast to char16_t 1.490 + while ((*rbufp++ = *bufp++)) { } 1.491 + *rbufp = '\0'; 1.492 + 1.493 + return fill2(ss, rbuf, NS_strlen(rbuf), width, flags); 1.494 +} 1.495 + 1.496 +/* 1.497 +** Convert a string into its printable form. "width" is the output 1.498 +** width. "prec" is the maximum number of characters of "s" to output, 1.499 +** where -1 means until NUL. 1.500 +*/ 1.501 +static int cvt_S(SprintfState *ss, const char16_t *s, int width, 1.502 + int prec, int flags) 1.503 +{ 1.504 + int slen; 1.505 + 1.506 + if (prec == 0) { 1.507 + return 0; 1.508 + } 1.509 + 1.510 + /* Limit string length by precision value */ 1.511 + slen = s ? NS_strlen(s) : 6; 1.512 + if (prec > 0) { 1.513 + if (prec < slen) { 1.514 + slen = prec; 1.515 + } 1.516 + } 1.517 + 1.518 + /* and away we go */ 1.519 + return fill2(ss, s ? s : MOZ_UTF16("(null)"), slen, width, flags); 1.520 +} 1.521 + 1.522 +/* 1.523 +** Convert a string into its printable form. "width" is the output 1.524 +** width. "prec" is the maximum number of characters of "s" to output, 1.525 +** where -1 means until NUL. 1.526 +*/ 1.527 +static int cvt_s(SprintfState *ss, const char *s, int width, 1.528 + int prec, int flags) 1.529 +{ 1.530 + NS_ConvertUTF8toUTF16 utf16Val(s); 1.531 + return cvt_S(ss, utf16Val.get(), width, prec, flags); 1.532 +} 1.533 + 1.534 +/* 1.535 +** BuildArgArray stands for Numbered Argument list Sprintf 1.536 +** for example, 1.537 +** fmp = "%4$i, %2$d, %3s, %1d"; 1.538 +** the number must start from 1, and no gap among them 1.539 +*/ 1.540 + 1.541 +static struct NumArgState* BuildArgArray(const char16_t *fmt, 1.542 + va_list ap, int * rv, 1.543 + struct NumArgState * nasArray) 1.544 +{ 1.545 + int number = 0, cn = 0, i; 1.546 + const char16_t* p; 1.547 + char16_t c; 1.548 + struct NumArgState* nas; 1.549 + 1.550 + /* 1.551 + ** first pass: 1.552 + ** detemine how many legal % I have got, then allocate space 1.553 + */ 1.554 + p = fmt; 1.555 + *rv = 0; 1.556 + i = 0; 1.557 + while ((c = *p++) != 0) { 1.558 + if (c != '%') { 1.559 + continue; 1.560 + } 1.561 + /* skip %% case */ 1.562 + if ((c = *p++) == '%') { 1.563 + continue; 1.564 + } 1.565 + 1.566 + while( c != 0 ){ 1.567 + if (c > '9' || c < '0') { 1.568 + /* numbered argument csae */ 1.569 + if (c == '$') { 1.570 + if (i > 0) { 1.571 + *rv = -1; 1.572 + return nullptr; 1.573 + } 1.574 + number++; 1.575 + break; 1.576 + 1.577 + } else { 1.578 + /* non-numbered argument case */ 1.579 + if (number > 0) { 1.580 + *rv = -1; 1.581 + return nullptr; 1.582 + } 1.583 + i = 1; 1.584 + break; 1.585 + } 1.586 + } 1.587 + c = *p++; 1.588 + } 1.589 + } 1.590 + 1.591 + if (number == 0) { 1.592 + return nullptr; 1.593 + } 1.594 + 1.595 + if (number > NAS_DEFAULT_NUM) { 1.596 + nas = (struct NumArgState*)nsMemory::Alloc(number * sizeof(struct NumArgState)); 1.597 + if (!nas) { 1.598 + *rv = -1; 1.599 + return nullptr; 1.600 + } 1.601 + } else { 1.602 + nas = nasArray; 1.603 + } 1.604 + 1.605 + for (i = 0; i < number; i++) { 1.606 + nas[i].type = NumArgState::UNKNOWN; 1.607 + } 1.608 + 1.609 + /* 1.610 + ** second pass: 1.611 + ** set nas[].type 1.612 + */ 1.613 + p = fmt; 1.614 + while ((c = *p++) != 0) { 1.615 + if (c != '%') { 1.616 + continue; 1.617 + } 1.618 + c = *p++; 1.619 + if (c == '%') { 1.620 + continue; 1.621 + } 1.622 + cn = 0; 1.623 + /* should imporve error check later */ 1.624 + while (c && c != '$') { 1.625 + cn = cn*10 + c - '0'; 1.626 + c = *p++; 1.627 + } 1.628 + 1.629 + if (!c || cn < 1 || cn > number) { 1.630 + *rv = -1; 1.631 + break; 1.632 + } 1.633 + 1.634 + /* nas[cn] starts from 0, and make sure 1.635 + nas[cn].type is not assigned */ 1.636 + cn--; 1.637 + if (nas[cn].type != NumArgState::UNKNOWN) { 1.638 + continue; 1.639 + } 1.640 + 1.641 + c = *p++; 1.642 + 1.643 + /* width */ 1.644 + if (c == '*') { 1.645 + /* not supported feature, for the argument is not numbered */ 1.646 + *rv = -1; 1.647 + break; 1.648 + } else { 1.649 + while ((c >= '0') && (c <= '9')) { 1.650 + c = *p++; 1.651 + } 1.652 + } 1.653 + 1.654 + /* precision */ 1.655 + if (c == '.') { 1.656 + c = *p++; 1.657 + if (c == '*') { 1.658 + /* not supported feature, for the argument is not numbered */ 1.659 + *rv = -1; 1.660 + break; 1.661 + } else { 1.662 + while ((c >= '0') && (c <= '9')) { 1.663 + c = *p++; 1.664 + } 1.665 + } 1.666 + } 1.667 + 1.668 + /* size */ 1.669 + nas[cn].type = NumArgState::INTN; 1.670 + if (c == 'h') { 1.671 + nas[cn].type = NumArgState::INT16; 1.672 + c = *p++; 1.673 + } else if (c == 'L') { 1.674 + /* XXX not quite sure here */ 1.675 + nas[cn].type = NumArgState::INT64; 1.676 + c = *p++; 1.677 + } else if (c == 'l') { 1.678 + nas[cn].type = NumArgState::INT32; 1.679 + c = *p++; 1.680 + if (c == 'l') { 1.681 + nas[cn].type = NumArgState::INT64; 1.682 + c = *p++; 1.683 + } 1.684 + } 1.685 + 1.686 + /* format */ 1.687 + switch (c) { 1.688 + case 'd': 1.689 + case 'c': 1.690 + case 'i': 1.691 + case 'o': 1.692 + case 'u': 1.693 + case 'x': 1.694 + case 'X': 1.695 + break; 1.696 + 1.697 + case 'e': 1.698 + case 'f': 1.699 + case 'g': 1.700 + nas[cn].type = NumArgState::DOUBLE; 1.701 + break; 1.702 + 1.703 + case 'p': 1.704 + /* XXX should use cpp */ 1.705 + if (sizeof(void *) == sizeof(int32_t)) { 1.706 + nas[cn].type = NumArgState::UINT32; 1.707 + } else if (sizeof(void *) == sizeof(int64_t)) { 1.708 + nas[cn].type = NumArgState::UINT64; 1.709 + } else if (sizeof(void *) == sizeof(int)) { 1.710 + nas[cn].type = NumArgState::UINTN; 1.711 + } else { 1.712 + nas[cn].type = NumArgState::UNKNOWN; 1.713 + } 1.714 + break; 1.715 + 1.716 + case 'C': 1.717 + /* XXX not supported I suppose */ 1.718 + PR_ASSERT(0); 1.719 + nas[cn].type = NumArgState::UNKNOWN; 1.720 + break; 1.721 + 1.722 + case 'S': 1.723 + nas[cn].type = NumArgState::UNISTRING; 1.724 + break; 1.725 + 1.726 + case 's': 1.727 + nas[cn].type = NumArgState::STRING; 1.728 + break; 1.729 + 1.730 + case 'n': 1.731 + nas[cn].type = NumArgState::INTSTR; 1.732 + break; 1.733 + 1.734 + default: 1.735 + PR_ASSERT(0); 1.736 + nas[cn].type = NumArgState::UNKNOWN; 1.737 + break; 1.738 + } 1.739 + 1.740 + /* get a legal para. */ 1.741 + if (nas[cn].type == NumArgState::UNKNOWN) { 1.742 + *rv = -1; 1.743 + break; 1.744 + } 1.745 + } 1.746 + 1.747 + 1.748 + /* 1.749 + ** third pass 1.750 + ** fill the nas[cn].ap 1.751 + */ 1.752 + if (*rv < 0) { 1.753 + if( nas != nasArray ) { 1.754 + PR_DELETE(nas); 1.755 + } 1.756 + return nullptr; 1.757 + } 1.758 + 1.759 + cn = 0; 1.760 + while (cn < number) { 1.761 + if (nas[cn].type == NumArgState::UNKNOWN) { 1.762 + cn++; 1.763 + continue; 1.764 + } 1.765 + 1.766 + VARARGS_ASSIGN(nas[cn].ap, ap); 1.767 + 1.768 + switch (nas[cn].type) { 1.769 + case NumArgState::INT16: 1.770 + case NumArgState::UINT16: 1.771 + case NumArgState::INTN: 1.772 + case NumArgState::UINTN: (void)va_arg(ap, int); break; 1.773 + 1.774 + case NumArgState::INT32: (void)va_arg(ap, int32_t); break; 1.775 + 1.776 + case NumArgState::UINT32: (void)va_arg(ap, uint32_t); break; 1.777 + 1.778 + case NumArgState::INT64: (void)va_arg(ap, int64_t); break; 1.779 + 1.780 + case NumArgState::UINT64: (void)va_arg(ap, uint64_t); break; 1.781 + 1.782 + case NumArgState::STRING: (void)va_arg(ap, char*); break; 1.783 + 1.784 + case NumArgState::INTSTR: (void)va_arg(ap, int*); break; 1.785 + 1.786 + case NumArgState::DOUBLE: (void)va_arg(ap, double); break; 1.787 + 1.788 + case NumArgState::UNISTRING: (void)va_arg(ap, char16_t*); break; 1.789 + 1.790 + default: 1.791 + if( nas != nasArray ) { 1.792 + PR_DELETE( nas ); 1.793 + } 1.794 + *rv = -1; 1.795 + return nullptr; 1.796 + } 1.797 + cn++; 1.798 + } 1.799 + return nas; 1.800 +} 1.801 + 1.802 +/* 1.803 +** The workhorse sprintf code. 1.804 +*/ 1.805 +static int dosprintf(SprintfState *ss, const char16_t *fmt, va_list ap) 1.806 +{ 1.807 + char16_t c; 1.808 + int flags, width, prec, radix, type; 1.809 + union { 1.810 + char16_t ch; 1.811 + int i; 1.812 + long l; 1.813 + int64_t ll; 1.814 + double d; 1.815 + const char *s; 1.816 + const char16_t *S; 1.817 + int *ip; 1.818 + } u; 1.819 + char16_t space = ' '; 1.820 + 1.821 + nsAutoString hex; 1.822 + hex.AssignLiteral("0123456789abcdef"); 1.823 + 1.824 + nsAutoString HEX; 1.825 + HEX.AssignLiteral("0123456789ABCDEF"); 1.826 + 1.827 + const char16_t *hexp; 1.828 + int rv, i; 1.829 + struct NumArgState* nas = nullptr; 1.830 + struct NumArgState nasArray[NAS_DEFAULT_NUM]; 1.831 + 1.832 + 1.833 + /* 1.834 + ** build an argument array, IF the fmt is numbered argument 1.835 + ** list style, to contain the Numbered Argument list pointers 1.836 + */ 1.837 + nas = BuildArgArray (fmt, ap, &rv, nasArray); 1.838 + if (rv < 0) { 1.839 + /* the fmt contains error Numbered Argument format, jliu@netscape.com */ 1.840 + PR_ASSERT(0); 1.841 + return rv; 1.842 + } 1.843 + 1.844 + while ((c = *fmt++) != 0) { 1.845 + if (c != '%') { 1.846 + rv = (*ss->stuff)(ss, fmt - 1, 1); 1.847 + if (rv < 0) { 1.848 + return rv; 1.849 + } 1.850 + continue; 1.851 + } 1.852 + 1.853 + /* 1.854 + ** Gobble up the % format string. Hopefully we have handled all 1.855 + ** of the strange cases! 1.856 + */ 1.857 + flags = 0; 1.858 + c = *fmt++; 1.859 + if (c == '%') { 1.860 + /* quoting a % with %% */ 1.861 + rv = (*ss->stuff)(ss, fmt - 1, 1); 1.862 + if (rv < 0) { 1.863 + return rv; 1.864 + } 1.865 + continue; 1.866 + } 1.867 + 1.868 + if (nas != nullptr) { 1.869 + /* the fmt contains the Numbered Arguments feature */ 1.870 + i = 0; 1.871 + /* should imporve error check later */ 1.872 + while (c && c != '$') { 1.873 + i = (i * 10) + (c - '0'); 1.874 + c = *fmt++; 1.875 + } 1.876 + 1.877 + if (nas[i-1].type == NumArgState::UNKNOWN) { 1.878 + if (nas && (nas != nasArray)) { 1.879 + PR_DELETE(nas); 1.880 + } 1.881 + return -1; 1.882 + } 1.883 + 1.884 + VARARGS_ASSIGN(ap, nas[i-1].ap); 1.885 + c = *fmt++; 1.886 + } 1.887 + 1.888 + /* 1.889 + * Examine optional flags. Note that we do not implement the 1.890 + * '#' flag of sprintf(). The ANSI C spec. of the '#' flag is 1.891 + * somewhat ambiguous and not ideal, which is perhaps why 1.892 + * the various sprintf() implementations are inconsistent 1.893 + * on this feature. 1.894 + */ 1.895 + while ((c == '-') || (c == '+') || (c == ' ') || (c == '0')) { 1.896 + if (c == '-') flags |= _LEFT; 1.897 + if (c == '+') flags |= _SIGNED; 1.898 + if (c == ' ') flags |= _SPACED; 1.899 + if (c == '0') flags |= _ZEROS; 1.900 + c = *fmt++; 1.901 + } 1.902 + if (flags & _SIGNED) flags &= ~_SPACED; 1.903 + if (flags & _LEFT) flags &= ~_ZEROS; 1.904 + 1.905 + /* width */ 1.906 + if (c == '*') { 1.907 + c = *fmt++; 1.908 + width = va_arg(ap, int); 1.909 + } else { 1.910 + width = 0; 1.911 + while ((c >= '0') && (c <= '9')) { 1.912 + width = (width * 10) + (c - '0'); 1.913 + c = *fmt++; 1.914 + } 1.915 + } 1.916 + 1.917 + /* precision */ 1.918 + prec = -1; 1.919 + if (c == '.') { 1.920 + c = *fmt++; 1.921 + if (c == '*') { 1.922 + c = *fmt++; 1.923 + prec = va_arg(ap, int); 1.924 + } else { 1.925 + prec = 0; 1.926 + while ((c >= '0') && (c <= '9')) { 1.927 + prec = (prec * 10) + (c - '0'); 1.928 + c = *fmt++; 1.929 + } 1.930 + } 1.931 + } 1.932 + 1.933 + /* size */ 1.934 + type = NumArgState::INTN; 1.935 + if (c == 'h') { 1.936 + type = NumArgState::INT16; 1.937 + c = *fmt++; 1.938 + } else if (c == 'L') { 1.939 + /* XXX not quite sure here */ 1.940 + type = NumArgState::INT64; 1.941 + c = *fmt++; 1.942 + } else if (c == 'l') { 1.943 + type = NumArgState::INT32; 1.944 + c = *fmt++; 1.945 + if (c == 'l') { 1.946 + type = NumArgState::INT64; 1.947 + c = *fmt++; 1.948 + } 1.949 + } 1.950 + 1.951 + /* format */ 1.952 + hexp = hex.get(); 1.953 + switch (c) { 1.954 + case 'd': 1.955 + case 'i': /* decimal/integer */ 1.956 + radix = 10; 1.957 + goto fetch_and_convert; 1.958 + 1.959 + case 'o': /* octal */ 1.960 + radix = 8; 1.961 + type |= 1; 1.962 + goto fetch_and_convert; 1.963 + 1.964 + case 'u': /* unsigned decimal */ 1.965 + radix = 10; 1.966 + type |= 1; 1.967 + goto fetch_and_convert; 1.968 + 1.969 + case 'x': /* unsigned hex */ 1.970 + radix = 16; 1.971 + type |= 1; 1.972 + goto fetch_and_convert; 1.973 + 1.974 + case 'X': /* unsigned HEX */ 1.975 + radix = 16; 1.976 + hexp = HEX.get(); 1.977 + type |= 1; 1.978 + goto fetch_and_convert; 1.979 + 1.980 + fetch_and_convert: 1.981 + switch (type) { 1.982 + case NumArgState::INT16: 1.983 + u.l = va_arg(ap, int); 1.984 + if (u.l < 0) { 1.985 + u.l = -u.l; 1.986 + flags |= _NEG; 1.987 + } 1.988 + goto do_long; 1.989 + case NumArgState::UINT16: 1.990 + u.l = va_arg(ap, int) & 0xffff; 1.991 + goto do_long; 1.992 + case NumArgState::INTN: 1.993 + u.l = va_arg(ap, int); 1.994 + if (u.l < 0) { 1.995 + u.l = -u.l; 1.996 + flags |= _NEG; 1.997 + } 1.998 + goto do_long; 1.999 + case NumArgState::UINTN: 1.1000 + u.l = (long)va_arg(ap, unsigned int); 1.1001 + goto do_long; 1.1002 + 1.1003 + case NumArgState::INT32: 1.1004 + u.l = va_arg(ap, int32_t); 1.1005 + if (u.l < 0) { 1.1006 + u.l = -u.l; 1.1007 + flags |= _NEG; 1.1008 + } 1.1009 + goto do_long; 1.1010 + case NumArgState::UINT32: 1.1011 + u.l = (long)va_arg(ap, uint32_t); 1.1012 + do_long: 1.1013 + rv = cvt_l(ss, u.l, width, prec, radix, type, flags, hexp); 1.1014 + if (rv < 0) { 1.1015 + return rv; 1.1016 + } 1.1017 + break; 1.1018 + 1.1019 + case NumArgState::INT64: 1.1020 + u.ll = va_arg(ap, int64_t); 1.1021 + if (u.ll < 0) { 1.1022 + u.ll = -u.ll; 1.1023 + flags |= _NEG; 1.1024 + } 1.1025 + goto do_longlong; 1.1026 + case NumArgState::UINT64: 1.1027 + u.ll = va_arg(ap, uint64_t); 1.1028 + do_longlong: 1.1029 + rv = cvt_ll(ss, u.ll, width, prec, radix, type, flags, hexp); 1.1030 + if (rv < 0) { 1.1031 + return rv; 1.1032 + } 1.1033 + break; 1.1034 + } 1.1035 + break; 1.1036 + 1.1037 + case 'e': 1.1038 + case 'E': 1.1039 + case 'f': 1.1040 + case 'g': 1.1041 + case 'G': 1.1042 + u.d = va_arg(ap, double); 1.1043 + rv = cvt_f(ss, u.d, width, prec, c, flags); 1.1044 + if (rv < 0) { 1.1045 + return rv; 1.1046 + } 1.1047 + break; 1.1048 + 1.1049 + case 'c': 1.1050 + u.ch = va_arg(ap, int); 1.1051 + if ((flags & _LEFT) == 0) { 1.1052 + while (width-- > 1) { 1.1053 + rv = (*ss->stuff)(ss, &space, 1); 1.1054 + if (rv < 0) { 1.1055 + return rv; 1.1056 + } 1.1057 + } 1.1058 + } 1.1059 + rv = (*ss->stuff)(ss, &u.ch, 1); 1.1060 + if (rv < 0) { 1.1061 + return rv; 1.1062 + } 1.1063 + if (flags & _LEFT) { 1.1064 + while (width-- > 1) { 1.1065 + rv = (*ss->stuff)(ss, &space, 1); 1.1066 + if (rv < 0) { 1.1067 + return rv; 1.1068 + } 1.1069 + } 1.1070 + } 1.1071 + break; 1.1072 + 1.1073 + case 'p': 1.1074 + if (sizeof(void *) == sizeof(int32_t)) { 1.1075 + type = NumArgState::UINT32; 1.1076 + } else if (sizeof(void *) == sizeof(int64_t)) { 1.1077 + type = NumArgState::UINT64; 1.1078 + } else if (sizeof(void *) == sizeof(int)) { 1.1079 + type = NumArgState::UINTN; 1.1080 + } else { 1.1081 + PR_ASSERT(0); 1.1082 + break; 1.1083 + } 1.1084 + radix = 16; 1.1085 + goto fetch_and_convert; 1.1086 + 1.1087 +#if 0 1.1088 + case 'C': 1.1089 + /* XXX not supported I suppose */ 1.1090 + PR_ASSERT(0); 1.1091 + break; 1.1092 +#endif 1.1093 + 1.1094 + case 'S': 1.1095 + u.S = va_arg(ap, const char16_t*); 1.1096 + rv = cvt_S(ss, u.S, width, prec, flags); 1.1097 + if (rv < 0) { 1.1098 + return rv; 1.1099 + } 1.1100 + break; 1.1101 + 1.1102 + case 's': 1.1103 + u.s = va_arg(ap, const char*); 1.1104 + rv = cvt_s(ss, u.s, width, prec, flags); 1.1105 + if (rv < 0) { 1.1106 + return rv; 1.1107 + } 1.1108 + break; 1.1109 + 1.1110 + case 'n': 1.1111 + u.ip = va_arg(ap, int*); 1.1112 + if (u.ip) { 1.1113 + *u.ip = ss->cur - ss->base; 1.1114 + } 1.1115 + break; 1.1116 + 1.1117 + default: 1.1118 + /* Not a % token after all... skip it */ 1.1119 +#if 0 1.1120 + PR_ASSERT(0); 1.1121 +#endif 1.1122 + char16_t perct = '%'; 1.1123 + rv = (*ss->stuff)(ss, &perct, 1); 1.1124 + if (rv < 0) { 1.1125 + return rv; 1.1126 + } 1.1127 + rv = (*ss->stuff)(ss, fmt - 1, 1); 1.1128 + if (rv < 0) { 1.1129 + return rv; 1.1130 + } 1.1131 + } 1.1132 + } 1.1133 + 1.1134 + /* Stuff trailing NUL */ 1.1135 + char16_t null = '\0'; 1.1136 + 1.1137 + rv = (*ss->stuff)(ss, &null, 1); 1.1138 + 1.1139 + if( nas && ( nas != nasArray ) ){ 1.1140 + PR_DELETE( nas ); 1.1141 + } 1.1142 + 1.1143 + return rv; 1.1144 +} 1.1145 + 1.1146 +/************************************************************************/ 1.1147 + 1.1148 +static int 1.1149 +StringStuff(SprintfState* ss, const char16_t* sp, uint32_t len) 1.1150 +{ 1.1151 + if (*sp == '\0') 1.1152 + return 0; 1.1153 + 1.1154 + ptrdiff_t off = ss->cur - ss->base; 1.1155 + 1.1156 + nsAString* str = static_cast<nsAString*>(ss->stuffclosure); 1.1157 + str->Append(sp, len); 1.1158 + 1.1159 + ss->base = str->BeginWriting(); 1.1160 + ss->cur = ss->base + off; 1.1161 + 1.1162 + return 0; 1.1163 +} 1.1164 + 1.1165 +/* 1.1166 +** Stuff routine that automatically grows the malloc'd output buffer 1.1167 +** before it overflows. 1.1168 +*/ 1.1169 +static int GrowStuff(SprintfState *ss, const char16_t *sp, uint32_t len) 1.1170 +{ 1.1171 + ptrdiff_t off; 1.1172 + char16_t *newbase; 1.1173 + uint32_t newlen; 1.1174 + 1.1175 + off = ss->cur - ss->base; 1.1176 + if (off + len >= ss->maxlen) { 1.1177 + /* Grow the buffer */ 1.1178 + newlen = ss->maxlen + ((len > 32) ? len : 32); 1.1179 + if (ss->base) { 1.1180 + newbase = (char16_t*) nsMemory::Realloc(ss->base, newlen*sizeof(char16_t)); 1.1181 + } else { 1.1182 + newbase = (char16_t*) nsMemory::Alloc(newlen*sizeof(char16_t)); 1.1183 + } 1.1184 + if (!newbase) { 1.1185 + /* Ran out of memory */ 1.1186 + return -1; 1.1187 + } 1.1188 + ss->base = newbase; 1.1189 + ss->maxlen = newlen; 1.1190 + ss->cur = ss->base + off; 1.1191 + } 1.1192 + 1.1193 + /* Copy data */ 1.1194 + while (len) { 1.1195 + --len; 1.1196 + *ss->cur++ = *sp++; 1.1197 + } 1.1198 + PR_ASSERT((uint32_t)(ss->cur - ss->base) <= ss->maxlen); 1.1199 + return 0; 1.1200 +} 1.1201 + 1.1202 +/* 1.1203 +** sprintf into a malloc'd buffer 1.1204 +*/ 1.1205 +char16_t * nsTextFormatter::smprintf(const char16_t *fmt, ...) 1.1206 +{ 1.1207 + va_list ap; 1.1208 + char16_t *rv; 1.1209 + 1.1210 + va_start(ap, fmt); 1.1211 + rv = nsTextFormatter::vsmprintf(fmt, ap); 1.1212 + va_end(ap); 1.1213 + return rv; 1.1214 +} 1.1215 + 1.1216 +uint32_t nsTextFormatter::ssprintf(nsAString& out, const char16_t* fmt, ...) 1.1217 +{ 1.1218 + va_list ap; 1.1219 + uint32_t rv; 1.1220 + 1.1221 + va_start(ap, fmt); 1.1222 + rv = nsTextFormatter::vssprintf(out, fmt, ap); 1.1223 + va_end(ap); 1.1224 + return rv; 1.1225 +} 1.1226 + 1.1227 +uint32_t nsTextFormatter::vssprintf(nsAString& out, const char16_t* fmt, va_list ap) 1.1228 +{ 1.1229 + SprintfState ss; 1.1230 + ss.stuff = StringStuff; 1.1231 + ss.base = 0; 1.1232 + ss.cur = 0; 1.1233 + ss.maxlen = 0; 1.1234 + ss.stuffclosure = &out; 1.1235 + 1.1236 + out.Truncate(); 1.1237 + int n = dosprintf(&ss, fmt, ap); 1.1238 + return n ? n - 1 : n; 1.1239 +} 1.1240 + 1.1241 +char16_t * nsTextFormatter::vsmprintf(const char16_t *fmt, va_list ap) 1.1242 +{ 1.1243 + SprintfState ss; 1.1244 + int rv; 1.1245 + 1.1246 + ss.stuff = GrowStuff; 1.1247 + ss.base = 0; 1.1248 + ss.cur = 0; 1.1249 + ss.maxlen = 0; 1.1250 + rv = dosprintf(&ss, fmt, ap); 1.1251 + if (rv < 0) { 1.1252 + if (ss.base) { 1.1253 + PR_DELETE(ss.base); 1.1254 + } 1.1255 + return 0; 1.1256 + } 1.1257 + return ss.base; 1.1258 +} 1.1259 + 1.1260 +/* 1.1261 +** Stuff routine that discards overflow data 1.1262 +*/ 1.1263 +static int LimitStuff(SprintfState *ss, const char16_t *sp, uint32_t len) 1.1264 +{ 1.1265 + uint32_t limit = ss->maxlen - (ss->cur - ss->base); 1.1266 + 1.1267 + if (len > limit) { 1.1268 + len = limit; 1.1269 + } 1.1270 + while (len) { 1.1271 + --len; 1.1272 + *ss->cur++ = *sp++; 1.1273 + } 1.1274 + return 0; 1.1275 +} 1.1276 + 1.1277 +/* 1.1278 +** sprintf into a fixed size buffer. Make sure there is a NUL at the end 1.1279 +** when finished. 1.1280 +*/ 1.1281 +uint32_t nsTextFormatter::snprintf(char16_t *out, uint32_t outlen, const char16_t *fmt, ...) 1.1282 +{ 1.1283 + va_list ap; 1.1284 + uint32_t rv; 1.1285 + 1.1286 + PR_ASSERT((int32_t)outlen > 0); 1.1287 + if ((int32_t)outlen <= 0) { 1.1288 + return 0; 1.1289 + } 1.1290 + 1.1291 + va_start(ap, fmt); 1.1292 + rv = nsTextFormatter::vsnprintf(out, outlen, fmt, ap); 1.1293 + va_end(ap); 1.1294 + return rv; 1.1295 +} 1.1296 + 1.1297 +uint32_t nsTextFormatter::vsnprintf(char16_t *out, uint32_t outlen,const char16_t *fmt, 1.1298 + va_list ap) 1.1299 +{ 1.1300 + SprintfState ss; 1.1301 + uint32_t n; 1.1302 + 1.1303 + PR_ASSERT((int32_t)outlen > 0); 1.1304 + if ((int32_t)outlen <= 0) { 1.1305 + return 0; 1.1306 + } 1.1307 + 1.1308 + ss.stuff = LimitStuff; 1.1309 + ss.base = out; 1.1310 + ss.cur = out; 1.1311 + ss.maxlen = outlen; 1.1312 + (void) dosprintf(&ss, fmt, ap); 1.1313 + 1.1314 + /* If we added chars, and we didn't append a null, do it now. */ 1.1315 + if( (ss.cur != ss.base) && (*(ss.cur - 1) != '\0') ) 1.1316 + *(--ss.cur) = '\0'; 1.1317 + 1.1318 + n = ss.cur - ss.base; 1.1319 + return n ? n - 1 : n; 1.1320 +} 1.1321 + 1.1322 +/* 1.1323 + * Free memory allocated, for the caller, by smprintf 1.1324 + */ 1.1325 +void nsTextFormatter::smprintf_free(char16_t *mem) 1.1326 +{ 1.1327 + nsMemory::Free(mem); 1.1328 +} 1.1329 +