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.

924 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(fBufferAlloc ? fBuffer : nullptr, 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. fBufferAlloc = true;
  631. return *this;
  632. }
  633. CarlaString& operator+=(const CarlaString& str) noexcept
  634. {
  635. return operator+=(str.fBuffer);
  636. }
  637. CarlaString operator+(const char* const strBuf) noexcept
  638. {
  639. if (strBuf == nullptr || strBuf[0] == '\0')
  640. return *this;
  641. if (isEmpty())
  642. return CarlaString(strBuf);
  643. const std::size_t strBufLen = std::strlen(strBuf);
  644. const std::size_t newBufSize = fBufferLen + strBufLen;
  645. char* const newBuf = (char*)std::malloc(newBufSize + 1);
  646. CARLA_SAFE_ASSERT_RETURN(newBuf != nullptr, CarlaString());
  647. std::memcpy(newBuf, fBuffer, fBufferLen);
  648. std::memcpy(newBuf + fBufferLen, strBuf, strBufLen + 1);
  649. return CarlaString(newBuf, false);
  650. }
  651. CarlaString operator+(const CarlaString& str) noexcept
  652. {
  653. return operator+(str.fBuffer);
  654. }
  655. // needed for std::map compatibility
  656. bool operator<(const CarlaString& str) const noexcept
  657. {
  658. return std::strcmp(fBuffer, str.fBuffer) < 0;
  659. }
  660. // -------------------------------------------------------------------
  661. private:
  662. char* fBuffer; // the actual string buffer
  663. std::size_t fBufferLen; // string length
  664. bool fBufferAlloc; // wherever the buffer is allocated, not using _null()
  665. /*
  666. * Static null string.
  667. * Prevents allocation for new and/or empty strings.
  668. */
  669. static char* _null() noexcept
  670. {
  671. static char sNull = '\0';
  672. return &sNull;
  673. }
  674. /*
  675. * Helper function.
  676. * Called whenever the string needs to be allocated.
  677. *
  678. * Notes:
  679. * - Allocates string only if 'strBuf' is not null and new string contents are different
  680. * - If 'strBuf' is null, 'size' must be 0
  681. */
  682. void _dup(const char* const strBuf, const std::size_t size = 0) noexcept
  683. {
  684. if (strBuf != nullptr)
  685. {
  686. // don't recreate string if contents match
  687. if (std::strcmp(fBuffer, strBuf) == 0)
  688. return;
  689. if (fBufferAlloc)
  690. std::free(fBuffer);
  691. fBufferLen = (size > 0) ? size : std::strlen(strBuf);
  692. fBuffer = (char*)std::malloc(fBufferLen+1);
  693. if (fBuffer == nullptr)
  694. {
  695. fBuffer = _null();
  696. fBufferLen = 0;
  697. fBufferAlloc = false;
  698. return;
  699. }
  700. fBufferAlloc = true;
  701. std::strcpy(fBuffer, strBuf);
  702. fBuffer[fBufferLen] = '\0';
  703. }
  704. else
  705. {
  706. CARLA_SAFE_ASSERT_UINT(size == 0, static_cast<uint>(size));
  707. // don't recreate null string
  708. if (! fBufferAlloc)
  709. return;
  710. CARLA_SAFE_ASSERT(fBuffer != nullptr);
  711. std::free(fBuffer);
  712. fBuffer = _null();
  713. fBufferLen = 0;
  714. fBufferAlloc = false;
  715. }
  716. }
  717. CARLA_PREVENT_HEAP_ALLOCATION
  718. };
  719. // -----------------------------------------------------------------------
  720. static inline
  721. CarlaString operator+(const CarlaString& strBefore, const char* const strBufAfter) noexcept
  722. {
  723. if (strBufAfter == nullptr || strBufAfter[0] == '\0')
  724. return strBefore;
  725. if (strBefore.isEmpty())
  726. return CarlaString(strBufAfter);
  727. const std::size_t strBeforeLen = strBefore.length();
  728. const std::size_t strBufAfterLen = std::strlen(strBufAfter);
  729. const std::size_t newBufSize = strBeforeLen + strBufAfterLen;
  730. char* const newBuf = (char*)std::malloc(newBufSize + 1);
  731. CARLA_SAFE_ASSERT_RETURN(newBuf != nullptr, CarlaString());
  732. std::memcpy(newBuf, strBefore.buffer(), strBeforeLen);
  733. std::memcpy(newBuf + strBeforeLen, strBufAfter, strBufAfterLen + 1);
  734. return CarlaString(newBuf, false);
  735. }
  736. static inline
  737. CarlaString operator+(const char* const strBufBefore, const CarlaString& strAfter) noexcept
  738. {
  739. if (strAfter.isEmpty())
  740. return CarlaString(strBufBefore);
  741. if (strBufBefore == nullptr || strBufBefore[0] == '\0')
  742. return strAfter;
  743. const std::size_t strBufBeforeLen = std::strlen(strBufBefore);
  744. const std::size_t strAfterLen = strAfter.length();
  745. const std::size_t newBufSize = strBufBeforeLen + strAfterLen;
  746. char* const newBuf = (char*)std::malloc(newBufSize + 1);
  747. CARLA_SAFE_ASSERT_RETURN(newBuf != nullptr, CarlaString());
  748. std::memcpy(newBuf, strBufBefore, strBufBeforeLen);
  749. std::memcpy(newBuf + strBufBeforeLen, strAfter.buffer(), strAfterLen + 1);
  750. return CarlaString(newBuf, false);
  751. }
  752. // -----------------------------------------------------------------------
  753. #endif // CARLA_STRING_HPP_INCLUDED