string_util.cpp 16 KB

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