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.

923 lines
23KB

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