diff --git a/format.cc b/format.cc index 517caba6..3daa1674 100644 --- a/format.cc +++ b/format.cc @@ -167,6 +167,42 @@ void fmt::internal::ReportUnknownType(char code, const char *type) { << static_cast(code) << type)); } +#ifdef _WIN32 + +fmt::internal::UTF8ToUTF16::UTF8ToUTF16(fmt::StringRef s) { + int length = MultiByteToWideChar( + CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, 0, 0); + static const char ERROR[] = "cannot convert string from UTF-8 to UTF-16"; + if (length == 0) + ThrowSystemError(GetLastError(), ERROR); + buffer_.resize(length); + length = MultiByteToWideChar( + CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, &buffer_[0], length); + if (length == 0) + ThrowSystemError(GetLastError(), ERROR); +} + +fmt::internal::UTF16ToUTF8::UTF16ToUTF8(fmt::WStringRef s) { + if (int error_code = Convert(s)) { + ThrowSystemError(GetLastError(), + "cannot convert string from UTF-16 to UTF-8"); + } +} + +int fmt::internal::UTF16ToUTF8::Convert(fmt::WStringRef s) { + int length = WideCharToMultiByte(CP_UTF8, 0, s.c_str(), -1, 0, 0, 0, 0); + if (length == 0) + return GetLastError(); + buffer_.resize(length); + length = WideCharToMultiByte( + CP_UTF8, 0, s.c_str(), -1, &buffer_[0], length, 0, 0); + if (length == 0) + return GetLastError(); + return 0; +} + +#endif + void fmt::internal::FormatSystemErrorMessage( fmt::Writer &out, int error_code, fmt::StringRef message) { #ifndef _WIN32 diff --git a/format.h b/format.h index 20fe5e27..b269824f 100644 --- a/format.h +++ b/format.h @@ -458,6 +458,37 @@ template void FormatCustomArg( BasicWriter &w, const void *arg, const FormatSpec &spec); +#ifdef _WIN32 +// A converter from UTF-8 to UTF-16. +// It is only provided for Windows since other systems use UTF-8. +class UTF8ToUTF16 { + private: + Array buffer_; + + public: + explicit UTF8ToUTF16(StringRef s); + operator const wchar_t*() const { return &buffer_[0]; } + size_t size() const { return buffer_.size() - 1; } +}; + +// A converter from UTF-16 to UTF-8. +// It is only provided for Windows since other systems use UTF-8. +class UTF16ToUTF8 { + private: + Array buffer_; + + public: + UTF16ToUTF8() {} + explicit UTF16ToUTF8(WStringRef s); + operator const char*() const { return &buffer_[0]; } + size_t size() const { return buffer_.size() - 1; } + + // Performs conversion returning a system error code instead of + // throwing exception on error. + int Convert(WStringRef s); +}; +#endif + // Formats a system error message writing the output to out. void FormatSystemErrorMessage(Writer &out, int error_code, StringRef message); @@ -1507,7 +1538,7 @@ class SystemErrorSink { /** Throws SystemError with a code and a formatted message. */ inline Formatter ThrowSystemError( - int error_code, StringRef format) { + int error_code, StringRef format = 0) { Formatter f(format, SystemErrorSink(error_code)); return f; }