From bbc897b35a9adb6a634e462a1344895a5a64f7d0 Mon Sep 17 00:00:00 2001 From: "daumling%adobe.com" Date: Sat, 18 Feb 2006 07:13:16 +0000 Subject: [PATCH] Bug 315974: JSprintf functions cannot print jschar characters and strings --- js/src/jsopcode.c | 23 +++++++++++++---- js/src/jsprf.c | 64 ++++++++++++++++++++++++++++++++++++++++++----- js/src/jsprf.h | 2 ++ js/src/jsstr.c | 2 +- 4 files changed, 79 insertions(+), 12 deletions(-) diff --git a/js/src/jsopcode.c b/js/src/jsopcode.c index 200a4c38f63..f302a056d5b 100644 --- a/js/src/jsopcode.c +++ b/js/src/jsopcode.c @@ -448,14 +448,27 @@ QuoteString(Sprinter *sp, JSString *str, jschar quote) break; /* Use js_EscapeMap, \u, or \x only if necessary. */ - if ((u = js_strchr(js_EscapeMap, c)) != NULL) + if ((u = js_strchr(js_EscapeMap, c)) != NULL) { ok = Sprint(sp, "\\%c", (char)u[1]) >= 0; - else { + } else { #ifdef JS_STRINGS_ARE_UTF8 - /* print as UTF-8 string */ - ok = Sprint(sp, "%hc", c) >= 0; + /* If this is a surrogate pair, make sure to print the pair. */ + if (c >= 0xD800 && c <= 0xDBFF) { + jschar buffer[3]; + buffer[0] = c; + buffer[1] = *++t; + buffer[2] = 0; + if (t == z) { + ok = JS_FALSE; + break; + } + ok = Sprint(sp, "%hs", buffer) >= 0; + } else { + /* Print as UTF-8 string. */ + ok = Sprint(sp, "%hc", c) >= 0; + } #else - /* Use \uxxxx or \xXX if the string cannot be displayed as UTF-8 */ + /* Use \uXXXX or \xXX if the string cannot be displayed as UTF-8. */ ok = Sprint(sp, (c >> 8) ? "\\u%04X" : "\\x%02X", c) >= 0; #endif } diff --git a/js/src/jsprf.c b/js/src/jsprf.c index 591313ef7c7..a1adc0a726d 100644 --- a/js/src/jsprf.c +++ b/js/src/jsprf.c @@ -49,6 +49,8 @@ #include "jsprf.h" #include "jslong.h" #include "jsutil.h" /* Added by JSIFY */ +#include "jspubtd.h" +#include "jsstr.h" /* ** Note: on some platforms va_list is defined as an array, @@ -105,6 +107,7 @@ struct NumArgState{ #define TYPE_STRING 8 #define TYPE_DOUBLE 9 #define TYPE_INTSTR 10 +#define TYPE_WSTRING 11 #define TYPE_UNKNOWN 20 #define FLAG_LEFT 0x1 @@ -395,6 +398,27 @@ static int cvt_s(SprintfState *ss, const char *s, int width, int prec, return fill2(ss, s ? s : "(null)", slen, width, flags); } +static int cvt_ws(SprintfState *ss, const jschar *ws, int width, int prec, + int flags) +{ + int result; + /* + * Supply NULL as the JSContext; errors are not reported, + * and malloc() is used to allocate the buffer buffer. + */ + if (ws) { + int slen = js_strlen(ws); + char *s = js_DeflateString(NULL, ws, slen); + if (!s) + return -1; /* JSStuffFunc error indicator. */ + result = cvt_s(ss, s, width, prec, flags); + free(s); + } else { + result = cvt_s(ss, NULL, width, prec, flags); + } + return result; +} + /* ** BuildArgArray stands for Numbered Argument list Sprintf ** for example, @@ -578,7 +602,7 @@ static struct NumArgState* BuildArgArray( const char *fmt, va_list ap, int* rv, break; case 's': - nas[ cn ].type = TYPE_STRING; + nas[ cn ].type = (nas[ cn ].type == TYPE_UINT16) ? TYPE_WSTRING : TYPE_STRING; break; case 'n': @@ -635,6 +659,8 @@ static struct NumArgState* BuildArgArray( const char *fmt, va_list ap, int* rv, case TYPE_STRING: (void)va_arg( ap, char* ); break; + case TYPE_WSTRING: (void)va_arg( ap, jschar* ); break; + case TYPE_INTSTR: (void)va_arg( ap, JSIntn* ); break; case TYPE_DOUBLE: (void)va_arg( ap, double ); break; @@ -662,11 +688,13 @@ static int dosprintf(SprintfState *ss, const char *fmt, va_list ap) int flags, width, prec, radix, type; union { char ch; + jschar wch; int i; long l; JSInt64 ll; double d; const char *s; + const jschar* ws; int *ip; } u; const char *fmt0; @@ -678,7 +706,10 @@ static int dosprintf(SprintfState *ss, const char *fmt, va_list ap) struct NumArgState nasArray[ NAS_DEFAULT_NUM ]; char pattern[20]; const char *dolPt = NULL; /* in "%4$.2f", dolPt will poiont to . */ - +#ifdef JS_STRINGS_ARE_UTF8 + char utf8buf[6]; + int utf8len; +#endif /* ** build an argument array, IF the fmt is numbered argument @@ -905,7 +936,6 @@ static int dosprintf(SprintfState *ss, const char *fmt, va_list ap) break; case 'c': - u.ch = va_arg(ap, int); if ((flags & FLAG_LEFT) == 0) { while (width-- > 1) { rv = (*ss->stuff)(ss, " ", 1); @@ -914,7 +944,20 @@ static int dosprintf(SprintfState *ss, const char *fmt, va_list ap) } } } - rv = (*ss->stuff)(ss, &u.ch, 1); + switch (type) { + case TYPE_INT16: + /* Treat %hc as %c if JS_STRINGS_ARE_UTF8 is undefined. */ +#ifdef JS_STRINGS_ARE_UTF8 + u.wch = va_arg(ap, int); + utf8len = js_OneUcs4ToUtf8Char (utf8buf, u.wch); + rv = (*ss->stuff)(ss, utf8buf, utf8len); + break; +#endif + case TYPE_INTN: + u.ch = va_arg(ap, int); + rv = (*ss->stuff)(ss, &u.ch, 1); + break; + } if (rv < 0) { return rv; } @@ -953,8 +996,17 @@ static int dosprintf(SprintfState *ss, const char *fmt, va_list ap) #endif case 's': - u.s = va_arg(ap, const char*); - rv = cvt_s(ss, u.s, width, prec, flags); + if(type == TYPE_INT16) { + /* + * This would do a simple string/byte conversion + * if JS_STRINGS_ARE_UTF8 is not defined. + */ + u.ws = va_arg(ap, const jschar*); + rv = cvt_ws(ss, u.ws, width, prec, flags); + } else { + u.s = va_arg(ap, const char*); + rv = cvt_s(ss, u.s, width, prec, flags); + } if (rv < 0) { return rv; } diff --git a/js/src/jsprf.h b/js/src/jsprf.h index 5e5bb98f3f4..446035d6ec1 100644 --- a/js/src/jsprf.h +++ b/js/src/jsprf.h @@ -50,7 +50,9 @@ ** %ld, %lu, %lx, %lX, %lo - 32-bit versions of above ** %lld, %llu, %llx, %llX, %llo - 64 bit versions of above ** %s - string +** %hs - 16-bit version of above (only available if compiled with JS_STRINGS_ARE_UTF8) ** %c - character +** %hc - 16-bit version of above (only available if compiled with JS_STRINGS_ARE_UTF8) ** %p - pointer (deals with machine dependent pointer size) ** %f - float ** %g - float diff --git a/js/src/jsstr.c b/js/src/jsstr.c index 25a7fa3a0d9..c78cfa04501 100644 --- a/js/src/jsstr.c +++ b/js/src/jsstr.c @@ -2965,7 +2965,7 @@ js_DeflateStringToBuffer(JSContext *cx, const jschar *src, size_t srclen, if (c < 0xD800 || c > 0xDBFF) { v = c; } else { - if (srclen < 2) + if (srclen < 1) goto bufferTooSmall; c2 = *src++; srclen--;