StringUtils.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. /**
  2. * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
  3. * SPDX-License-Identifier: Apache-2.0.
  4. */
  5. #include <aws/core/utils/StringUtils.h>
  6. #include <aws/core/utils/memory/stl/AWSStringStream.h>
  7. #include <algorithm>
  8. #include <iomanip>
  9. #include <cstdlib>
  10. #include <cstdio>
  11. #include <cstring>
  12. #include <functional>
  13. #ifdef _WIN32
  14. #include <Windows.h>
  15. #endif
  16. using namespace Aws::Utils;
  17. void StringUtils::Replace(Aws::String& s, const char* search, const char* replace)
  18. {
  19. if(!search || !replace)
  20. {
  21. return;
  22. }
  23. size_t replaceLength = strlen(replace);
  24. size_t searchLength = strlen(search);
  25. for (std::size_t pos = 0;; pos += replaceLength)
  26. {
  27. pos = s.find(search, pos);
  28. if (pos == Aws::String::npos)
  29. break;
  30. s.erase(pos, searchLength);
  31. s.insert(pos, replace);
  32. }
  33. }
  34. Aws::String StringUtils::ToLower(const char* source)
  35. {
  36. Aws::String copy;
  37. size_t sourceLength = strlen(source);
  38. copy.resize(sourceLength);
  39. //appease the latest whims of the VC++ 2017 gods
  40. std::transform(source, source + sourceLength, copy.begin(), [](unsigned char c) { return (char)::tolower(c); });
  41. return copy;
  42. }
  43. Aws::String StringUtils::ToUpper(const char* source)
  44. {
  45. Aws::String copy;
  46. size_t sourceLength = strlen(source);
  47. copy.resize(sourceLength);
  48. //appease the latest whims of the VC++ 2017 gods
  49. std::transform(source, source + sourceLength, copy.begin(), [](unsigned char c) { return (char)::toupper(c); });
  50. return copy;
  51. }
  52. bool StringUtils::CaselessCompare(const char* value1, const char* value2)
  53. {
  54. Aws::String value1Lower = ToLower(value1);
  55. Aws::String value2Lower = ToLower(value2);
  56. return value1Lower == value2Lower;
  57. }
  58. Aws::Vector<Aws::String> StringUtils::Split(const Aws::String& toSplit, char splitOn)
  59. {
  60. return Split(toSplit, splitOn, SIZE_MAX, SplitOptions::NOT_SET);
  61. }
  62. Aws::Vector<Aws::String> StringUtils::Split(const Aws::String& toSplit, char splitOn, SplitOptions option)
  63. {
  64. return Split(toSplit, splitOn, SIZE_MAX, option);
  65. }
  66. Aws::Vector<Aws::String> StringUtils::Split(const Aws::String& toSplit, char splitOn, size_t numOfTargetParts)
  67. {
  68. return Split(toSplit, splitOn, numOfTargetParts, SplitOptions::NOT_SET);
  69. }
  70. Aws::Vector<Aws::String> StringUtils::Split(const Aws::String& toSplit, char splitOn, size_t numOfTargetParts, SplitOptions option)
  71. {
  72. Aws::Vector<Aws::String> returnValues;
  73. Aws::StringStream input(toSplit);
  74. Aws::String item;
  75. while(returnValues.size() < numOfTargetParts - 1 && std::getline(input, item, splitOn))
  76. {
  77. if (!item.empty() || option == SplitOptions::INCLUDE_EMPTY_ENTRIES)
  78. {
  79. returnValues.emplace_back(std::move(item));
  80. }
  81. }
  82. if (std::getline(input, item, static_cast<char>(EOF)))
  83. {
  84. if (option != SplitOptions::INCLUDE_EMPTY_ENTRIES)
  85. {
  86. // Trim all leading delimiters.
  87. item.erase(item.begin(), std::find_if(item.begin(), item.end(), [splitOn](int ch) { return ch != splitOn; }));
  88. if (!item.empty())
  89. {
  90. returnValues.emplace_back(std::move(item));
  91. }
  92. }
  93. else
  94. {
  95. returnValues.emplace_back(std::move(item));
  96. }
  97. }
  98. // To handle the case when there are trailing delimiters.
  99. else if (!toSplit.empty() && toSplit.back() == splitOn && option == SplitOptions::INCLUDE_EMPTY_ENTRIES)
  100. {
  101. returnValues.emplace_back();
  102. }
  103. return returnValues;
  104. }
  105. Aws::Vector<Aws::String> StringUtils::SplitOnLine(const Aws::String& toSplit)
  106. {
  107. Aws::StringStream input(toSplit);
  108. Aws::Vector<Aws::String> returnValues;
  109. Aws::String item;
  110. while (std::getline(input, item))
  111. {
  112. if (item.size() > 0)
  113. {
  114. returnValues.push_back(item);
  115. }
  116. }
  117. return returnValues;
  118. }
  119. Aws::String StringUtils::URLEncode(const char* unsafe)
  120. {
  121. Aws::StringStream escaped;
  122. escaped.fill('0');
  123. escaped << std::hex << std::uppercase;
  124. size_t unsafeLength = strlen(unsafe);
  125. for (auto i = unsafe, n = unsafe + unsafeLength; i != n; ++i)
  126. {
  127. char c = *i;
  128. if (IsAlnum(c) || c == '-' || c == '_' || c == '.' || c == '~')
  129. {
  130. escaped << (char)c;
  131. }
  132. else
  133. {
  134. //this unsigned char cast allows us to handle unicode characters.
  135. escaped << '%' << std::setw(2) << int((unsigned char)c) << std::setw(0);
  136. }
  137. }
  138. return escaped.str();
  139. }
  140. Aws::String StringUtils::UTF8Escape(const char* unicodeString, const char* delimiter)
  141. {
  142. Aws::StringStream escaped;
  143. escaped.fill('0');
  144. escaped << std::hex << std::uppercase;
  145. size_t unsafeLength = strlen(unicodeString);
  146. for (auto i = unicodeString, n = unicodeString + unsafeLength; i != n; ++i)
  147. {
  148. int c = *i;
  149. if (c >= ' ' && c < 127 )
  150. {
  151. escaped << (char)c;
  152. }
  153. else
  154. {
  155. //this unsigned char cast allows us to handle unicode characters.
  156. escaped << delimiter << std::setw(2) << int((unsigned char)c) << std::setw(0);
  157. }
  158. }
  159. return escaped.str();
  160. }
  161. Aws::String StringUtils::URLEncode(double unsafe)
  162. {
  163. char buffer[32];
  164. #if defined(_MSC_VER) && _MSC_VER < 1900
  165. _snprintf_s(buffer, sizeof(buffer), _TRUNCATE, "%g", unsafe);
  166. #else
  167. snprintf(buffer, sizeof(buffer), "%g", unsafe);
  168. #endif
  169. return StringUtils::URLEncode(buffer);
  170. }
  171. Aws::String StringUtils::URLDecode(const char* safe)
  172. {
  173. Aws::String unescaped;
  174. for (; *safe; safe++)
  175. {
  176. switch(*safe)
  177. {
  178. case '%':
  179. {
  180. int hex = 0;
  181. auto ch = *++safe;
  182. if (ch >= '0' && ch <= '9')
  183. {
  184. hex = (ch - '0') * 16;
  185. }
  186. else if (ch >= 'A' && ch <= 'F')
  187. {
  188. hex = (ch - 'A' + 10) * 16;
  189. }
  190. else if (ch >= 'a' && ch <= 'f')
  191. {
  192. hex = (ch - 'a' + 10) * 16;
  193. }
  194. else
  195. {
  196. unescaped.push_back('%');
  197. if (ch == 0)
  198. {
  199. return unescaped;
  200. }
  201. unescaped.push_back(ch);
  202. break;
  203. }
  204. ch = *++safe;
  205. if (ch >= '0' && ch <= '9')
  206. {
  207. hex += (ch - '0');
  208. }
  209. else if (ch >= 'A' && ch <= 'F')
  210. {
  211. hex += (ch - 'A' + 10);
  212. }
  213. else if (ch >= 'a' && ch <= 'f')
  214. {
  215. hex += (ch - 'a' + 10);
  216. }
  217. else
  218. {
  219. unescaped.push_back('%');
  220. unescaped.push_back(*(safe - 1));
  221. if (ch == 0)
  222. {
  223. return unescaped;
  224. }
  225. unescaped.push_back(ch);
  226. break;
  227. }
  228. unescaped.push_back(char(hex));
  229. break;
  230. }
  231. case '+':
  232. unescaped.push_back(' ');
  233. break;
  234. default:
  235. unescaped.push_back(*safe);
  236. break;
  237. }
  238. }
  239. return unescaped;
  240. }
  241. static bool IsSpace(int ch)
  242. {
  243. if (ch < -1 || ch > 255)
  244. {
  245. return false;
  246. }
  247. return ::isspace(ch) != 0;
  248. }
  249. Aws::String StringUtils::LTrim(const char* source)
  250. {
  251. Aws::String copy(source);
  252. copy.erase(copy.begin(), std::find_if(copy.begin(), copy.end(), [](int ch) { return !IsSpace(ch); }));
  253. return copy;
  254. }
  255. // trim from end
  256. Aws::String StringUtils::RTrim(const char* source)
  257. {
  258. Aws::String copy(source);
  259. copy.erase(std::find_if(copy.rbegin(), copy.rend(), [](int ch) { return !IsSpace(ch); }).base(), copy.end());
  260. return copy;
  261. }
  262. // trim from both ends
  263. Aws::String StringUtils::Trim(const char* source)
  264. {
  265. return LTrim(RTrim(source).c_str());
  266. }
  267. long long StringUtils::ConvertToInt64(const char* source)
  268. {
  269. if(!source)
  270. {
  271. return 0;
  272. }
  273. #ifdef __ANDROID__
  274. return atoll(source);
  275. #else
  276. return std::atoll(source);
  277. #endif // __ANDROID__
  278. }
  279. long StringUtils::ConvertToInt32(const char* source)
  280. {
  281. if (!source)
  282. {
  283. return 0;
  284. }
  285. return std::atol(source);
  286. }
  287. bool StringUtils::ConvertToBool(const char* source)
  288. {
  289. if(!source)
  290. {
  291. return false;
  292. }
  293. Aws::String strValue = ToLower(source);
  294. if(strValue == "true" || strValue == "1")
  295. {
  296. return true;
  297. }
  298. return false;
  299. }
  300. double StringUtils::ConvertToDouble(const char* source)
  301. {
  302. if(!source)
  303. {
  304. return 0.0;
  305. }
  306. return std::strtod(source, NULL);
  307. }
  308. #ifdef _WIN32
  309. Aws::WString StringUtils::ToWString(const char* source)
  310. {
  311. const auto len = static_cast<int>(std::strlen(source));
  312. Aws::WString outString;
  313. outString.resize(len); // there is no way UTF-16 would require _more_ code-points than UTF-8 for the _same_ string
  314. const auto result = MultiByteToWideChar(CP_UTF8 /*CodePage*/,
  315. 0 /*dwFlags*/,
  316. source /*lpMultiByteStr*/,
  317. len /*cbMultiByte*/,
  318. &outString[0] /*lpWideCharStr*/,
  319. static_cast<int>(outString.length())/*cchWideChar*/);
  320. if (!result)
  321. {
  322. return L"";
  323. }
  324. outString.resize(result);
  325. return outString;
  326. }
  327. Aws::String StringUtils::FromWString(const wchar_t* source)
  328. {
  329. const auto len = static_cast<int>(std::wcslen(source));
  330. Aws::String output;
  331. if (int requiredSizeInBytes = WideCharToMultiByte(CP_UTF8 /*CodePage*/,
  332. 0 /*dwFlags*/,
  333. source /*lpWideCharStr*/,
  334. len /*cchWideChar*/,
  335. nullptr /*lpMultiByteStr*/,
  336. 0 /*cbMultiByte*/,
  337. nullptr /*lpDefaultChar*/,
  338. nullptr /*lpUsedDefaultChar*/))
  339. {
  340. output.resize(requiredSizeInBytes);
  341. }
  342. const auto result = WideCharToMultiByte(CP_UTF8 /*CodePage*/,
  343. 0 /*dwFlags*/,
  344. source /*lpWideCharStr*/,
  345. len /*cchWideChar*/,
  346. &output[0] /*lpMultiByteStr*/,
  347. static_cast<int>(output.length()) /*cbMultiByte*/,
  348. nullptr /*lpDefaultChar*/,
  349. nullptr /*lpUsedDefaultChar*/);
  350. if (!result)
  351. {
  352. return "";
  353. }
  354. output.resize(result);
  355. return output;
  356. }
  357. #endif