Audio plugin host https://kx.studio/carla
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.

521 lines
12KB

  1. /*
  2. * Carla common utils
  3. * Copyright (C) 2011-2013 Filipe Coelho <falktx@falktx.com>
  4. *
  5. * This program is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU General Public License as
  7. * published by the Free Software Foundation; either version 2 of
  8. * the License, or any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * For a full copy of the GNU General Public License see the GPL.txt file
  16. */
  17. #ifndef __CARLA_STRING_HPP__
  18. #define __CARLA_STRING_HPP__
  19. #include "CarlaBase64Utils.hpp"
  20. #include "CarlaJuceUtils.hpp"
  21. // -------------------------------------------------
  22. // CarlaString class
  23. class CarlaString
  24. {
  25. public:
  26. // ---------------------------------------------
  27. // constructors (no explicit conversions allowed)
  28. explicit CarlaString()
  29. {
  30. _init();
  31. _dup(nullptr);
  32. }
  33. explicit CarlaString(char* const strBuf)
  34. {
  35. _init();
  36. _dup(strBuf);
  37. }
  38. explicit CarlaString(const char* const strBuf)
  39. {
  40. _init();
  41. _dup(strBuf);
  42. }
  43. explicit CarlaString(const int value)
  44. {
  45. const size_t strBufSize = static_cast<size_t>(std::abs(value/10) + 3);
  46. char strBuf[strBufSize];
  47. std::snprintf(strBuf, strBufSize, "%d", value);
  48. _init();
  49. _dup(strBuf, strBufSize);
  50. }
  51. explicit CarlaString(const unsigned int value, const bool hexadecimal = false)
  52. {
  53. const size_t strBufSize = value/10 + 2 + (hexadecimal ? 2 : 0);
  54. char strBuf[strBufSize];
  55. std::snprintf(strBuf, strBufSize, hexadecimal ? "0x%x" : "%u", value);
  56. _init();
  57. _dup(strBuf, strBufSize);
  58. }
  59. explicit CarlaString(const long int value)
  60. {
  61. const size_t strBufSize = static_cast<size_t>(std::abs(value/10) + 3);
  62. char strBuf[strBufSize];
  63. std::snprintf(strBuf, strBufSize, "%ld", value);
  64. _init();
  65. _dup(strBuf, strBufSize);
  66. }
  67. explicit CarlaString(const unsigned long int value, const bool hexadecimal = false)
  68. {
  69. const size_t strBufSize = value/10 + 2 + (hexadecimal ? 2 : 0);
  70. char strBuf[strBufSize];
  71. std::snprintf(strBuf, strBufSize, hexadecimal ? "0x%lx" : "%lu", value);
  72. _init();
  73. _dup(strBuf, strBufSize);
  74. }
  75. explicit CarlaString(const float value)
  76. {
  77. char strBuf[0xff];
  78. std::snprintf(strBuf, 0xff, "%f", value);
  79. _init();
  80. _dup(strBuf);
  81. }
  82. explicit CarlaString(const double value)
  83. {
  84. char strBuf[0xff];
  85. std::snprintf(strBuf, 0xff, "%g", value);
  86. _init();
  87. _dup(strBuf);
  88. }
  89. // ---------------------------------------------
  90. // non-explicit constructor
  91. CarlaString(const CarlaString& str)
  92. {
  93. _init();
  94. _dup(str.buffer);
  95. }
  96. // ---------------------------------------------
  97. // deconstructor
  98. ~CarlaString()
  99. {
  100. CARLA_ASSERT(buffer != nullptr);
  101. delete[] buffer;
  102. }
  103. // ---------------------------------------------
  104. // public methods
  105. size_t length() const
  106. {
  107. return bufferLen;
  108. }
  109. bool isEmpty() const
  110. {
  111. return (bufferLen == 0);
  112. }
  113. bool isNotEmpty() const
  114. {
  115. return (bufferLen != 0);
  116. }
  117. #if __USE_GNU
  118. bool contains(const char* const strBuf, const bool ignoreCase = false) const
  119. {
  120. if (strBuf == nullptr)
  121. return false;
  122. if (ignoreCase)
  123. return (strcasestr(buffer, strBuf) != nullptr);
  124. else
  125. return (std::strstr(buffer, strBuf) != nullptr);
  126. }
  127. bool contains(const CarlaString& str, const bool ignoreCase = false) const
  128. {
  129. return contains(str.buffer, ignoreCase);
  130. }
  131. #else
  132. bool contains(const char* const strBuf) const
  133. {
  134. if (strBuf == nullptr)
  135. return false;
  136. return (std::strstr(buffer, strBuf) != nullptr);
  137. }
  138. bool contains(const CarlaString& str) const
  139. {
  140. return contains(str.buffer);
  141. }
  142. #endif
  143. bool isDigit(const size_t pos) const
  144. {
  145. if (pos >= bufferLen)
  146. return false;
  147. return (buffer[pos] >= '0' && buffer[pos] <= '9');
  148. }
  149. void clear()
  150. {
  151. truncate(0);
  152. }
  153. size_t find(const char c)
  154. {
  155. for (size_t i=0; i < bufferLen; i++)
  156. {
  157. if (buffer[i] == c)
  158. return i;
  159. }
  160. return 0;
  161. }
  162. size_t rfind(const char c)
  163. {
  164. size_t pos = 0;
  165. for (size_t i=0; i < bufferLen; i++)
  166. {
  167. if (buffer[i] == c)
  168. pos = i;
  169. }
  170. return pos;
  171. }
  172. void replace(const char before, const char after)
  173. {
  174. if (after == '\0')
  175. return;
  176. for (size_t i=0; i < bufferLen; i++)
  177. {
  178. if (buffer[i] == before)
  179. buffer[i] = after;
  180. else if (buffer[i] == '\0')
  181. break;
  182. }
  183. }
  184. void truncate(const size_t n)
  185. {
  186. if (n >= bufferLen)
  187. return;
  188. for (size_t i=n; i < bufferLen; i++)
  189. buffer[i] = '\0';
  190. bufferLen = n;
  191. }
  192. void toBasic()
  193. {
  194. for (size_t i=0; i < bufferLen; i++)
  195. {
  196. if (buffer[i] >= '0' && buffer[i] <= '9')
  197. continue;
  198. if (buffer[i] >= 'A' && buffer[i] <= 'Z')
  199. continue;
  200. if (buffer[i] >= 'a' && buffer[i] <= 'z')
  201. continue;
  202. if (buffer[i] == '_')
  203. continue;
  204. buffer[i] = '_';
  205. }
  206. }
  207. void toLower()
  208. {
  209. static const char charDiff = 'a' - 'A';
  210. for (size_t i=0; i < bufferLen; i++)
  211. {
  212. if (buffer[i] >= 'A' && buffer[i] <= 'Z')
  213. buffer[i] += charDiff;
  214. }
  215. }
  216. void toUpper()
  217. {
  218. static const char charDiff = 'a' - 'A';
  219. for (size_t i=0; i < bufferLen; i++)
  220. {
  221. if (buffer[i] >= 'a' && buffer[i] <= 'z')
  222. buffer[i] -= charDiff;
  223. }
  224. }
  225. void toBase64()
  226. {
  227. importBinaryAsBase64((const uint8_t*)buffer, bufferLen);
  228. }
  229. void fromBase64()
  230. {
  231. uint8_t buffer2[carla_base64_decoded_max_len(buffer)];
  232. if (unsigned int len = carla_base64_decode(buffer, buffer2))
  233. {
  234. char bufDecoded[len+1];
  235. std::strncpy(bufDecoded, (char*)buffer2, len);
  236. bufDecoded[len] = '\0';
  237. _dup(bufDecoded, len);
  238. }
  239. else
  240. clear();
  241. }
  242. void importBinaryAsBase64(const uint8_t* const raw, const size_t rawLen)
  243. {
  244. const size_t rawBufferSize = carla_base64_encoded_len(rawLen);
  245. char rawBuffer[rawBufferSize+1];
  246. carla_base64_encode(raw, rawLen, rawBuffer);
  247. _dup(rawBuffer, rawBufferSize);
  248. }
  249. template<typename T>
  250. void importBinaryAsBase64(const T* const t)
  251. {
  252. importBinaryAsBase64((const uint8_t*)t, sizeof(T));
  253. }
  254. size_t exportAsBase64Binary(uint8_t** const rawPtr)
  255. {
  256. uint8_t binaryBuffer[carla_base64_decoded_max_len(buffer)];
  257. if (unsigned int len = carla_base64_decode(buffer, binaryBuffer))
  258. {
  259. uint8_t* const binaryBufferHeap = new uint8_t[len];
  260. carla_copy<uint8_t>(binaryBufferHeap, binaryBuffer, len);
  261. *rawPtr = binaryBufferHeap;
  262. return len;
  263. }
  264. *rawPtr = nullptr;
  265. return 0;
  266. }
  267. template<typename T>
  268. T* exportAsBase64Binary()
  269. {
  270. uint8_t binaryBuffer[carla_base64_decoded_max_len(buffer)];
  271. if (unsigned int len = carla_base64_decode(buffer, binaryBuffer))
  272. {
  273. CARLA_ASSERT_INT2(len == sizeof(T), len, sizeof(T));
  274. T* const t = new T();
  275. std::memcpy(t, binaryBuffer, sizeof(T));
  276. return t;
  277. }
  278. return nullptr;
  279. }
  280. // ---------------------------------------------
  281. // public operators
  282. operator const char*() const
  283. {
  284. return buffer;
  285. }
  286. char& operator[](const size_t pos)
  287. {
  288. return buffer[pos];
  289. }
  290. bool operator==(const char* const strBuf) const
  291. {
  292. return (strBuf != nullptr && std::strcmp(buffer, strBuf) == 0);
  293. }
  294. bool operator==(const CarlaString& str) const
  295. {
  296. return operator==(str.buffer);
  297. }
  298. bool operator!=(const char* const strBuf) const
  299. {
  300. return !operator==(strBuf);
  301. }
  302. bool operator!=(const CarlaString& str) const
  303. {
  304. return !operator==(str.buffer);
  305. }
  306. CarlaString& operator=(const char* const strBuf)
  307. {
  308. _dup(strBuf);
  309. return *this;
  310. }
  311. CarlaString& operator=(const CarlaString& str)
  312. {
  313. return operator=(str.buffer);
  314. }
  315. CarlaString& operator+=(const char* const strBuf)
  316. {
  317. const size_t newBufSize = bufferLen + ((strBuf != nullptr) ? std::strlen(strBuf) : 0) + 1;
  318. char newBuf[newBufSize];
  319. std::strcpy(newBuf, buffer);
  320. std::strcat(newBuf, strBuf);
  321. _dup(newBuf, newBufSize-1);
  322. return *this;
  323. }
  324. CarlaString& operator+=(const CarlaString& str)
  325. {
  326. return operator+=(str.buffer);
  327. }
  328. CarlaString operator+(const char* const strBuf)
  329. {
  330. const size_t newBufSize = bufferLen + ((strBuf != nullptr) ? std::strlen(strBuf) : 0) + 1;
  331. char newBuf[newBufSize];
  332. std::strcpy(newBuf, buffer);
  333. std::strcat(newBuf, strBuf);
  334. return CarlaString(newBuf);
  335. }
  336. CarlaString operator+(const CarlaString& str)
  337. {
  338. return operator+(str.buffer);
  339. }
  340. // ---------------------------------------------
  341. private:
  342. char* buffer;
  343. size_t bufferLen;
  344. bool firstInit;
  345. void _init()
  346. {
  347. buffer = nullptr;
  348. bufferLen = 0;
  349. firstInit = true;
  350. }
  351. // allocate string strBuf if not null
  352. // size > 0 only if strBuf is valid
  353. void _dup(const char* const strBuf, const size_t size = 0)
  354. {
  355. if (strBuf != nullptr)
  356. {
  357. // don't recreate string if contents match
  358. if (firstInit || std::strcmp(buffer, strBuf) != 0)
  359. {
  360. if (! firstInit)
  361. {
  362. CARLA_ASSERT(buffer != nullptr);
  363. delete[] buffer;
  364. }
  365. bufferLen = (size > 0) ? size : std::strlen(strBuf);
  366. buffer = new char[bufferLen+1];
  367. std::strcpy(buffer, strBuf);
  368. buffer[bufferLen] = '\0';
  369. firstInit = false;
  370. }
  371. }
  372. else
  373. {
  374. CARLA_ASSERT(size == 0);
  375. // don't recreate null string
  376. if (firstInit || bufferLen != 0)
  377. {
  378. if (! firstInit)
  379. {
  380. CARLA_ASSERT(buffer != nullptr);
  381. delete[] buffer;
  382. }
  383. bufferLen = 0;
  384. buffer = new char[1];
  385. buffer[0] = '\0';
  386. firstInit = false;
  387. }
  388. }
  389. }
  390. CARLA_LEAK_DETECTOR(CarlaString)
  391. CARLA_PREVENT_HEAP_ALLOCATION
  392. };
  393. static inline
  394. CarlaString operator+(const CarlaString& strBefore, const char* const strBufAfter)
  395. {
  396. const char* const strBufBefore = (const char*)strBefore;
  397. const size_t newBufSize = strBefore.length() + ((strBufAfter != nullptr) ? std::strlen(strBufAfter) : 0) + 1;
  398. char newBuf[newBufSize];
  399. std::strcpy(newBuf, strBufBefore);
  400. std::strcat(newBuf, strBufAfter);
  401. return CarlaString(newBuf);
  402. }
  403. static inline
  404. CarlaString operator+(const char* const strBufBefore, const CarlaString& strAfter)
  405. {
  406. const char* const strBufAfter = (const char*)strAfter;
  407. const size_t newBufSize = ((strBufBefore != nullptr) ? std::strlen(strBufBefore) : 0) + strAfter.length() + 1;
  408. char newBuf[newBufSize];
  409. std::strcpy(newBuf, strBufBefore);
  410. std::strcat(newBuf, strBufAfter);
  411. return CarlaString(newBuf);
  412. }
  413. // -------------------------------------------------
  414. #endif // __CARLA_UTILS_HPP__