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.

872 lines
22KB

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