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.

string.cpp 6.4KB

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