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.

883 lines
22KB

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