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.

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