#pragma once #include #include #include #include #include "./com/com_include.h" #include "util_bit.h" #include "util_likely.h" namespace dxvk::str { template struct UnicodeChar { }; template<> struct UnicodeChar<1> { using type = uint8_t; }; template<> struct UnicodeChar<2> { using type = uint16_t; }; template<> struct UnicodeChar<4> { using type = uint32_t; }; template using UnicodeCharType = typename UnicodeChar::type; const uint8_t* decodeTypedChar( const uint8_t* begin, const uint8_t* end, uint32_t& ch); const uint16_t* decodeTypedChar( const uint16_t* begin, const uint16_t* end, uint32_t& ch); const uint32_t* decodeTypedChar( const uint32_t* begin, const uint32_t* end, uint32_t& ch); size_t encodeTypedChar( uint8_t* begin, uint8_t* end, uint32_t ch); size_t encodeTypedChar( uint16_t* begin, uint16_t* end, uint32_t ch); size_t encodeTypedChar( uint32_t* begin, uint32_t* end, uint32_t ch); /** * \brief Decodes a single character * * Note that \c begin and \c end must not be equal. * \param [in] begin Pointer to current position within the input string * \param [in] end Pointer to the end of the input string * \param [out] ch Pointer to the decoded character code * \returns Pointer to next character in the input string */ template const T* decodeChar( const T* begin, const T* end, uint32_t& ch) { using CharType = UnicodeCharType; const CharType* result = decodeTypedChar( reinterpret_cast(begin), reinterpret_cast(end), ch); return reinterpret_cast(result); } /** * \brief Encodes a character * * Note that \c begin and \c end may be both be \c nullptr or equal, in * which case only the length of the encoded character will be returned. * \param [in] begin Pointer to current position within the output string * \param [in] end Pointer to the end of the output string * \param [in] ch Character to encode * \returns If begin is \c nullptr , the number of units required to encode * the character. Otherwise, the number of units written to the output. * This may return \c 0 for characters that cannot be written or encoded. */ template size_t encodeChar( T* begin, T* end, uint32_t ch) { using CharType = UnicodeCharType; return encodeTypedChar( reinterpret_cast(begin), reinterpret_cast(end), ch); } /** * \brief Computes length of a null-terminated string * * \param [in] begin Start of input string * \returns Number of characters in input string, * excluding the terminating null character */ template size_t length(const S* string) { size_t result = 0; while (string[result]) result += 1; return result; } /** * \brief Converts string from one encoding to another * * The output string arguments may be \c nullptr. In that case, the * total length of the transcoded string will be returned, in units * of the output character type. The output string will only be * null-terminated if the input string is also null-terminated. * \tparam D Output character type * \tparam S Input character type * \param [in] dstBegin Start of output string * \param [in] dstLength Length of output string * \param [in] srcBegin Start of input string * \param [in] srcLength Length of input string * \returns If \c dstBegin is \c nullptr , the total number of output * characters required to store the output string. Otherwise, the * total number of characters written to the output string. */ template size_t transcodeString( D* dstBegin, size_t dstLength, const S* srcBegin, size_t srcLength) { size_t totalLength = 0; auto dstEnd = dstBegin + dstLength; auto srcEnd = srcBegin + srcLength; while (srcBegin < srcEnd) { uint32_t ch; srcBegin = decodeChar(srcBegin, srcEnd, ch); if (dstBegin) totalLength += encodeChar(dstBegin + totalLength, dstEnd, ch); else totalLength += encodeChar(nullptr, nullptr, ch); if (!ch) break; } return totalLength; } /** * \brief Creates string object from wide char array * * \param [in] ws Null-terminated wide string * \returns Regular string object */ std::string fromws(const WCHAR* ws); /** * \brief Creates wide string object from char array * * \param [in] mbs Null-terminated string * \returns Wide string object */ std::wstring tows(const char* mbs); #ifdef _WIN32 using path_string = std::wstring; inline path_string topath(const char* mbs) { return tows(mbs); } #else using path_string = std::string; inline path_string topath(const char* mbs) { return std::string(mbs); } #endif inline void format1(std::stringstream&) { } template void format1(std::stringstream& str, const WCHAR *arg, const Tx&... args) { str << fromws(arg); format1(str, args...); } template void format1(std::stringstream& str, const T& arg, const Tx&... args) { str << arg; format1(str, args...); } template std::string format(const Args&... args) { std::stringstream stream; format1(stream, args...); return stream.str(); } inline void strlcpy(char* dst, const char* src, size_t count) { if (count > 0) { std::strncpy(dst, src, count - 1); dst[count - 1] = '\0'; } } }