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.

833 lines
20KB

  1. /*
  2. * Carla String
  3. * Copyright (C) 2013-2014 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 doc/GPL.txt file.
  16. */
  17. #ifndef CARLA_STRING_HPP_INCLUDED
  18. #define CARLA_STRING_HPP_INCLUDED
  19. #include "CarlaJuceUtils.hpp"
  20. namespace std {
  21. #ifdef CARLA_OS_HAIKU
  22. using ::snprintf;
  23. #endif
  24. using ::ssize_t; // FIXME?
  25. }
  26. // -----------------------------------------------------------------------
  27. // CarlaString class
  28. class CarlaString
  29. {
  30. public:
  31. // -------------------------------------------------------------------
  32. // constructors (no explicit conversions allowed)
  33. /*
  34. * Empty string.
  35. */
  36. explicit CarlaString() noexcept
  37. {
  38. _init();
  39. }
  40. /*
  41. * Simple character.
  42. */
  43. explicit CarlaString(const char c) noexcept
  44. {
  45. char ch[2];
  46. ch[0] = c;
  47. ch[1] = '\0';
  48. _init();
  49. _dup(ch);
  50. }
  51. /*
  52. * Simple char string.
  53. */
  54. explicit CarlaString(char* const strBuf) noexcept
  55. {
  56. _init();
  57. _dup(strBuf);
  58. }
  59. /*
  60. * Simple const char string.
  61. */
  62. explicit CarlaString(const char* const strBuf) noexcept
  63. {
  64. _init();
  65. _dup(strBuf);
  66. }
  67. /*
  68. * Integer.
  69. */
  70. explicit CarlaString(const int value) noexcept
  71. {
  72. char strBuf[0xff+1];
  73. std::snprintf(strBuf, 0xff, "%d", value);
  74. strBuf[0xff] = '\0';
  75. _init();
  76. _dup(strBuf);
  77. }
  78. /*
  79. * Unsigned integer, possibly in hexadecimal.
  80. */
  81. explicit CarlaString(const unsigned int value, const bool hexadecimal = false) noexcept
  82. {
  83. char strBuf[0xff+1];
  84. std::snprintf(strBuf, 0xff, hexadecimal ? "0x%x" : "%u", value);
  85. strBuf[0xff] = '\0';
  86. _init();
  87. _dup(strBuf);
  88. }
  89. /*
  90. * Long integer.
  91. */
  92. explicit CarlaString(const long value) noexcept
  93. {
  94. char strBuf[0xff+1];
  95. std::snprintf(strBuf, 0xff, "%ld", value);
  96. strBuf[0xff] = '\0';
  97. _init();
  98. _dup(strBuf);
  99. }
  100. /*
  101. * Long unsigned integer, possibly hexadecimal.
  102. */
  103. explicit CarlaString(const unsigned long value, const bool hexadecimal = false) noexcept
  104. {
  105. char strBuf[0xff+1];
  106. std::snprintf(strBuf, 0xff, hexadecimal ? "0x%lx" : "%lu", value);
  107. strBuf[0xff] = '\0';
  108. _init();
  109. _dup(strBuf);
  110. }
  111. /*
  112. * Long long integer.
  113. */
  114. explicit CarlaString(const long long value) noexcept
  115. {
  116. char strBuf[0xff+1];
  117. std::snprintf(strBuf, 0xff, "%lld", value);
  118. strBuf[0xff] = '\0';
  119. _init();
  120. _dup(strBuf);
  121. }
  122. /*
  123. * Long long unsigned integer, possibly hexadecimal.
  124. */
  125. explicit CarlaString(const unsigned long long value, const bool hexadecimal = false) noexcept
  126. {
  127. char strBuf[0xff+1];
  128. std::snprintf(strBuf, 0xff, hexadecimal ? "0x%llx" : "%llu", value);
  129. strBuf[0xff] = '\0';
  130. _init();
  131. _dup(strBuf);
  132. }
  133. /*
  134. * Single-precision floating point number.
  135. */
  136. explicit CarlaString(const float value) noexcept
  137. {
  138. char strBuf[0xff+1];
  139. std::snprintf(strBuf, 0xff, "%f", value);
  140. strBuf[0xff] = '\0';
  141. _init();
  142. _dup(strBuf);
  143. }
  144. /*
  145. * Double-precision floating point number.
  146. */
  147. explicit CarlaString(const double value) noexcept
  148. {
  149. char strBuf[0xff+1];
  150. std::snprintf(strBuf, 0xff, "%g", value);
  151. strBuf[0xff] = '\0';
  152. _init();
  153. _dup(strBuf);
  154. }
  155. // -------------------------------------------------------------------
  156. // non-explicit constructor
  157. /*
  158. * Create string from another string.
  159. */
  160. CarlaString(const CarlaString& str) noexcept
  161. {
  162. _init();
  163. _dup(str.fBuffer);
  164. }
  165. // -------------------------------------------------------------------
  166. // destructor
  167. /*
  168. * Destructor.
  169. */
  170. ~CarlaString() noexcept
  171. {
  172. CARLA_SAFE_ASSERT_RETURN(fBuffer != nullptr,);
  173. if (fBuffer == _null())
  174. return;
  175. std::free(fBuffer);
  176. fBuffer = nullptr;
  177. fBufferLen = 0;
  178. }
  179. // -------------------------------------------------------------------
  180. // public methods
  181. /*
  182. * Get length of the string.
  183. */
  184. std::size_t length() const noexcept
  185. {
  186. return fBufferLen;
  187. }
  188. /*
  189. * Check if the string is empty.
  190. */
  191. bool isEmpty() const noexcept
  192. {
  193. return (fBufferLen == 0);
  194. }
  195. /*
  196. * Check if the string is not empty.
  197. */
  198. bool isNotEmpty() const noexcept
  199. {
  200. return (fBufferLen != 0);
  201. }
  202. /*
  203. * Check if the string contains another string, optionally ignoring case.
  204. */
  205. bool contains(const char* const strBuf, const bool ignoreCase = false) const noexcept
  206. {
  207. CARLA_SAFE_ASSERT_RETURN(strBuf != nullptr, false);
  208. if (ignoreCase)
  209. {
  210. #ifdef __USE_GNU
  211. return (strcasestr(fBuffer, strBuf) != nullptr);
  212. #else
  213. CarlaString tmp1(fBuffer), tmp2(strBuf);
  214. // memory allocation failed or empty string(s)
  215. if (tmp1.fBuffer == _null() || tmp2.fBuffer == _null())
  216. return false;
  217. tmp1.toLower();
  218. tmp2.toLower();
  219. return (std::strstr(tmp1, tmp2) != nullptr);
  220. #endif
  221. }
  222. return (std::strstr(fBuffer, strBuf) != nullptr);
  223. }
  224. /*
  225. * Check if character at 'pos' is a digit.
  226. */
  227. bool isDigit(const std::size_t pos) const noexcept
  228. {
  229. CARLA_SAFE_ASSERT_RETURN(pos < fBufferLen, false);
  230. return (fBuffer[pos] >= '0' && fBuffer[pos] <= '9');
  231. }
  232. /*
  233. * Check if the string starts with the character 'c'.
  234. */
  235. bool startsWith(const char c) const noexcept
  236. {
  237. CARLA_SAFE_ASSERT_RETURN(c != '\0', false);
  238. return (fBufferLen > 0 && fBuffer[0] == c);
  239. }
  240. /*
  241. * Check if the string starts with the string 'prefix'.
  242. */
  243. bool startsWith(const char* const prefix) const noexcept
  244. {
  245. CARLA_SAFE_ASSERT_RETURN(prefix != nullptr, false);
  246. const std::size_t prefixLen(std::strlen(prefix));
  247. if (fBufferLen < prefixLen)
  248. return false;
  249. return (std::strncmp(fBuffer, prefix, prefixLen) == 0);
  250. }
  251. /*
  252. * Check if the string ends with the character 'c'.
  253. */
  254. bool endsWith(const char c) const noexcept
  255. {
  256. CARLA_SAFE_ASSERT_RETURN(c != '\0', false);
  257. return (fBufferLen > 0 && fBuffer[fBufferLen-1] == c);
  258. }
  259. /*
  260. * Check if the string ends with the string 'suffix'.
  261. */
  262. bool endsWith(const char* const suffix) const noexcept
  263. {
  264. CARLA_SAFE_ASSERT_RETURN(suffix != nullptr, false);
  265. const std::size_t suffixLen(std::strlen(suffix));
  266. if (fBufferLen < suffixLen)
  267. return false;
  268. return (std::strncmp(fBuffer + (fBufferLen-suffixLen), suffix, suffixLen) == 0);
  269. }
  270. /*
  271. * Find the first occurrence of character 'c' in the string.
  272. * Returns "length()" if the character is not found.
  273. */
  274. std::size_t find(const char c, bool* const found = nullptr) const noexcept
  275. {
  276. if (fBufferLen == 0 || c == '\0')
  277. {
  278. if (found != nullptr)
  279. *found = false;
  280. return fBufferLen;
  281. }
  282. for (std::size_t i=0; i < fBufferLen; ++i)
  283. {
  284. if (fBuffer[i] == c)
  285. {
  286. if (found != nullptr)
  287. *found = true;
  288. return i;
  289. }
  290. }
  291. if (found != nullptr)
  292. *found = false;
  293. return fBufferLen;
  294. }
  295. /*
  296. * Find the first occurrence of string 'strBuf' in the string.
  297. * Returns "length()" if the string is not found.
  298. */
  299. std::size_t find(const char* const strBuf, bool* const found = nullptr) const noexcept
  300. {
  301. if (fBufferLen == 0 || strBuf == nullptr || strBuf[0] == '\0')
  302. {
  303. if (found != nullptr)
  304. *found = false;
  305. return fBufferLen;
  306. }
  307. if (char* const subStrBuf = std::strstr(fBuffer, strBuf))
  308. {
  309. const std::ssize_t ret(subStrBuf - fBuffer);
  310. if (ret < 0)
  311. {
  312. // should never happen!
  313. carla_safe_assert_int("ret >= 0", __FILE__, __LINE__, int(ret));
  314. if (found != nullptr)
  315. *found = false;
  316. return fBufferLen;
  317. }
  318. if (found != nullptr)
  319. *found = true;
  320. return static_cast<std::size_t>(ret);
  321. }
  322. if (found != nullptr)
  323. *found = false;
  324. return fBufferLen;
  325. }
  326. /*
  327. * Find the last occurrence of character 'c' in the string.
  328. * Returns "length()" if the character is not found.
  329. */
  330. std::size_t rfind(const char c, bool* const found = nullptr) const noexcept
  331. {
  332. if (fBufferLen == 0 || c == '\0')
  333. {
  334. if (found != nullptr)
  335. *found = false;
  336. return fBufferLen;
  337. }
  338. for (std::size_t i=fBufferLen; i > 0; --i)
  339. {
  340. if (fBuffer[i-1] == c)
  341. {
  342. if (found != nullptr)
  343. *found = true;
  344. return i-1;
  345. }
  346. }
  347. if (found != nullptr)
  348. *found = false;
  349. return fBufferLen;
  350. }
  351. /*
  352. * Find the last occurrence of string 'strBuf' in the string.
  353. * Returns "length()" if the string is not found.
  354. */
  355. std::size_t rfind(const char* const strBuf, bool* const found = nullptr) const noexcept
  356. {
  357. if (found != nullptr)
  358. *found = false;
  359. if (fBufferLen == 0 || strBuf == nullptr || strBuf[0] == '\0')
  360. return fBufferLen;
  361. const std::size_t strBufLen(std::strlen(strBuf));
  362. std::size_t ret = fBufferLen;
  363. const char* tmpBuf = fBuffer;
  364. for (std::size_t i=0; i < fBufferLen; ++i)
  365. {
  366. if (std::strstr(tmpBuf+1, strBuf) == nullptr && std::strncmp(tmpBuf, strBuf, strBufLen) == 0)
  367. {
  368. if (found != nullptr)
  369. *found = true;
  370. break;
  371. }
  372. --ret;
  373. ++tmpBuf;
  374. }
  375. return fBufferLen-ret;
  376. }
  377. /*
  378. * Clear the string.
  379. */
  380. void clear() noexcept
  381. {
  382. truncate(0);
  383. }
  384. /*
  385. * Replace all occurrences of character 'before' with character 'after'.
  386. */
  387. void replace(const char before, const char after) noexcept
  388. {
  389. CARLA_SAFE_ASSERT_RETURN(before != '\0' && after != '\0',);
  390. for (std::size_t i=0; i < fBufferLen; ++i)
  391. {
  392. if (fBuffer[i] == before)
  393. fBuffer[i] = after;
  394. }
  395. }
  396. /*
  397. * Truncate the string to size 'n'.
  398. */
  399. void truncate(const std::size_t n) noexcept
  400. {
  401. if (n >= fBufferLen)
  402. return;
  403. for (std::size_t i=n; i < fBufferLen; ++i)
  404. fBuffer[i] = '\0';
  405. fBufferLen = n;
  406. }
  407. /*
  408. * Convert all non-basic characters to '_'.
  409. */
  410. void toBasic() noexcept
  411. {
  412. for (std::size_t i=0; i < fBufferLen; ++i)
  413. {
  414. if (fBuffer[i] >= '0' && fBuffer[i] <= '9')
  415. continue;
  416. if (fBuffer[i] >= 'A' && fBuffer[i] <= 'Z')
  417. continue;
  418. if (fBuffer[i] >= 'a' && fBuffer[i] <= 'z')
  419. continue;
  420. if (fBuffer[i] == '_')
  421. continue;
  422. fBuffer[i] = '_';
  423. }
  424. }
  425. /*
  426. * Convert to all ascii characters to lowercase.
  427. */
  428. void toLower() noexcept
  429. {
  430. static const char kCharDiff('a' - 'A');
  431. for (std::size_t i=0; i < fBufferLen; ++i)
  432. {
  433. if (fBuffer[i] >= 'A' && fBuffer[i] <= 'Z')
  434. fBuffer[i] = static_cast<char>(fBuffer[i] + kCharDiff);
  435. }
  436. }
  437. /*
  438. * Convert to all ascii characters to uppercase.
  439. */
  440. void toUpper() noexcept
  441. {
  442. static const char kCharDiff('a' - 'A');
  443. for (std::size_t i=0; i < fBufferLen; ++i)
  444. {
  445. if (fBuffer[i] >= 'a' && fBuffer[i] <= 'z')
  446. fBuffer[i] = static_cast<char>(fBuffer[i] - kCharDiff);
  447. }
  448. }
  449. /*
  450. * Direct access to the string buffer (read-only).
  451. */
  452. const char* buffer() const noexcept
  453. {
  454. return fBuffer;
  455. }
  456. /*
  457. * Return a duplicate string buffer.
  458. * May throw.
  459. */
  460. const char* dup() const
  461. {
  462. return carla_strdup(fBuffer);
  463. }
  464. // -------------------------------------------------------------------
  465. // base64 stuff, based on http://www.adp-gmbh.ch/cpp/common/base64.html
  466. // Copyright (C) 2004-2008 René Nyffenegger
  467. static CarlaString asBase64(const void* const data, const std::size_t dataSize)
  468. {
  469. static const char* const kBase64Chars =
  470. "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  471. "abcdefghijklmnopqrstuvwxyz"
  472. "0123456789+/";
  473. const uchar* bytesToEncode((const uchar*)data);
  474. uint i=0, j=0;
  475. uint charArray3[3], charArray4[4];
  476. char strBuf[0xff+1];
  477. strBuf[0xff] = '\0';
  478. int strBufIndex = 0;
  479. CarlaString ret;
  480. for (std::size_t s=0; s<dataSize; ++s)
  481. {
  482. charArray3[i++] = *(bytesToEncode++);
  483. if (i == 3)
  484. {
  485. charArray4[0] = (charArray3[0] & 0xfc) >> 2;
  486. charArray4[1] = ((charArray3[0] & 0x03) << 4) + ((charArray3[1] & 0xf0) >> 4);
  487. charArray4[2] = ((charArray3[1] & 0x0f) << 2) + ((charArray3[2] & 0xc0) >> 6);
  488. charArray4[3] = charArray3[2] & 0x3f;
  489. for (i=0; i<4; ++i)
  490. strBuf[strBufIndex++] = kBase64Chars[charArray4[i]];
  491. if (strBufIndex >= 0xff-7)
  492. {
  493. strBuf[strBufIndex] = '\0';
  494. strBufIndex = 0;
  495. ret += strBuf;
  496. }
  497. i = 0;
  498. }
  499. }
  500. if (i != 0)
  501. {
  502. for (j=i; j<3; ++j)
  503. charArray3[j] = '\0';
  504. charArray4[0] = (charArray3[0] & 0xfc) >> 2;
  505. charArray4[1] = ((charArray3[0] & 0x03) << 4) + ((charArray3[1] & 0xf0) >> 4);
  506. charArray4[2] = ((charArray3[1] & 0x0f) << 2) + ((charArray3[2] & 0xc0) >> 6);
  507. charArray4[3] = charArray3[2] & 0x3f;
  508. for (j=0; j<4 && i<3 && j<i+1; ++j)
  509. strBuf[strBufIndex++] = kBase64Chars[charArray4[j]];
  510. for (; i++ < 3;)
  511. strBuf[strBufIndex++] = '=';
  512. strBuf[strBufIndex] = '\0';
  513. ret += strBuf;
  514. }
  515. return ret;
  516. }
  517. // -------------------------------------------------------------------
  518. // public operators
  519. operator const char*() const noexcept
  520. {
  521. return fBuffer;
  522. }
  523. char operator[](const std::size_t pos) const noexcept
  524. {
  525. if (pos < fBufferLen)
  526. return fBuffer[pos];
  527. carla_safe_assert("pos < fBufferLen", __FILE__, __LINE__);
  528. static char fallback;
  529. fallback = '\0';
  530. return fallback;
  531. }
  532. char& operator[](const std::size_t pos) noexcept
  533. {
  534. if (pos < fBufferLen)
  535. return fBuffer[pos];
  536. carla_safe_assert("pos < fBufferLen", __FILE__, __LINE__);
  537. static char fallback;
  538. fallback = '\0';
  539. return fallback;
  540. }
  541. bool operator==(const char* const strBuf) const noexcept
  542. {
  543. return (strBuf != nullptr && std::strcmp(fBuffer, strBuf) == 0);
  544. }
  545. bool operator==(const CarlaString& str) const noexcept
  546. {
  547. return operator==(str.fBuffer);
  548. }
  549. bool operator!=(const char* const strBuf) const noexcept
  550. {
  551. return !operator==(strBuf);
  552. }
  553. bool operator!=(const CarlaString& str) const noexcept
  554. {
  555. return !operator==(str.fBuffer);
  556. }
  557. CarlaString& operator=(const char* const strBuf) noexcept
  558. {
  559. _dup(strBuf);
  560. return *this;
  561. }
  562. CarlaString& operator=(const CarlaString& str) noexcept
  563. {
  564. _dup(str.fBuffer);
  565. return *this;
  566. }
  567. CarlaString& operator+=(const char* const strBuf) noexcept
  568. {
  569. if (strBuf == nullptr)
  570. return *this;
  571. const std::size_t newBufSize = fBufferLen + std::strlen(strBuf) + 1;
  572. char newBuf[newBufSize];
  573. std::strcpy(newBuf, fBuffer);
  574. std::strcat(newBuf, strBuf);
  575. _dup(newBuf, newBufSize-1);
  576. return *this;
  577. }
  578. CarlaString& operator+=(const CarlaString& str) noexcept
  579. {
  580. return operator+=(str.fBuffer);
  581. }
  582. CarlaString operator+(const char* const strBuf) noexcept
  583. {
  584. const std::size_t newBufSize = fBufferLen + ((strBuf != nullptr) ? std::strlen(strBuf) : 0) + 1;
  585. char newBuf[newBufSize];
  586. std::strcpy(newBuf, fBuffer);
  587. if (strBuf != nullptr)
  588. std::strcat(newBuf, strBuf);
  589. return CarlaString(newBuf);
  590. }
  591. CarlaString operator+(const CarlaString& str) noexcept
  592. {
  593. return operator+(str.fBuffer);
  594. }
  595. // -------------------------------------------------------------------
  596. private:
  597. char* fBuffer; // the actual string buffer
  598. std::size_t fBufferLen; // string length
  599. /*
  600. * Static null string.
  601. * Prevents allocation for new and/or empty strings.
  602. */
  603. static char* _null() noexcept
  604. {
  605. static char sNull = '\0';
  606. return &sNull;
  607. }
  608. /*
  609. * Shared init function.
  610. * Called on all constructors.
  611. */
  612. void _init() noexcept
  613. {
  614. fBuffer = _null();
  615. fBufferLen = 0;
  616. }
  617. /*
  618. * Helper function.
  619. * Called whenever the string needs to be allocated.
  620. *
  621. * Notes:
  622. * - Allocates string only if 'strBuf' is not null and new string contents are different
  623. * - If 'strBuf' is null, 'size' must be 0
  624. */
  625. void _dup(const char* const strBuf, const std::size_t size = 0) noexcept
  626. {
  627. if (strBuf != nullptr)
  628. {
  629. // don't recreate string if contents match
  630. if (std::strcmp(fBuffer, strBuf) == 0)
  631. return;
  632. if (fBuffer != _null())
  633. std::free(fBuffer);
  634. fBufferLen = (size > 0) ? size : std::strlen(strBuf);
  635. fBuffer = (char*)std::malloc(fBufferLen+1);
  636. if (fBuffer == nullptr)
  637. return _init();
  638. std::strcpy(fBuffer, strBuf);
  639. fBuffer[fBufferLen] = '\0';
  640. }
  641. else
  642. {
  643. CARLA_SAFE_ASSERT(size == 0);
  644. // don't recreate null string
  645. if (fBuffer == _null())
  646. return;
  647. CARLA_SAFE_ASSERT(fBuffer != nullptr);
  648. std::free(fBuffer);
  649. _init();
  650. }
  651. }
  652. CARLA_PREVENT_HEAP_ALLOCATION
  653. };
  654. // -----------------------------------------------------------------------
  655. static inline
  656. CarlaString operator+(const CarlaString& strBefore, const char* const strBufAfter) noexcept
  657. {
  658. const char* const strBufBefore = strBefore.buffer();
  659. const std::size_t newBufSize = strBefore.length() + ((strBufAfter != nullptr) ? std::strlen(strBufAfter) : 0) + 1;
  660. char newBuf[newBufSize];
  661. std::strcpy(newBuf, strBufBefore);
  662. std::strcat(newBuf, strBufAfter);
  663. return CarlaString(newBuf);
  664. }
  665. static inline
  666. CarlaString operator+(const char* const strBufBefore, const CarlaString& strAfter) noexcept
  667. {
  668. const char* const strBufAfter = strAfter.buffer();
  669. const std::size_t newBufSize = ((strBufBefore != nullptr) ? std::strlen(strBufBefore) : 0) + strAfter.length() + 1;
  670. char newBuf[newBufSize];
  671. std::strcpy(newBuf, strBufBefore);
  672. std::strcat(newBuf, strBufAfter);
  673. return CarlaString(newBuf);
  674. }
  675. // -----------------------------------------------------------------------
  676. #endif // CARLA_STRING_HPP_INCLUDED