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.

896 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. * Release the buffer pointer while clearing this string.
  504. * This allows to keep a pointer to the buffer after this object is deleted.
  505. */
  506. char* releaseBufferPointer() noexcept
  507. {
  508. char* ret = fBufferLen > 0 ? fBuffer : nullptr;
  509. fBuffer = _null();
  510. fBufferLen = 0;
  511. fBufferAlloc = false;
  512. return ret;
  513. }
  514. // -------------------------------------------------------------------
  515. // base64 stuff, based on http://www.adp-gmbh.ch/cpp/common/base64.html
  516. // Copyright (C) 2004-2008 René Nyffenegger
  517. static CarlaString asBase64(const void* const data, const std::size_t dataSize)
  518. {
  519. static const char* const kBase64Chars =
  520. "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  521. "abcdefghijklmnopqrstuvwxyz"
  522. "0123456789+/";
  523. const std::size_t kTmpBufSize = std::min(carla_nextPowerOf2(static_cast<uint32_t>(dataSize/3)), 65536U);
  524. const uchar* bytesToEncode((const uchar*)data);
  525. uint i=0, j=0;
  526. uint charArray3[3], charArray4[4];
  527. char strBuf[kTmpBufSize+1];
  528. strBuf[kTmpBufSize] = '\0';
  529. std::size_t strBufIndex = 0;
  530. CarlaString ret;
  531. for (std::size_t s=0; s<dataSize; ++s)
  532. {
  533. charArray3[i++] = *(bytesToEncode++);
  534. if (i == 3)
  535. {
  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 (i=0; i<4; ++i)
  541. strBuf[strBufIndex++] = kBase64Chars[charArray4[i]];
  542. if (strBufIndex >= kTmpBufSize-7)
  543. {
  544. strBuf[strBufIndex] = '\0';
  545. strBufIndex = 0;
  546. ret += strBuf;
  547. }
  548. i = 0;
  549. }
  550. }
  551. if (i != 0)
  552. {
  553. for (j=i; j<3; ++j)
  554. charArray3[j] = '\0';
  555. charArray4[0] = (charArray3[0] & 0xfc) >> 2;
  556. charArray4[1] = ((charArray3[0] & 0x03) << 4) + ((charArray3[1] & 0xf0) >> 4);
  557. charArray4[2] = ((charArray3[1] & 0x0f) << 2) + ((charArray3[2] & 0xc0) >> 6);
  558. charArray4[3] = charArray3[2] & 0x3f;
  559. for (j=0; j<4 && i<3 && j<i+1; ++j)
  560. strBuf[strBufIndex++] = kBase64Chars[charArray4[j]];
  561. for (; i++ < 3;)
  562. strBuf[strBufIndex++] = '=';
  563. }
  564. if (strBufIndex != 0)
  565. {
  566. strBuf[strBufIndex] = '\0';
  567. ret += strBuf;
  568. }
  569. return ret;
  570. }
  571. // -------------------------------------------------------------------
  572. // public operators
  573. operator const char*() const noexcept
  574. {
  575. return fBuffer;
  576. }
  577. char operator[](const std::size_t pos) const noexcept
  578. {
  579. if (pos < fBufferLen)
  580. return fBuffer[pos];
  581. carla_safe_assert("pos < fBufferLen", __FILE__, __LINE__);
  582. static char fallback;
  583. fallback = '\0';
  584. return fallback;
  585. }
  586. char& operator[](const std::size_t pos) noexcept
  587. {
  588. if (pos < fBufferLen)
  589. return fBuffer[pos];
  590. carla_safe_assert("pos < fBufferLen", __FILE__, __LINE__);
  591. static char fallback;
  592. fallback = '\0';
  593. return fallback;
  594. }
  595. bool operator==(const char* const strBuf) const noexcept
  596. {
  597. return (strBuf != nullptr && std::strcmp(fBuffer, strBuf) == 0);
  598. }
  599. bool operator==(const CarlaString& str) const noexcept
  600. {
  601. return operator==(str.fBuffer);
  602. }
  603. bool operator!=(const char* const strBuf) const noexcept
  604. {
  605. return !operator==(strBuf);
  606. }
  607. bool operator!=(const CarlaString& str) const noexcept
  608. {
  609. return !operator==(str.fBuffer);
  610. }
  611. CarlaString& operator=(const char* const strBuf) noexcept
  612. {
  613. _dup(strBuf);
  614. return *this;
  615. }
  616. CarlaString& operator=(const CarlaString& str) noexcept
  617. {
  618. _dup(str.fBuffer);
  619. return *this;
  620. }
  621. CarlaString& operator+=(const char* const strBuf) noexcept
  622. {
  623. if (strBuf == nullptr)
  624. return *this;
  625. const std::size_t newBufSize = fBufferLen + std::strlen(strBuf) + 1;
  626. char newBuf[newBufSize];
  627. std::strcpy(newBuf, fBuffer);
  628. std::strcat(newBuf, strBuf);
  629. _dup(newBuf, newBufSize-1);
  630. return *this;
  631. }
  632. CarlaString& operator+=(const CarlaString& str) noexcept
  633. {
  634. return operator+=(str.fBuffer);
  635. }
  636. CarlaString operator+(const char* const strBuf) noexcept
  637. {
  638. const std::size_t newBufSize = fBufferLen + ((strBuf != nullptr) ? std::strlen(strBuf) : 0) + 1;
  639. char newBuf[newBufSize];
  640. std::strcpy(newBuf, fBuffer);
  641. if (strBuf != nullptr)
  642. std::strcat(newBuf, strBuf);
  643. return CarlaString(newBuf);
  644. }
  645. CarlaString operator+(const CarlaString& str) noexcept
  646. {
  647. return operator+(str.fBuffer);
  648. }
  649. // -------------------------------------------------------------------
  650. private:
  651. char* fBuffer; // the actual string buffer
  652. std::size_t fBufferLen; // string length
  653. bool fBufferAlloc; // wherever the buffer is allocated, not using _null()
  654. /*
  655. * Static null string.
  656. * Prevents allocation for new and/or empty strings.
  657. */
  658. static char* _null() noexcept
  659. {
  660. static char sNull = '\0';
  661. return &sNull;
  662. }
  663. /*
  664. * Helper function.
  665. * Called whenever the string needs to be allocated.
  666. *
  667. * Notes:
  668. * - Allocates string only if 'strBuf' is not null and new string contents are different
  669. * - If 'strBuf' is null, 'size' must be 0
  670. */
  671. void _dup(const char* const strBuf, const std::size_t size = 0) noexcept
  672. {
  673. if (strBuf != nullptr)
  674. {
  675. // don't recreate string if contents match
  676. if (std::strcmp(fBuffer, strBuf) == 0)
  677. return;
  678. if (fBufferAlloc)
  679. std::free(fBuffer);
  680. fBufferLen = (size > 0) ? size : std::strlen(strBuf);
  681. fBuffer = (char*)std::malloc(fBufferLen+1);
  682. if (fBuffer == nullptr)
  683. {
  684. fBuffer = _null();
  685. fBufferLen = 0;
  686. fBufferAlloc = false;
  687. return;
  688. }
  689. fBufferAlloc = true;
  690. std::strcpy(fBuffer, strBuf);
  691. fBuffer[fBufferLen] = '\0';
  692. }
  693. else
  694. {
  695. CARLA_SAFE_ASSERT_UINT(size == 0, static_cast<uint>(size));
  696. // don't recreate null string
  697. if (! fBufferAlloc)
  698. return;
  699. CARLA_SAFE_ASSERT(fBuffer != nullptr);
  700. std::free(fBuffer);
  701. fBuffer = _null();
  702. fBufferLen = 0;
  703. fBufferAlloc = false;
  704. }
  705. }
  706. CARLA_PREVENT_HEAP_ALLOCATION
  707. };
  708. // -----------------------------------------------------------------------
  709. static inline
  710. CarlaString operator+(const CarlaString& strBefore, const char* const strBufAfter) noexcept
  711. {
  712. const char* const strBufBefore = strBefore.buffer();
  713. const std::size_t newBufSize = strBefore.length() + ((strBufAfter != nullptr) ? std::strlen(strBufAfter) : 0) + 1;
  714. char newBuf[newBufSize];
  715. std::strcpy(newBuf, strBufBefore);
  716. std::strcat(newBuf, strBufAfter);
  717. return CarlaString(newBuf);
  718. }
  719. static inline
  720. CarlaString operator+(const char* const strBufBefore, const CarlaString& strAfter) noexcept
  721. {
  722. const char* const strBufAfter = strAfter.buffer();
  723. const std::size_t newBufSize = ((strBufBefore != nullptr) ? std::strlen(strBufBefore) : 0) + strAfter.length() + 1;
  724. char newBuf[newBufSize];
  725. std::strcpy(newBuf, strBufBefore);
  726. std::strcat(newBuf, strBufAfter);
  727. return CarlaString(newBuf);
  728. }
  729. // -----------------------------------------------------------------------
  730. #endif // CARLA_STRING_HPP_INCLUDED