string_util.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605
  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 <boost/range/algorithm.hpp>
  5. #include "common/common_funcs.h"
  6. #include "common/common_paths.h"
  7. #include "common/logging/log.h"
  8. #include "common/string_util.h"
  9. #ifdef _MSC_VER
  10. #include <Windows.h>
  11. #include <codecvt>
  12. #else
  13. #include <iconv.h>
  14. #endif
  15. namespace Common {
  16. /// Make a string lowercase
  17. std::string ToLower(std::string str) {
  18. boost::transform(str, str.begin(), ::tolower);
  19. return str;
  20. }
  21. /// Make a string uppercase
  22. std::string ToUpper(std::string str) {
  23. boost::transform(str, str.begin(), ::toupper);
  24. return str;
  25. }
  26. // faster than sscanf
  27. bool AsciiToHex(const char* _szValue, u32& result)
  28. {
  29. char *endptr = nullptr;
  30. const u32 value = strtoul(_szValue, &endptr, 16);
  31. if (!endptr || *endptr)
  32. return false;
  33. result = value;
  34. return true;
  35. }
  36. bool CharArrayFromFormatV(char* out, int outsize, const char* format, va_list args)
  37. {
  38. int writtenCount;
  39. #ifdef _MSC_VER
  40. // You would think *printf are simple, right? Iterate on each character,
  41. // if it's a format specifier handle it properly, etc.
  42. //
  43. // Nooooo. Not according to the C standard.
  44. //
  45. // According to the C99 standard (7.19.6.1 "The fprintf function")
  46. // The format shall be a multibyte character sequence
  47. //
  48. // Because some character encodings might have '%' signs in the middle of
  49. // a multibyte sequence (SJIS for example only specifies that the first
  50. // byte of a 2 byte sequence is "high", the second byte can be anything),
  51. // printf functions have to decode the multibyte sequences and try their
  52. // best to not screw up.
  53. //
  54. // Unfortunately, on Windows, the locale for most languages is not UTF-8
  55. // as we would need. Notably, for zh_TW, Windows chooses EUC-CN as the
  56. // locale, and completely fails when trying to decode UTF-8 as EUC-CN.
  57. //
  58. // On the other hand, the fix is simple: because we use UTF-8, no such
  59. // multibyte handling is required as we can simply assume that no '%' char
  60. // will be present in the middle of a multibyte sequence.
  61. //
  62. // This is why we lookup an ANSI (cp1252) locale here and use _vsnprintf_l.
  63. static locale_t c_locale = nullptr;
  64. if (!c_locale)
  65. c_locale = _create_locale(LC_ALL, ".1252");
  66. writtenCount = _vsnprintf_l(out, outsize, format, c_locale, args);
  67. #else
  68. writtenCount = vsnprintf(out, outsize, format, args);
  69. #endif
  70. if (writtenCount > 0 && writtenCount < outsize)
  71. {
  72. out[writtenCount] = '\0';
  73. return true;
  74. }
  75. else
  76. {
  77. out[outsize - 1] = '\0';
  78. return false;
  79. }
  80. }
  81. std::string StringFromFormat(const char* format, ...)
  82. {
  83. va_list args;
  84. char *buf = nullptr;
  85. #ifdef _WIN32
  86. int required = 0;
  87. va_start(args, format);
  88. required = _vscprintf(format, args);
  89. buf = new char[required + 1];
  90. CharArrayFromFormatV(buf, required + 1, format, args);
  91. va_end(args);
  92. std::string temp = buf;
  93. delete[] buf;
  94. #else
  95. va_start(args, format);
  96. if (vasprintf(&buf, format, args) < 0)
  97. LOG_ERROR(Common, "Unable to allocate memory for string");
  98. va_end(args);
  99. std::string temp = buf;
  100. free(buf);
  101. #endif
  102. return temp;
  103. }
  104. // For Debugging. Read out an u8 array.
  105. std::string ArrayToString(const u8 *data, u32 size, int line_len, bool spaces)
  106. {
  107. std::ostringstream oss;
  108. oss << std::setfill('0') << std::hex;
  109. for (int line = 0; size; ++data, --size)
  110. {
  111. oss << std::setw(2) << (int)*data;
  112. if (line_len == ++line)
  113. {
  114. oss << '\n';
  115. line = 0;
  116. }
  117. else if (spaces)
  118. oss << ' ';
  119. }
  120. return oss.str();
  121. }
  122. // Turns " hej " into "hej". Also handles tabs.
  123. std::string StripSpaces(const std::string &str)
  124. {
  125. const size_t s = str.find_first_not_of(" \t\r\n");
  126. if (str.npos != s)
  127. return str.substr(s, str.find_last_not_of(" \t\r\n") - s + 1);
  128. else
  129. return "";
  130. }
  131. // "\"hello\"" is turned to "hello"
  132. // This one assumes that the string has already been space stripped in both
  133. // ends, as done by StripSpaces above, for example.
  134. std::string StripQuotes(const std::string& s)
  135. {
  136. if (s.size() && '\"' == s[0] && '\"' == *s.rbegin())
  137. return s.substr(1, s.size() - 2);
  138. else
  139. return s;
  140. }
  141. bool TryParse(const std::string &str, u32 *const output)
  142. {
  143. char *endptr = nullptr;
  144. // Reset errno to a value other than ERANGE
  145. errno = 0;
  146. unsigned long value = strtoul(str.c_str(), &endptr, 0);
  147. if (!endptr || *endptr)
  148. return false;
  149. if (errno == ERANGE)
  150. return false;
  151. #if ULONG_MAX > UINT_MAX
  152. if (value >= 0x100000000ull
  153. && value <= 0xFFFFFFFF00000000ull)
  154. return false;
  155. #endif
  156. *output = static_cast<u32>(value);
  157. return true;
  158. }
  159. bool TryParse(const std::string &str, bool *const output)
  160. {
  161. if ("1" == str || "true" == ToLower(str))
  162. *output = true;
  163. else if ("0" == str || "false" == ToLower(str))
  164. *output = false;
  165. else
  166. return false;
  167. return true;
  168. }
  169. std::string StringFromBool(bool value)
  170. {
  171. return value ? "True" : "False";
  172. }
  173. bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _pFilename, std::string* _pExtension)
  174. {
  175. if (full_path.empty())
  176. return false;
  177. size_t dir_end = full_path.find_last_of("/"
  178. // windows needs the : included for something like just "C:" to be considered a directory
  179. #ifdef _WIN32
  180. ":"
  181. #endif
  182. );
  183. if (std::string::npos == dir_end)
  184. dir_end = 0;
  185. else
  186. dir_end += 1;
  187. size_t fname_end = full_path.rfind('.');
  188. if (fname_end < dir_end || std::string::npos == fname_end)
  189. fname_end = full_path.size();
  190. if (_pPath)
  191. *_pPath = full_path.substr(0, dir_end);
  192. if (_pFilename)
  193. *_pFilename = full_path.substr(dir_end, fname_end - dir_end);
  194. if (_pExtension)
  195. *_pExtension = full_path.substr(fname_end);
  196. return true;
  197. }
  198. void BuildCompleteFilename(std::string& _CompleteFilename, const std::string& _Path, const std::string& _Filename)
  199. {
  200. _CompleteFilename = _Path;
  201. // check for seperator
  202. if (DIR_SEP_CHR != *_CompleteFilename.rbegin())
  203. _CompleteFilename += DIR_SEP_CHR;
  204. // add the filename
  205. _CompleteFilename += _Filename;
  206. }
  207. void SplitString(const std::string& str, const char delim, std::vector<std::string>& output)
  208. {
  209. std::istringstream iss(str);
  210. output.resize(1);
  211. while (std::getline(iss, *output.rbegin(), delim))
  212. output.push_back("");
  213. output.pop_back();
  214. }
  215. std::string TabsToSpaces(int tab_size, const std::string &in)
  216. {
  217. const std::string spaces(tab_size, ' ');
  218. std::string out(in);
  219. size_t i = 0;
  220. while (out.npos != (i = out.find('\t')))
  221. out.replace(i, 1, spaces);
  222. return out;
  223. }
  224. std::string ReplaceAll(std::string result, const std::string& src, const std::string& dest)
  225. {
  226. size_t pos = 0;
  227. if (src == dest)
  228. return result;
  229. while ((pos = result.find(src, pos)) != std::string::npos)
  230. {
  231. result.replace(pos, src.size(), dest);
  232. pos += dest.length();
  233. }
  234. return result;
  235. }
  236. // UriDecode and UriEncode are from http://www.codeguru.com/cpp/cpp/string/conversions/print.php/c12759
  237. // by jinq0123 (November 2, 2006)
  238. // Uri encode and decode.
  239. // RFC1630, RFC1738, RFC2396
  240. //#include <string>
  241. //#include <assert.h>
  242. const char HEX2DEC[256] =
  243. {
  244. /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
  245. /* 0 */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16,
  246. /* 1 */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16,
  247. /* 2 */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16,
  248. /* 3 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,16,16, 16,16,16,16,
  249. /* 4 */ 16,10,11,12, 13,14,15,16, 16,16,16,16, 16,16,16,16,
  250. /* 5 */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16,
  251. /* 6 */ 16,10,11,12, 13,14,15,16, 16,16,16,16, 16,16,16,16,
  252. /* 7 */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16,
  253. /* 8 */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16,
  254. /* 9 */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16,
  255. /* A */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16,
  256. /* B */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16,
  257. /* C */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16,
  258. /* D */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16,
  259. /* E */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16,
  260. /* F */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16
  261. };
  262. std::string UriDecode(const std::string & sSrc)
  263. {
  264. // Note from RFC1630: "Sequences which start with a percent sign
  265. // but are not followed by two hexadecimal characters (0-9, A-F) are reserved
  266. // for future extension"
  267. const unsigned char * pSrc = (const unsigned char *)sSrc.c_str();
  268. const size_t SRC_LEN = sSrc.length();
  269. const unsigned char * const SRC_END = pSrc + SRC_LEN;
  270. const unsigned char * const SRC_LAST_DEC = SRC_END - 2; // last decodable '%'
  271. char * const pStart = new char[SRC_LEN];
  272. char * pEnd = pStart;
  273. while (pSrc < SRC_LAST_DEC)
  274. {
  275. if (*pSrc == '%')
  276. {
  277. char dec1, dec2;
  278. if (16 != (dec1 = HEX2DEC[*(pSrc + 1)])
  279. && 16 != (dec2 = HEX2DEC[*(pSrc + 2)]))
  280. {
  281. *pEnd++ = (dec1 << 4) + dec2;
  282. pSrc += 3;
  283. continue;
  284. }
  285. }
  286. *pEnd++ = *pSrc++;
  287. }
  288. // the last 2- chars
  289. while (pSrc < SRC_END)
  290. *pEnd++ = *pSrc++;
  291. std::string sResult(pStart, pEnd);
  292. delete [] pStart;
  293. return sResult;
  294. }
  295. // Only alphanum is safe.
  296. const char SAFE[256] =
  297. {
  298. /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
  299. /* 0 */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
  300. /* 1 */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
  301. /* 2 */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
  302. /* 3 */ 1,1,1,1, 1,1,1,1, 1,1,0,0, 0,0,0,0,
  303. /* 4 */ 0,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1,
  304. /* 5 */ 1,1,1,1, 1,1,1,1, 1,1,1,0, 0,0,0,0,
  305. /* 6 */ 0,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1,
  306. /* 7 */ 1,1,1,1, 1,1,1,1, 1,1,1,0, 0,0,0,0,
  307. /* 8 */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
  308. /* 9 */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
  309. /* A */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
  310. /* B */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
  311. /* C */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
  312. /* D */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
  313. /* E */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
  314. /* F */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0
  315. };
  316. std::string UriEncode(const std::string & sSrc)
  317. {
  318. const char DEC2HEX[16 + 1] = "0123456789ABCDEF";
  319. const unsigned char * pSrc = (const unsigned char *)sSrc.c_str();
  320. const size_t SRC_LEN = sSrc.length();
  321. unsigned char * const pStart = new unsigned char[SRC_LEN * 3];
  322. unsigned char * pEnd = pStart;
  323. const unsigned char * const SRC_END = pSrc + SRC_LEN;
  324. for (; pSrc < SRC_END; ++pSrc)
  325. {
  326. if (SAFE[*pSrc])
  327. *pEnd++ = *pSrc;
  328. else
  329. {
  330. // escape this char
  331. *pEnd++ = '%';
  332. *pEnd++ = DEC2HEX[*pSrc >> 4];
  333. *pEnd++ = DEC2HEX[*pSrc & 0x0F];
  334. }
  335. }
  336. std::string sResult((char *)pStart, (char *)pEnd);
  337. delete [] pStart;
  338. return sResult;
  339. }
  340. #ifdef _MSC_VER
  341. std::string UTF16ToUTF8(const std::u16string& input)
  342. {
  343. std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
  344. return convert.to_bytes(input);
  345. }
  346. std::u16string UTF8ToUTF16(const std::string& input)
  347. {
  348. std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
  349. return convert.from_bytes(input);
  350. }
  351. static std::string UTF16ToUTF8(const std::wstring& input)
  352. {
  353. auto const size = WideCharToMultiByte(CP_UTF8, 0, input.data(), static_cast<int>(input.size()), nullptr, 0, nullptr, nullptr);
  354. std::string output;
  355. output.resize(size);
  356. if (size == 0 || size != WideCharToMultiByte(CP_UTF8, 0, input.data(), input.size(), &output[0], output.size(), nullptr, nullptr))
  357. output.clear();
  358. return output;
  359. }
  360. static std::wstring CPToUTF16(u32 code_page, const std::string& input)
  361. {
  362. auto const size = MultiByteToWideChar(code_page, 0, input.data(), static_cast<int>(input.size()), nullptr, 0);
  363. std::wstring output;
  364. output.resize(size);
  365. if (size == 0 || size != MultiByteToWideChar(code_page, 0, input.data(), static_cast<int>(input.size()), &output[0], static_cast<int>(output.size())))
  366. output.clear();
  367. return output;
  368. }
  369. std::wstring UTF8ToUTF16W(const std::string &input)
  370. {
  371. return CPToUTF16(CP_UTF8, input);
  372. }
  373. std::string SHIFTJISToUTF8(const std::string& input)
  374. {
  375. return UTF16ToUTF8(CPToUTF16(932, input));
  376. }
  377. std::string CP1252ToUTF8(const std::string& input)
  378. {
  379. return UTF16ToUTF8(CPToUTF16(1252, input));
  380. }
  381. #else
  382. template <typename T>
  383. static std::string CodeToUTF8(const char* fromcode, const std::basic_string<T>& input)
  384. {
  385. std::string result;
  386. iconv_t const conv_desc = iconv_open("UTF-8", fromcode);
  387. if ((iconv_t)(-1) == conv_desc)
  388. {
  389. LOG_ERROR(Common, "Iconv initialization failure [%s]: %s", fromcode, strerror(errno));
  390. iconv_close(conv_desc);
  391. return {};
  392. }
  393. const size_t in_bytes = sizeof(T) * input.size();
  394. // Multiply by 4, which is the max number of bytes to encode a codepoint
  395. const size_t out_buffer_size = 4 * in_bytes;
  396. std::string out_buffer;
  397. out_buffer.resize(out_buffer_size);
  398. auto src_buffer = &input[0];
  399. size_t src_bytes = in_bytes;
  400. auto dst_buffer = &out_buffer[0];
  401. size_t dst_bytes = out_buffer.size();
  402. while (0 != src_bytes)
  403. {
  404. size_t const iconv_result = iconv(conv_desc, (char**)(&src_buffer), &src_bytes,
  405. &dst_buffer, &dst_bytes);
  406. if (static_cast<size_t>(-1) == iconv_result)
  407. {
  408. if (EILSEQ == errno || EINVAL == errno)
  409. {
  410. // Try to skip the bad character
  411. if (0 != src_bytes)
  412. {
  413. --src_bytes;
  414. ++src_buffer;
  415. }
  416. }
  417. else
  418. {
  419. LOG_ERROR(Common, "iconv failure [%s]: %s", fromcode, strerror(errno));
  420. break;
  421. }
  422. }
  423. }
  424. out_buffer.resize(out_buffer_size - dst_bytes);
  425. out_buffer.swap(result);
  426. iconv_close(conv_desc);
  427. return result;
  428. }
  429. std::u16string UTF8ToUTF16(const std::string& input)
  430. {
  431. std::u16string result;
  432. iconv_t const conv_desc = iconv_open("UTF-16LE", "UTF-8");
  433. if ((iconv_t)(-1) == conv_desc)
  434. {
  435. LOG_ERROR(Common, "Iconv initialization failure [UTF-8]: %s", strerror(errno));
  436. iconv_close(conv_desc);
  437. return {};
  438. }
  439. const size_t in_bytes = sizeof(char) * input.size();
  440. // Multiply by 4, which is the max number of bytes to encode a codepoint
  441. const size_t out_buffer_size = 4 * sizeof(char16_t) * in_bytes;
  442. std::u16string out_buffer;
  443. out_buffer.resize(out_buffer_size);
  444. char* src_buffer = const_cast<char*>(&input[0]);
  445. size_t src_bytes = in_bytes;
  446. char* dst_buffer = (char*)(&out_buffer[0]);
  447. size_t dst_bytes = out_buffer.size();
  448. while (0 != src_bytes)
  449. {
  450. size_t const iconv_result = iconv(conv_desc, &src_buffer, &src_bytes,
  451. &dst_buffer, &dst_bytes);
  452. if (static_cast<size_t>(-1) == iconv_result)
  453. {
  454. if (EILSEQ == errno || EINVAL == errno)
  455. {
  456. // Try to skip the bad character
  457. if (0 != src_bytes)
  458. {
  459. --src_bytes;
  460. ++src_buffer;
  461. }
  462. }
  463. else
  464. {
  465. LOG_ERROR(Common, "iconv failure [UTF-8]: %s", strerror(errno));
  466. break;
  467. }
  468. }
  469. }
  470. out_buffer.resize(out_buffer_size - dst_bytes);
  471. out_buffer.swap(result);
  472. iconv_close(conv_desc);
  473. return result;
  474. }
  475. std::string UTF16ToUTF8(const std::u16string& input)
  476. {
  477. return CodeToUTF8("UTF-16LE", input);
  478. }
  479. std::string CP1252ToUTF8(const std::string& input)
  480. {
  481. //return CodeToUTF8("CP1252//TRANSLIT", input);
  482. //return CodeToUTF8("CP1252//IGNORE", input);
  483. return CodeToUTF8("CP1252", input);
  484. }
  485. std::string SHIFTJISToUTF8(const std::string& input)
  486. {
  487. //return CodeToUTF8("CP932", input);
  488. return CodeToUTF8("SJIS", input);
  489. }
  490. #endif
  491. }