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.

841 lines
20KB

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