--- a/mozglue/misc/Printf.cpp
+++ b/mozglue/misc/Printf.cpp
@@ -8,23 +8,28 @@
* Portable safe sprintf code.
*
* Author: Kipp E.B. Hickman
*/
#include "mozilla/AllocPolicy.h"
#include "mozilla/Printf.h"
#include "mozilla/Sprintf.h"
+#include "mozilla/UniquePtrExtensions.h"
#include "mozilla/Vector.h"
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#if defined(XP_WIN)
+#include <windows.h>
+#endif
+
/*
* Note: on some platforms va_list is defined as an array,
* and requires array notation.
*/
#ifdef HAVE_VA_COPY
#define VARARGS_ASSIGN(foo, bar) VA_COPY(foo, bar)
#elif defined(HAVE_VA_LIST_AS_ARRAY)
#define VARARGS_ASSIGN(foo, bar) foo[0] = bar[0]
@@ -51,16 +56,19 @@ typedef mozilla::Vector<NumArgState, 20,
#define TYPE_LONG 4
#define TYPE_ULONG 5
#define TYPE_LONGLONG 6
#define TYPE_ULONGLONG 7
#define TYPE_STRING 8
#define TYPE_DOUBLE 9
#define TYPE_INTSTR 10
#define TYPE_POINTER 11
+#if defined(XP_WIN)
+#define TYPE_WSTRING 12
+#endif
#define TYPE_UNKNOWN 20
#define FLAG_LEFT 0x1
#define FLAG_SIGNED 0x2
#define FLAG_SPACED 0x4
#define FLAG_ZEROS 0x8
#define FLAG_NEG 0x10
@@ -441,27 +449,42 @@ BuildArgArray(const char* fmt, va_list a
case 'g':
nas[cn].type = TYPE_DOUBLE;
break;
case 'p':
nas[cn].type = TYPE_POINTER;
break;
+ case 'S':
+#if defined(XP_WIN)
+ nas[cn].type = TYPE_WSTRING;
+ break;
+#endif
+ /* Fall through here when not XP_WIN. */
case 'C':
- case 'S':
case 'E':
case 'G':
// XXX not supported I suppose
MOZ_ASSERT(0);
nas[cn].type = TYPE_UNKNOWN;
break;
case 's':
- nas[cn].type = TYPE_STRING;
+#if defined(XP_WIN)
+ if (nas[cn].type == TYPE_LONG) {
+ nas[cn].type = TYPE_WSTRING;
+ break;
+ }
+#endif
+ if (nas[cn].type == TYPE_INTN) {
+ nas[cn].type = TYPE_STRING;
+ } else {
+ nas[cn].type = TYPE_UNKNOWN;
+ }
break;
case 'n':
nas[cn].type = TYPE_INTSTR;
break;
default:
MOZ_ASSERT(0);
@@ -495,16 +518,19 @@ BuildArgArray(const char* fmt, va_list a
case TYPE_LONG: (void) va_arg(ap, long); break;
case TYPE_ULONG: (void) va_arg(ap, unsigned long); break;
case TYPE_LONGLONG: (void) va_arg(ap, long long); break;
case TYPE_ULONGLONG: (void) va_arg(ap, unsigned long long); break;
case TYPE_STRING: (void) va_arg(ap, char*); break;
case TYPE_INTSTR: (void) va_arg(ap, int*); break;
case TYPE_DOUBLE: (void) va_arg(ap, double); break;
case TYPE_POINTER: (void) va_arg(ap, void*); break;
+#if defined(XP_WIN)
+ case TYPE_WSTRING: (void) va_arg(ap, wchar_t*); break;
+#endif
default: MOZ_CRASH();
}
cn++;
}
return true;
@@ -519,16 +545,19 @@ mozilla::PrintfTarget::vprint(const char
char ch;
int i;
long l;
long long ll;
double d;
const char* s;
int* ip;
void* p;
+#if defined(XP_WIN)
+ const wchar_t* ws;
+#endif
} u;
const char* fmt0;
static const char hex[] = "0123456789abcdef";
static const char HEX[] = "0123456789ABCDEF";
const char* hexp;
int i;
char pattern[20];
const char* dolPt = nullptr; // in "%4$.2f", dolPt will point to '.'
@@ -777,28 +806,63 @@ mozilla::PrintfTarget::vprint(const char
case 'p':
type = TYPE_POINTER;
radix = 16;
goto fetch_and_convert;
#if 0
case 'C':
- case 'S':
case 'E':
case 'G':
// XXX not supported I suppose
MOZ_ASSERT(0);
break;
#endif
case 's':
- u.s = va_arg(ap, const char*);
- if (!cvt_s(u.s, width, prec, flags))
- return false;
+ if (type == TYPE_INTN) {
+ u.s = va_arg(ap, const char*);
+ if (!cvt_s(u.s, width, prec, flags))
+ return false;
+ break;
+ } else if (type == TYPE_LONGLONG) {
+ // This should have asserted during BuildArgArray anyway.
+ MOZ_ASSERT(0);
+ break;
+ }
+ MOZ_ASSERT(type == TYPE_LONG);
+ MOZ_FALLTHROUGH;
+ case 'S':
+#if defined(XP_WIN)
+ {
+ u.ws = va_arg(ap, const wchar_t*);
+
+ int rv = WideCharToMultiByte(CP_ACP, 0, u.ws, -1, NULL, 0, NULL, NULL);
+ if (rv == 0 && GetLastError() == ERROR_NO_UNICODE_TRANSLATION) {
+ if (!cvt_s("<unicode errors in string>", width, prec, flags)) {
+ return false;
+ }
+ } else {
+ if (rv == 0) {
+ rv = 1;
+ }
+ UniqueFreePtr<char[]> buf((char*)malloc(rv));
+ WideCharToMultiByte(CP_ACP, 0, u.ws, -1, buf.get(), rv, NULL, NULL);
+ buf[rv - 1] = '\0';
+
+ if (!cvt_s(buf.get(), width, prec, flags)) {
+ return false;
+ }
+ }
+ }
+#else
+ // This should have asserted during BuildArgArray anyway.
+ MOZ_ASSERT(0);
+#endif
break;
case 'n':
u.ip = va_arg(ap, int*);
if (u.ip) {
*u.ip = mEmitted;
}
break;
@@ -842,15 +906,16 @@ mozilla::PrintfTarget::print(const char*
#undef TYPE_LONG
#undef TYPE_ULONG
#undef TYPE_LONGLONG
#undef TYPE_ULONGLONG
#undef TYPE_STRING
#undef TYPE_DOUBLE
#undef TYPE_INTSTR
#undef TYPE_POINTER
+#undef TYPE_WSTRING
#undef TYPE_UNKNOWN
#undef FLAG_LEFT
#undef FLAG_SIGNED
#undef FLAG_SPACED
#undef FLAG_ZEROS
#undef FLAG_NEG