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.

517 lines
12KB

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