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.

858 lines
21KB

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