You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

248 lines
5.3KB

  1. #include <string.hpp>
  2. #include <locale> // for wstring_convert
  3. #include <codecvt> // for codecvt_utf8_utf16
  4. #include <cctype> // for tolower and toupper
  5. #include <algorithm> // for transform
  6. #include <libgen.h> // for dirname and basename
  7. namespace rack {
  8. namespace string {
  9. std::string fromWstring(const std::wstring& s) {
  10. std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
  11. return converter.to_bytes(s);
  12. }
  13. std::wstring toWstring(const std::string& s) {
  14. std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
  15. return converter.from_bytes(s);
  16. }
  17. std::string f(const char* format, ...) {
  18. va_list args;
  19. va_start(args, format);
  20. // Compute size of required buffer
  21. int size = vsnprintf(NULL, 0, format, args);
  22. va_end(args);
  23. if (size < 0)
  24. return "";
  25. // Create buffer
  26. std::string s;
  27. s.resize(size);
  28. va_start(args, format);
  29. vsnprintf(&s[0], size + 1, format, args);
  30. va_end(args);
  31. return s;
  32. }
  33. std::string lowercase(const std::string& s) {
  34. std::string r = s;
  35. std::transform(r.begin(), r.end(), r.begin(), [](unsigned char c) {
  36. return std::tolower(c);
  37. });
  38. return r;
  39. }
  40. std::string uppercase(const std::string& s) {
  41. std::string r = s;
  42. std::transform(r.begin(), r.end(), r.begin(), [](unsigned char c) {
  43. return std::toupper(c);
  44. });
  45. return r;
  46. }
  47. std::string trim(const std::string& s) {
  48. const std::string whitespace = " \n\r\t";
  49. size_t first = s.find_first_not_of(whitespace);
  50. if (first == std::string::npos)
  51. return "";
  52. size_t last = s.find_last_not_of(whitespace);
  53. if (last == std::string::npos)
  54. return "";
  55. return s.substr(first, last - first + 1);
  56. }
  57. std::string ellipsize(const std::string& s, size_t len) {
  58. if (s.size() <= len)
  59. return s;
  60. else
  61. return s.substr(0, len - 3) + "...";
  62. }
  63. std::string ellipsizePrefix(const std::string& s, size_t len) {
  64. if (s.size() <= len)
  65. return s;
  66. else
  67. return "..." + s.substr(s.size() - (len - 3));
  68. }
  69. bool startsWith(const std::string& str, const std::string& prefix) {
  70. return str.substr(0, prefix.size()) == prefix;
  71. }
  72. bool endsWith(const std::string& str, const std::string& suffix) {
  73. return str.substr(str.size() - suffix.size(), suffix.size()) == suffix;
  74. }
  75. std::string directory(const std::string& path) {
  76. char* pathDup = strdup(path.c_str());
  77. std::string directory = dirname(pathDup);
  78. free(pathDup);
  79. return directory;
  80. }
  81. std::string filename(const std::string& path) {
  82. char* pathDup = strdup(path.c_str());
  83. std::string filename = basename(pathDup);
  84. free(pathDup);
  85. return filename;
  86. }
  87. std::string filenameBase(const std::string& filename) {
  88. size_t pos = filename.rfind('.');
  89. if (pos == std::string::npos)
  90. return filename;
  91. return std::string(filename, 0, pos);
  92. }
  93. std::string filenameExtension(const std::string& filename) {
  94. size_t pos = filename.rfind('.');
  95. if (pos == std::string::npos)
  96. return "";
  97. return std::string(filename, pos + 1);
  98. }
  99. std::string absolutePath(const std::string& path) {
  100. #if defined ARCH_LIN || defined ARCH_MAC
  101. char buf[PATH_MAX];
  102. char* absPathC = realpath(path.c_str(), buf);
  103. if (absPathC)
  104. return absPathC;
  105. #elif defined ARCH_WIN
  106. std::wstring pathW = toWstring(path);
  107. wchar_t buf[PATH_MAX];
  108. wchar_t* absPathC = _wfullpath(buf, pathW.c_str(), PATH_MAX);
  109. if (absPathC)
  110. return fromWstring(absPathC);
  111. #endif
  112. return "";
  113. }
  114. float fuzzyScore(const std::string& s, const std::string& query) {
  115. size_t pos = s.find(query);
  116. if (pos == std::string::npos)
  117. return 0.f;
  118. return (float)(query.size() + 1) / (s.size() + 1);
  119. }
  120. std::string toBase64(const uint8_t* data, size_t len) {
  121. static const char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  122. size_t numBlocks = size_t((len + 2) / 3);
  123. size_t strLen = numBlocks * 4;
  124. std::string str;
  125. str.reserve(strLen);
  126. for (size_t b = 0; b < numBlocks; b++) {
  127. // Encode block
  128. uint32_t block = 0;
  129. int i;
  130. for (i = 0; i < 3 && 3 * b + i < len; i++) {
  131. block |= uint32_t(data[3 * b + i]) << (8 * (2 - i));
  132. }
  133. // Decode block
  134. str += alphabet[(block >> 18) & 0x3f];
  135. str += alphabet[(block >> 12) & 0x3f];
  136. str += (i > 1) ? alphabet[(block >> 6) & 0x3f] : '=';
  137. str += (i > 2) ? alphabet[(block >> 0) & 0x3f] : '=';
  138. }
  139. return str;
  140. }
  141. uint8_t* fromBase64(const std::string& str, size_t* outLen) {
  142. size_t strLen = str.size();
  143. if (strLen % 4 != 0)
  144. return NULL;
  145. size_t numBlocks = strLen / 4;
  146. size_t len = numBlocks * 3;
  147. if (strLen >= 4) {
  148. if (str[strLen - 1] == '=')
  149. len--;
  150. if (str[strLen - 2] == '=')
  151. len--;
  152. }
  153. if (outLen)
  154. *outLen = len;
  155. uint8_t* data = new uint8_t[len];
  156. for (size_t b = 0; b < numBlocks; b++) {
  157. // Encode block
  158. uint32_t block = 0;
  159. size_t i;
  160. for (i = 0; i < 4; i++) {
  161. uint8_t c = str[4 * b + i];
  162. uint8_t d = 0;
  163. if ('A' <= c && c <= 'Z') {
  164. d = c - 'A';
  165. }
  166. else if ('a' <= c && c <= 'z') {
  167. d = c - 'a' + 26;
  168. }
  169. else if ('0' <= c && c <= '9') {
  170. d = c - '0' + 52;
  171. }
  172. else if (c == '+') {
  173. d = 62;
  174. }
  175. else if (c == '/') {
  176. d = 63;
  177. }
  178. else if (c == '=') {
  179. // Padding ends block encoding
  180. break;
  181. }
  182. else {
  183. // Ignore invalid characters, such as whitespace.
  184. continue;
  185. }
  186. block |= uint32_t(d) << (6 * (3 - i));
  187. }
  188. // Decode block
  189. for (size_t k = 0; k < i - 1; k++) {
  190. data[3 * b + k] = (block >> (8 * (2 - k))) & 0xff;
  191. }
  192. }
  193. return data;
  194. }
  195. } // namespace string
  196. } // namespace rack