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.

909 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 a specific character, case-sensitive.
  230. */
  231. bool contains(const char c) const noexcept
  232. {
  233. for (std::size_t i=0; i<fBufferLen; ++i)
  234. {
  235. if (fBuffer[i] == c)
  236. return true;
  237. }
  238. return false;
  239. }
  240. /*
  241. * Check if the string contains another string, optionally ignoring case.
  242. */
  243. bool contains(const char* const strBuf, const bool ignoreCase = false) const noexcept
  244. {
  245. CARLA_SAFE_ASSERT_RETURN(strBuf != nullptr, false);
  246. if (ignoreCase)
  247. {
  248. #ifdef __USE_GNU
  249. return (strcasestr(fBuffer, strBuf) != nullptr);
  250. #else
  251. CarlaString tmp1(fBuffer), tmp2(strBuf);
  252. // memory allocation failed or empty string(s)
  253. if (tmp1.fBuffer == _null() || tmp2.fBuffer == _null())
  254. return false;
  255. tmp1.toLower();
  256. tmp2.toLower();
  257. return (std::strstr(tmp1, tmp2) != nullptr);
  258. #endif
  259. }
  260. return (std::strstr(fBuffer, strBuf) != nullptr);
  261. }
  262. /*
  263. * Check if character at 'pos' is a digit.
  264. */
  265. bool isDigit(const std::size_t pos) const noexcept
  266. {
  267. CARLA_SAFE_ASSERT_RETURN(pos < fBufferLen, false);
  268. return (fBuffer[pos] >= '0' && fBuffer[pos] <= '9');
  269. }
  270. /*
  271. * Check if the string starts with the character 'c'.
  272. */
  273. bool startsWith(const char c) const noexcept
  274. {
  275. CARLA_SAFE_ASSERT_RETURN(c != '\0', false);
  276. return (fBufferLen > 0 && fBuffer[0] == c);
  277. }
  278. /*
  279. * Check if the string starts with the string 'prefix'.
  280. */
  281. bool startsWith(const char* const prefix) const noexcept
  282. {
  283. CARLA_SAFE_ASSERT_RETURN(prefix != nullptr, false);
  284. const std::size_t prefixLen(std::strlen(prefix));
  285. if (fBufferLen < prefixLen)
  286. return false;
  287. return (std::strncmp(fBuffer, prefix, prefixLen) == 0);
  288. }
  289. /*
  290. * Check if the string ends with the character 'c'.
  291. */
  292. bool endsWith(const char c) const noexcept
  293. {
  294. CARLA_SAFE_ASSERT_RETURN(c != '\0', false);
  295. return (fBufferLen > 0 && fBuffer[fBufferLen-1] == c);
  296. }
  297. /*
  298. * Check if the string ends with the string 'suffix'.
  299. */
  300. bool endsWith(const char* const suffix) const noexcept
  301. {
  302. CARLA_SAFE_ASSERT_RETURN(suffix != nullptr, false);
  303. const std::size_t suffixLen(std::strlen(suffix));
  304. if (fBufferLen < suffixLen)
  305. return false;
  306. return (std::strncmp(fBuffer + (fBufferLen-suffixLen), suffix, suffixLen) == 0);
  307. }
  308. /*
  309. * Find the first occurrence of character 'c' in the string.
  310. * Returns "length()" if the character is not found.
  311. */
  312. std::size_t find(const char c, bool* const found = nullptr) const noexcept
  313. {
  314. if (fBufferLen == 0 || c == '\0')
  315. {
  316. if (found != nullptr)
  317. *found = false;
  318. return fBufferLen;
  319. }
  320. for (std::size_t i=0; i < fBufferLen; ++i)
  321. {
  322. if (fBuffer[i] == c)
  323. {
  324. if (found != nullptr)
  325. *found = true;
  326. return i;
  327. }
  328. }
  329. if (found != nullptr)
  330. *found = false;
  331. return fBufferLen;
  332. }
  333. /*
  334. * Find the first occurrence of string 'strBuf' in the string.
  335. * Returns "length()" if the string is not found.
  336. */
  337. std::size_t find(const char* const strBuf, bool* const found = nullptr) const noexcept
  338. {
  339. if (fBufferLen == 0 || strBuf == nullptr || strBuf[0] == '\0')
  340. {
  341. if (found != nullptr)
  342. *found = false;
  343. return fBufferLen;
  344. }
  345. if (char* const subStrBuf = std::strstr(fBuffer, strBuf))
  346. {
  347. const ssize_t ret(subStrBuf - fBuffer);
  348. if (ret < 0)
  349. {
  350. // should never happen!
  351. carla_safe_assert_int("ret >= 0", __FILE__, __LINE__, int(ret));
  352. if (found != nullptr)
  353. *found = false;
  354. return fBufferLen;
  355. }
  356. if (found != nullptr)
  357. *found = true;
  358. return static_cast<std::size_t>(ret);
  359. }
  360. if (found != nullptr)
  361. *found = false;
  362. return fBufferLen;
  363. }
  364. /*
  365. * Find the last occurrence of character 'c' in the string.
  366. * Returns "length()" if the character is not found.
  367. */
  368. std::size_t rfind(const char c, bool* const found = nullptr) const noexcept
  369. {
  370. if (fBufferLen == 0 || c == '\0')
  371. {
  372. if (found != nullptr)
  373. *found = false;
  374. return fBufferLen;
  375. }
  376. for (std::size_t i=fBufferLen; i > 0; --i)
  377. {
  378. if (fBuffer[i-1] == c)
  379. {
  380. if (found != nullptr)
  381. *found = true;
  382. return i-1;
  383. }
  384. }
  385. if (found != nullptr)
  386. *found = false;
  387. return fBufferLen;
  388. }
  389. /*
  390. * Find the last occurrence of string 'strBuf' in the string.
  391. * Returns "length()" if the string is not found.
  392. */
  393. std::size_t rfind(const char* const strBuf, bool* const found = nullptr) const noexcept
  394. {
  395. if (found != nullptr)
  396. *found = false;
  397. if (fBufferLen == 0 || strBuf == nullptr || strBuf[0] == '\0')
  398. return fBufferLen;
  399. const std::size_t strBufLen(std::strlen(strBuf));
  400. std::size_t ret = fBufferLen;
  401. const char* tmpBuf = fBuffer;
  402. for (std::size_t i=0; i < fBufferLen; ++i)
  403. {
  404. if (std::strstr(tmpBuf+1, strBuf) == nullptr && std::strncmp(tmpBuf, strBuf, strBufLen) == 0)
  405. {
  406. if (found != nullptr)
  407. *found = true;
  408. break;
  409. }
  410. --ret;
  411. ++tmpBuf;
  412. }
  413. return fBufferLen-ret;
  414. }
  415. /*
  416. * Clear the string.
  417. */
  418. void clear() noexcept
  419. {
  420. truncate(0);
  421. }
  422. /*
  423. * Replace all occurrences of character 'before' with character 'after'.
  424. */
  425. CarlaString& replace(const char before, const char after) noexcept
  426. {
  427. CARLA_SAFE_ASSERT_RETURN(before != '\0' && after != '\0', *this);
  428. for (std::size_t i=0; i < fBufferLen; ++i)
  429. {
  430. if (fBuffer[i] == before)
  431. fBuffer[i] = after;
  432. }
  433. return *this;
  434. }
  435. /*
  436. * Truncate the string to size 'n'.
  437. */
  438. CarlaString& truncate(const std::size_t n) noexcept
  439. {
  440. if (n >= fBufferLen)
  441. return *this;
  442. fBuffer[n] = '\0';
  443. fBufferLen = n;
  444. return *this;
  445. }
  446. /*
  447. * Convert all non-basic characters to '_'.
  448. */
  449. CarlaString& toBasic() noexcept
  450. {
  451. for (std::size_t i=0; i < fBufferLen; ++i)
  452. {
  453. if (fBuffer[i] >= '0' && fBuffer[i] <= '9')
  454. continue;
  455. if (fBuffer[i] >= 'A' && fBuffer[i] <= 'Z')
  456. continue;
  457. if (fBuffer[i] >= 'a' && fBuffer[i] <= 'z')
  458. continue;
  459. if (fBuffer[i] == '_')
  460. continue;
  461. fBuffer[i] = '_';
  462. }
  463. return *this;
  464. }
  465. /*
  466. * Convert all ascii characters to lowercase.
  467. */
  468. CarlaString& toLower() noexcept
  469. {
  470. static const char kCharDiff('a' - 'A');
  471. for (std::size_t i=0; i < fBufferLen; ++i)
  472. {
  473. if (fBuffer[i] >= 'A' && fBuffer[i] <= 'Z')
  474. fBuffer[i] = static_cast<char>(fBuffer[i] + kCharDiff);
  475. }
  476. return *this;
  477. }
  478. /*
  479. * Convert all ascii characters to uppercase.
  480. */
  481. CarlaString& toUpper() noexcept
  482. {
  483. static const char kCharDiff('a' - 'A');
  484. for (std::size_t i=0; i < fBufferLen; ++i)
  485. {
  486. if (fBuffer[i] >= 'a' && fBuffer[i] <= 'z')
  487. fBuffer[i] = static_cast<char>(fBuffer[i] - kCharDiff);
  488. }
  489. return *this;
  490. }
  491. /*
  492. * Direct access to the string buffer (read-only).
  493. */
  494. const char* buffer() const noexcept
  495. {
  496. return fBuffer;
  497. }
  498. /*
  499. * Return a duplicate string buffer.
  500. * May throw.
  501. */
  502. const char* dup() const
  503. {
  504. return carla_strdup(fBuffer);
  505. }
  506. /*
  507. * Return a duplicate string buffer or null.
  508. */
  509. const char* dupSafe() const noexcept
  510. {
  511. return carla_strdup_safe(fBuffer);
  512. }
  513. /*
  514. * Release the buffer pointer while clearing this string.
  515. * This allows to keep a pointer to the buffer after this object is deleted.
  516. */
  517. char* releaseBufferPointer() noexcept
  518. {
  519. char* ret = fBufferLen > 0 ? fBuffer : nullptr;
  520. fBuffer = _null();
  521. fBufferLen = 0;
  522. fBufferAlloc = false;
  523. return ret;
  524. }
  525. // -------------------------------------------------------------------
  526. // base64 stuff, based on http://www.adp-gmbh.ch/cpp/common/base64.html
  527. // Copyright (C) 2004-2008 René Nyffenegger
  528. static CarlaString asBase64(const void* const data, const std::size_t dataSize)
  529. {
  530. static const char* const kBase64Chars =
  531. "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  532. "abcdefghijklmnopqrstuvwxyz"
  533. "0123456789+/";
  534. const std::size_t kTmpBufSize = std::min(carla_nextPowerOf2(static_cast<uint32_t>(dataSize/3)), 65536U);
  535. const uchar* bytesToEncode((const uchar*)data);
  536. uint i=0, j=0;
  537. uint charArray3[3], charArray4[4];
  538. char strBuf[kTmpBufSize+1];
  539. strBuf[kTmpBufSize] = '\0';
  540. std::size_t strBufIndex = 0;
  541. CarlaString ret;
  542. for (std::size_t s=0; s<dataSize; ++s)
  543. {
  544. charArray3[i++] = *(bytesToEncode++);
  545. if (i == 3)
  546. {
  547. charArray4[0] = (charArray3[0] & 0xfc) >> 2;
  548. charArray4[1] = ((charArray3[0] & 0x03) << 4) + ((charArray3[1] & 0xf0) >> 4);
  549. charArray4[2] = ((charArray3[1] & 0x0f) << 2) + ((charArray3[2] & 0xc0) >> 6);
  550. charArray4[3] = charArray3[2] & 0x3f;
  551. for (i=0; i<4; ++i)
  552. strBuf[strBufIndex++] = kBase64Chars[charArray4[i]];
  553. if (strBufIndex >= kTmpBufSize-7)
  554. {
  555. strBuf[strBufIndex] = '\0';
  556. strBufIndex = 0;
  557. ret += strBuf;
  558. }
  559. i = 0;
  560. }
  561. }
  562. if (i != 0)
  563. {
  564. for (j=i; j<3; ++j)
  565. charArray3[j] = '\0';
  566. charArray4[0] = (charArray3[0] & 0xfc) >> 2;
  567. charArray4[1] = ((charArray3[0] & 0x03) << 4) + ((charArray3[1] & 0xf0) >> 4);
  568. charArray4[2] = ((charArray3[1] & 0x0f) << 2) + ((charArray3[2] & 0xc0) >> 6);
  569. charArray4[3] = charArray3[2] & 0x3f;
  570. for (j=0; j<4 && i<3 && j<i+1; ++j)
  571. strBuf[strBufIndex++] = kBase64Chars[charArray4[j]];
  572. for (; i++ < 3;)
  573. strBuf[strBufIndex++] = '=';
  574. }
  575. if (strBufIndex != 0)
  576. {
  577. strBuf[strBufIndex] = '\0';
  578. ret += strBuf;
  579. }
  580. return ret;
  581. }
  582. // -------------------------------------------------------------------
  583. // public operators
  584. operator const char*() const noexcept
  585. {
  586. return fBuffer;
  587. }
  588. char operator[](const std::size_t pos) const noexcept
  589. {
  590. if (pos < fBufferLen)
  591. return fBuffer[pos];
  592. carla_safe_assert("pos < fBufferLen", __FILE__, __LINE__);
  593. static char fallback;
  594. fallback = '\0';
  595. return fallback;
  596. }
  597. char& operator[](const std::size_t pos) noexcept
  598. {
  599. if (pos < fBufferLen)
  600. return fBuffer[pos];
  601. carla_safe_assert("pos < fBufferLen", __FILE__, __LINE__);
  602. static char fallback;
  603. fallback = '\0';
  604. return fallback;
  605. }
  606. bool operator==(const char* const strBuf) const noexcept
  607. {
  608. return (strBuf != nullptr && std::strcmp(fBuffer, strBuf) == 0);
  609. }
  610. bool operator==(const CarlaString& str) const noexcept
  611. {
  612. return operator==(str.fBuffer);
  613. }
  614. bool operator!=(const char* const strBuf) const noexcept
  615. {
  616. return !operator==(strBuf);
  617. }
  618. bool operator!=(const CarlaString& str) const noexcept
  619. {
  620. return !operator==(str.fBuffer);
  621. }
  622. CarlaString& operator=(const char* const strBuf) noexcept
  623. {
  624. _dup(strBuf);
  625. return *this;
  626. }
  627. CarlaString& operator=(const CarlaString& str) noexcept
  628. {
  629. _dup(str.fBuffer);
  630. return *this;
  631. }
  632. CarlaString& operator+=(const char* const strBuf) noexcept
  633. {
  634. if (strBuf == nullptr)
  635. return *this;
  636. const std::size_t newBufSize = fBufferLen + std::strlen(strBuf) + 1;
  637. char newBuf[newBufSize];
  638. std::strcpy(newBuf, fBuffer);
  639. std::strcat(newBuf, strBuf);
  640. _dup(newBuf, newBufSize-1);
  641. return *this;
  642. }
  643. CarlaString& operator+=(const CarlaString& str) noexcept
  644. {
  645. return operator+=(str.fBuffer);
  646. }
  647. CarlaString operator+(const char* const strBuf) noexcept
  648. {
  649. const std::size_t newBufSize = fBufferLen + ((strBuf != nullptr) ? std::strlen(strBuf) : 0) + 1;
  650. char newBuf[newBufSize];
  651. std::strcpy(newBuf, fBuffer);
  652. if (strBuf != nullptr)
  653. std::strcat(newBuf, strBuf);
  654. return CarlaString(newBuf);
  655. }
  656. CarlaString operator+(const CarlaString& str) noexcept
  657. {
  658. return operator+(str.fBuffer);
  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. const char* const strBufBefore = strBefore.buffer();
  724. const std::size_t newBufSize = strBefore.length() + ((strBufAfter != nullptr) ? std::strlen(strBufAfter) : 0) + 1;
  725. char newBuf[newBufSize];
  726. std::strcpy(newBuf, strBufBefore);
  727. std::strcat(newBuf, strBufAfter);
  728. return CarlaString(newBuf);
  729. }
  730. static inline
  731. CarlaString operator+(const char* const strBufBefore, const CarlaString& strAfter) noexcept
  732. {
  733. const char* const strBufAfter = strAfter.buffer();
  734. const std::size_t newBufSize = ((strBufBefore != nullptr) ? std::strlen(strBufBefore) : 0) + strAfter.length() + 1;
  735. char newBuf[newBufSize];
  736. std::strcpy(newBuf, strBufBefore);
  737. std::strcat(newBuf, strBufAfter);
  738. return CarlaString(newBuf);
  739. }
  740. // -----------------------------------------------------------------------
  741. #endif // CARLA_STRING_HPP_INCLUDED