string_util.cpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. // Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <algorithm>
  5. #include <cctype>
  6. #include <cerrno>
  7. #include <codecvt>
  8. #include <cstdio>
  9. #include <cstdlib>
  10. #include <cstring>
  11. #include "common/common_paths.h"
  12. #include "common/logging/log.h"
  13. #include "common/string_util.h"
  14. #ifdef _WIN32
  15. #include <windows.h>
  16. #endif
  17. namespace Common {
  18. /// Make a string lowercase
  19. std::string ToLower(std::string str) {
  20. std::transform(str.begin(), str.end(), str.begin(),
  21. [](unsigned char c) { return std::tolower(c); });
  22. return str;
  23. }
  24. /// Make a string uppercase
  25. std::string ToUpper(std::string str) {
  26. std::transform(str.begin(), str.end(), str.begin(),
  27. [](unsigned char c) { return std::toupper(c); });
  28. return str;
  29. }
  30. // For Debugging. Read out an u8 array.
  31. std::string ArrayToString(const u8* data, std::size_t size, int line_len, bool spaces) {
  32. std::ostringstream oss;
  33. oss << std::setfill('0') << std::hex;
  34. for (int line = 0; size; ++data, --size) {
  35. oss << std::setw(2) << (int)*data;
  36. if (line_len == ++line) {
  37. oss << '\n';
  38. line = 0;
  39. } else if (spaces)
  40. oss << ' ';
  41. }
  42. return oss.str();
  43. }
  44. std::string StringFromBuffer(const std::vector<u8>& data) {
  45. return std::string(data.begin(), std::find(data.begin(), data.end(), '\0'));
  46. }
  47. // Turns " hej " into "hej". Also handles tabs.
  48. std::string StripSpaces(const std::string& str) {
  49. const std::size_t s = str.find_first_not_of(" \t\r\n");
  50. if (str.npos != s)
  51. return str.substr(s, str.find_last_not_of(" \t\r\n") - s + 1);
  52. else
  53. return "";
  54. }
  55. // "\"hello\"" is turned to "hello"
  56. // This one assumes that the string has already been space stripped in both
  57. // ends, as done by StripSpaces above, for example.
  58. std::string StripQuotes(const std::string& s) {
  59. if (s.size() && '\"' == s[0] && '\"' == *s.rbegin())
  60. return s.substr(1, s.size() - 2);
  61. else
  62. return s;
  63. }
  64. bool TryParse(const std::string& str, u32* const output) {
  65. char* endptr = nullptr;
  66. // Reset errno to a value other than ERANGE
  67. errno = 0;
  68. unsigned long value = strtoul(str.c_str(), &endptr, 0);
  69. if (!endptr || *endptr)
  70. return false;
  71. if (errno == ERANGE)
  72. return false;
  73. #if ULONG_MAX > UINT_MAX
  74. if (value >= 0x100000000ull && value <= 0xFFFFFFFF00000000ull)
  75. return false;
  76. #endif
  77. *output = static_cast<u32>(value);
  78. return true;
  79. }
  80. bool TryParse(const std::string& str, bool* const output) {
  81. if ("1" == str || "true" == ToLower(str))
  82. *output = true;
  83. else if ("0" == str || "false" == ToLower(str))
  84. *output = false;
  85. else
  86. return false;
  87. return true;
  88. }
  89. std::string StringFromBool(bool value) {
  90. return value ? "True" : "False";
  91. }
  92. bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _pFilename,
  93. std::string* _pExtension) {
  94. if (full_path.empty())
  95. return false;
  96. std::size_t dir_end = full_path.find_last_of("/"
  97. // windows needs the : included for something like just "C:" to be considered a directory
  98. #ifdef _WIN32
  99. "\\:"
  100. #endif
  101. );
  102. if (std::string::npos == dir_end)
  103. dir_end = 0;
  104. else
  105. dir_end += 1;
  106. std::size_t fname_end = full_path.rfind('.');
  107. if (fname_end < dir_end || std::string::npos == fname_end)
  108. fname_end = full_path.size();
  109. if (_pPath)
  110. *_pPath = full_path.substr(0, dir_end);
  111. if (_pFilename)
  112. *_pFilename = full_path.substr(dir_end, fname_end - dir_end);
  113. if (_pExtension)
  114. *_pExtension = full_path.substr(fname_end);
  115. return true;
  116. }
  117. void BuildCompleteFilename(std::string& _CompleteFilename, const std::string& _Path,
  118. const std::string& _Filename) {
  119. _CompleteFilename = _Path;
  120. // check for seperator
  121. if (DIR_SEP_CHR != *_CompleteFilename.rbegin())
  122. _CompleteFilename += DIR_SEP_CHR;
  123. // add the filename
  124. _CompleteFilename += _Filename;
  125. }
  126. void SplitString(const std::string& str, const char delim, std::vector<std::string>& output) {
  127. std::istringstream iss(str);
  128. output.resize(1);
  129. while (std::getline(iss, *output.rbegin(), delim)) {
  130. output.emplace_back();
  131. }
  132. output.pop_back();
  133. }
  134. std::string TabsToSpaces(int tab_size, std::string in) {
  135. std::size_t i = 0;
  136. while ((i = in.find('\t')) != std::string::npos) {
  137. in.replace(i, 1, tab_size, ' ');
  138. }
  139. return in;
  140. }
  141. std::string ReplaceAll(std::string result, const std::string& src, const std::string& dest) {
  142. std::size_t pos = 0;
  143. if (src == dest)
  144. return result;
  145. while ((pos = result.find(src, pos)) != std::string::npos) {
  146. result.replace(pos, src.size(), dest);
  147. pos += dest.length();
  148. }
  149. return result;
  150. }
  151. std::string UTF16ToUTF8(const std::u16string& input) {
  152. #ifdef _MSC_VER
  153. // Workaround for missing char16_t/char32_t instantiations in MSVC2017
  154. std::wstring_convert<std::codecvt_utf8_utf16<__int16>, __int16> convert;
  155. std::basic_string<__int16> tmp_buffer(input.cbegin(), input.cend());
  156. return convert.to_bytes(tmp_buffer);
  157. #else
  158. std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
  159. return convert.to_bytes(input);
  160. #endif
  161. }
  162. std::u16string UTF8ToUTF16(const std::string& input) {
  163. #ifdef _MSC_VER
  164. // Workaround for missing char16_t/char32_t instantiations in MSVC2017
  165. std::wstring_convert<std::codecvt_utf8_utf16<__int16>, __int16> convert;
  166. auto tmp_buffer = convert.from_bytes(input);
  167. return std::u16string(tmp_buffer.cbegin(), tmp_buffer.cend());
  168. #else
  169. std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
  170. return convert.from_bytes(input);
  171. #endif
  172. }
  173. #ifdef _WIN32
  174. static std::wstring CPToUTF16(u32 code_page, const std::string& input) {
  175. const auto size =
  176. MultiByteToWideChar(code_page, 0, input.data(), static_cast<int>(input.size()), nullptr, 0);
  177. if (size == 0) {
  178. return L"";
  179. }
  180. std::wstring output(size, L'\0');
  181. if (size != MultiByteToWideChar(code_page, 0, input.data(), static_cast<int>(input.size()),
  182. &output[0], static_cast<int>(output.size()))) {
  183. output.clear();
  184. }
  185. return output;
  186. }
  187. std::string UTF16ToUTF8(const std::wstring& input) {
  188. const auto size = WideCharToMultiByte(CP_UTF8, 0, input.data(), static_cast<int>(input.size()),
  189. nullptr, 0, nullptr, nullptr);
  190. if (size == 0) {
  191. return "";
  192. }
  193. std::string output(size, '\0');
  194. if (size != WideCharToMultiByte(CP_UTF8, 0, input.data(), static_cast<int>(input.size()),
  195. &output[0], static_cast<int>(output.size()), nullptr,
  196. nullptr)) {
  197. output.clear();
  198. }
  199. return output;
  200. }
  201. std::wstring UTF8ToUTF16W(const std::string& input) {
  202. return CPToUTF16(CP_UTF8, input);
  203. }
  204. #endif
  205. std::string StringFromFixedZeroTerminatedBuffer(const char* buffer, std::size_t max_len) {
  206. std::size_t len = 0;
  207. while (len < max_len && buffer[len] != '\0')
  208. ++len;
  209. return std::string(buffer, len);
  210. }
  211. const char* TrimSourcePath(const char* path, const char* root) {
  212. const char* p = path;
  213. while (*p != '\0') {
  214. const char* next_slash = p;
  215. while (*next_slash != '\0' && *next_slash != '/' && *next_slash != '\\') {
  216. ++next_slash;
  217. }
  218. bool is_src = Common::ComparePartialString(p, next_slash, root);
  219. p = next_slash;
  220. if (*p != '\0') {
  221. ++p;
  222. }
  223. if (is_src) {
  224. path = p;
  225. }
  226. }
  227. return path;
  228. }
  229. } // namespace Common