diff --git a/misc.cpp b/misc.cpp index 42b70161..be3d6bf1 100644 --- a/misc.cpp +++ b/misc.cpp @@ -197,6 +197,70 @@ std::string StringNarrow(const wchar_t *str, bool throwOnError) return result; } +std::wstring StringWiden(const char *str, bool throwOnError) +{ + CRYPTOPP_ASSERT(str); + std::wstring result; + + // Safer functions on Windows for C&A, https://github.com/weidai11/cryptopp/issues/55 +#if (CRYPTOPP_MSC_VERSION >= 1400) + size_t len=0, size=0; + errno_t err = 0; + + //const char* ptr = str; + //while (*ptr++) len++; + len = std::strlen(str)+1; + + err = mbstowcs_s(&size, NULLPTR, 0, str, len); + CRYPTOPP_ASSERT(err == 0); + if (err != 0) + { + if (throwOnError) + throw InvalidArgument("StringWiden: wcstombs_s() call failed with error " + IntToString(err)); + else + return std::wstring(); + } + + result.resize(size); + err = mbstowcs_s(&size, &result[0], size, str, len); + CRYPTOPP_ASSERT(err == 0); + if (err != 0) + { + if (throwOnError) + throw InvalidArgument("StringWiden: wcstombs_s() call failed with error " + IntToString(err)); + else + return std::wstring(); + } + + // The safe routine's size includes the NULL. + if (!result.empty() && result[size - 1] == '\0') + result.erase(size - 1); +#else + size_t size = mbstowcs(NULLPTR, str, 0); + CRYPTOPP_ASSERT(size != (size_t)-1); + if (size == (size_t)-1) + { + if (throwOnError) + throw InvalidArgument("StringWiden: mbstowcs() call failed"); + else + return std::wstring(); + } + + result.resize(size); + size = mbstowcs(&result[0], str, size); + CRYPTOPP_ASSERT(size != (size_t)-1); + if (size == (size_t)-1) + { + if (throwOnError) + throw InvalidArgument("StringWiden: mbstowcs() call failed"); + else + return std::wstring(); + } +#endif + + return result; +} + void CallNewHandler() { using std::new_handler; diff --git a/misc.h b/misc.h index 6bb2d4c2..76893d16 100644 --- a/misc.h +++ b/misc.h @@ -163,7 +163,6 @@ struct CompileAssert { static char dummy[2*b-1]; }; -//! \endif #define CRYPTOPP_COMPILE_ASSERT(assertion) CRYPTOPP_COMPILE_ASSERT_INSTANCE(assertion, __LINE__) #if defined(CRYPTOPP_EXPORTS) || defined(CRYPTOPP_IMPORTS) @@ -1293,9 +1292,9 @@ inline void SecureWipeArray(T *buf, size_t n) //! \brief Converts a wide character C-string to a multibyte string //! \param str C-string consisting of wide characters -//! \param throwOnError flag indication the function should throw on error +//! \param throwOnError flag indicating the function should throw on error //! \returns str converted to a multibyte string or an empty string. -//! \details StringNarrow converts a wide string to a narrow string using C++ std::wcstombs() under +//! \details StringNarrow() converts a wide string to a narrow string using C++ std::wcstombs() under //! the executing thread's locale. A locale must be set before using this function, and it can be //! set with std::setlocale() if needed. Upon success, the converted string is returned. //! \details Upon failure with throwOnError as false, the function returns an empty string. If @@ -1305,6 +1304,20 @@ inline void SecureWipeArray(T *buf, size_t n) //! then a 0x21 error is returned on Windows which eventually results in an InvalidArgument() exception. std::string StringNarrow(const wchar_t *str, bool throwOnError = true); +//! \brief Converts a multibyte C-string to a wide character string +//! \param str C-string consisting of wide characters +//! \param throwOnError flag indicating the function should throw on error +//! \returns str converted to a multibyte string or an empty string. +//! \details StringWiden() converts a narrow string to a wide string using C++ std::mbstowcs() under +//! the executing thread's locale. A locale must be set before using this function, and it can be +//! set with std::setlocale() if needed. Upon success, the converted string is returned. +//! \details Upon failure with throwOnError as false, the function returns an empty string. If +//! throwOnError as true, the function throws an InvalidArgument() exception. +//! \note If you try to convert, say, the Chinese character for "bone" from UTF-8 (0xE9 0xAA 0xA8) +//! to UTF-16 (0x9AA8), then you must ensure the locale is available. If the locale is not available, +//! then a 0x21 error is returned on Windows which eventually results in an InvalidArgument() exception. +std::wstring StringWiden(const char *str, bool throwOnError = true); + #ifdef CRYPTOPP_DOXYGEN_PROCESSING //! \brief Allocates a buffer on 16-byte boundary