1 // SPDX-FileCopyrightText: 2011-2024 Filipe Coelho <falktx@falktx.com>
2 // SPDX-License-Identifier: GPL-2.0-or-later
4 #ifndef CARLA_STRING_HPP_INCLUDED
5 #define CARLA_STRING_HPP_INCLUDED
7 #include "CarlaMathUtils.hpp"
8 #include "CarlaScopeUtils.hpp"
12 // -----------------------------------------------------------------------
15 class CARLA_API CarlaString
18 // -------------------------------------------------------------------
19 // constructors (no explicit conversions allowed)
24 explicit CarlaString() noexcept
27 fBufferAlloc(false) {}
32 explicit CarlaString(const char c
) noexcept
47 explicit CarlaString(char* const strBuf
, const bool reallocData
= true) noexcept
52 if (reallocData
|| strBuf
== nullptr)
59 fBufferLen
= std::strlen(strBuf
);
65 * Simple const char string.
67 explicit CarlaString(const char* const strBuf
) noexcept
78 explicit CarlaString(const int value
) noexcept
84 std::snprintf(strBuf
, 0xff, "%d", value
);
91 * Unsigned integer, possibly in hexadecimal.
93 explicit CarlaString(const unsigned int value
, const bool hexadecimal
= false) noexcept
99 std::snprintf(strBuf
, 0xff, hexadecimal
? "0x%x" : "%u", value
);
108 explicit CarlaString(const long value
) noexcept
114 std::snprintf(strBuf
, 0xff, "%ld", value
);
121 * Long unsigned integer, possibly hexadecimal.
123 explicit CarlaString(const unsigned long value
, const bool hexadecimal
= false) noexcept
129 std::snprintf(strBuf
, 0xff, hexadecimal
? "0x%lx" : "%lu", value
);
138 explicit CarlaString(const long long value
) noexcept
144 std::snprintf(strBuf
, 0xff, "%lld", value
);
151 * Long long unsigned integer, possibly hexadecimal.
153 explicit CarlaString(const unsigned long long value
, const bool hexadecimal
= false) noexcept
159 std::snprintf(strBuf
, 0xff, hexadecimal
? "0x%llx" : "%llu", value
);
166 * Single-precision floating point number.
168 explicit CarlaString(const float value
) noexcept
176 const CarlaScopedLocale csl
;
177 std::snprintf(strBuf
, 0xff, "%.12g", static_cast<double>(value
));
186 * Double-precision floating point number.
188 explicit CarlaString(const double value
) noexcept
196 const CarlaScopedLocale csl
;
197 std::snprintf(strBuf
, 0xff, "%.24g", value
);
205 // -------------------------------------------------------------------
206 // non-explicit constructor
209 * Create string from another string.
211 CarlaString(const CarlaString
& str
) noexcept
219 // -------------------------------------------------------------------
225 ~CarlaString() noexcept
227 CARLA_SAFE_ASSERT_RETURN(fBuffer
!= nullptr,);
234 fBufferAlloc
= false;
237 // -------------------------------------------------------------------
241 * Get length of the string.
243 std::size_t length() const noexcept
249 * Check if the string is empty.
251 bool isEmpty() const noexcept
253 return (fBufferLen
== 0);
257 * Check if the string is not empty.
259 bool isNotEmpty() const noexcept
261 return (fBufferLen
!= 0);
265 * Check if the string contains a specific character, case-sensitive.
267 bool contains(const char c
) const noexcept
269 for (std::size_t i
=0; i
<fBufferLen
; ++i
)
279 * Check if the string contains another string, optionally ignoring case.
281 bool contains(const char* const strBuf
, const bool ignoreCase
= false) const noexcept
283 CARLA_SAFE_ASSERT_RETURN(strBuf
!= nullptr, false);
286 return carla_strcasestr(fBuffer
, strBuf
) != nullptr;
288 return std::strstr(fBuffer
, strBuf
) != nullptr;
292 * Check if character at 'pos' is a digit.
294 bool isDigit(const std::size_t pos
) const noexcept
296 CARLA_SAFE_ASSERT_RETURN(pos
< fBufferLen
, false);
298 return (fBuffer
[pos
] >= '0' && fBuffer
[pos
] <= '9');
302 * Check if the string starts with the character 'c'.
304 bool startsWith(const char c
) const noexcept
306 CARLA_SAFE_ASSERT_RETURN(c
!= '\0', false);
308 return (fBufferLen
> 0 && fBuffer
[0] == c
);
312 * Check if the string starts with the string 'prefix'.
314 bool startsWith(const char* const prefix
) const noexcept
316 CARLA_SAFE_ASSERT_RETURN(prefix
!= nullptr, false);
318 const std::size_t prefixLen(std::strlen(prefix
));
320 if (fBufferLen
< prefixLen
)
323 return (std::strncmp(fBuffer
, prefix
, prefixLen
) == 0);
327 * Check if the string ends with the character 'c'.
329 bool endsWith(const char c
) const noexcept
331 CARLA_SAFE_ASSERT_RETURN(c
!= '\0', false);
333 return (fBufferLen
> 0 && fBuffer
[fBufferLen
-1] == c
);
337 * Check if the string ends with the string 'suffix'.
339 bool endsWith(const char* const suffix
) const noexcept
341 CARLA_SAFE_ASSERT_RETURN(suffix
!= nullptr, false);
343 const std::size_t suffixLen(std::strlen(suffix
));
345 if (fBufferLen
< suffixLen
)
348 return (std::strncmp(fBuffer
+ (fBufferLen
-suffixLen
), suffix
, suffixLen
) == 0);
352 * Find the first occurrence of character 'c' in the string.
353 * Returns "length()" if the character is not found.
355 std::size_t find(const char c
, bool* const found
= nullptr) const noexcept
357 if (fBufferLen
== 0 || c
== '\0')
359 if (found
!= nullptr)
364 for (std::size_t i
=0; i
< fBufferLen
; ++i
)
368 if (found
!= nullptr)
374 if (found
!= nullptr)
380 * Find the first occurrence of string 'strBuf' in the string.
381 * Returns "length()" if the string is not found.
383 std::size_t find(const char* const strBuf
, bool* const found
= nullptr) const noexcept
385 if (fBufferLen
== 0 || strBuf
== nullptr || strBuf
[0] == '\0')
387 if (found
!= nullptr)
392 if (char* const subStrBuf
= std::strstr(fBuffer
, strBuf
))
394 const ssize_t ret
= subStrBuf
- fBuffer
;
398 // should never happen!
399 carla_safe_assert_int("ret >= 0", __FILE__
, __LINE__
, int(ret
));
401 if (found
!= nullptr)
406 if (found
!= nullptr)
408 return static_cast<std::size_t>(ret
);
411 if (found
!= nullptr)
417 * Find the last occurrence of character 'c' in the string.
418 * Returns "length()" if the character is not found.
420 std::size_t rfind(const char c
, bool* const found
= nullptr) const noexcept
422 if (fBufferLen
== 0 || c
== '\0')
424 if (found
!= nullptr)
429 for (std::size_t i
=fBufferLen
; i
> 0; --i
)
431 if (fBuffer
[i
-1] == c
)
433 if (found
!= nullptr)
439 if (found
!= nullptr)
445 * Find the last occurrence of string 'strBuf' in the string.
446 * Returns "length()" if the string is not found.
448 std::size_t rfind(const char* const strBuf
, bool* const found
= nullptr) const noexcept
450 if (found
!= nullptr)
453 if (fBufferLen
== 0 || strBuf
== nullptr || strBuf
[0] == '\0')
456 const std::size_t strBufLen(std::strlen(strBuf
));
458 std::size_t ret
= fBufferLen
;
459 const char* tmpBuf
= fBuffer
;
461 for (std::size_t i
=0; i
< fBufferLen
; ++i
)
463 if (std::strstr(tmpBuf
+1, strBuf
) == nullptr && std::strncmp(tmpBuf
, strBuf
, strBufLen
) == 0)
465 if (found
!= nullptr)
474 return fBufferLen
-ret
;
480 void clear() noexcept
486 * Replace all occurrences of character 'before' with character 'after'.
488 CarlaString
& replace(const char before
, const char after
) noexcept
490 CARLA_SAFE_ASSERT_RETURN(before
!= '\0' && after
!= '\0', *this);
492 for (std::size_t i
=0; i
< fBufferLen
; ++i
)
494 if (fBuffer
[i
] == before
)
502 * Truncate the string to size 'n'.
504 CarlaString
& truncate(const std::size_t n
) noexcept
516 * Convert all non-basic characters to '_'.
518 CarlaString
& toBasic() noexcept
520 for (std::size_t i
=0; i
< fBufferLen
; ++i
)
522 if (fBuffer
[i
] >= '0' && fBuffer
[i
] <= '9')
524 if (fBuffer
[i
] >= 'A' && fBuffer
[i
] <= 'Z')
526 if (fBuffer
[i
] >= 'a' && fBuffer
[i
] <= 'z')
528 if (fBuffer
[i
] == '_')
538 * Convert all ascii characters to lowercase.
540 CarlaString
& toLower() noexcept
542 static const char kCharDiff('a' - 'A');
544 for (std::size_t i
=0; i
< fBufferLen
; ++i
)
546 if (fBuffer
[i
] >= 'A' && fBuffer
[i
] <= 'Z')
547 fBuffer
[i
] = static_cast<char>(fBuffer
[i
] + kCharDiff
);
554 * Convert all ascii characters to uppercase.
556 CarlaString
& toUpper() noexcept
558 static const char kCharDiff('a' - 'A');
560 for (std::size_t i
=0; i
< fBufferLen
; ++i
)
562 if (fBuffer
[i
] >= 'a' && fBuffer
[i
] <= 'z')
563 fBuffer
[i
] = static_cast<char>(fBuffer
[i
] - kCharDiff
);
570 * Direct access to the string buffer (read-only).
572 const char* buffer() const noexcept
578 * Return a duplicate string buffer.
581 const char* dup() const
583 return carla_strdup(fBuffer
);
587 * Return a duplicate string buffer or null.
589 const char* dupSafe() const noexcept
591 return carla_strdup_safe(fBuffer
);
595 * Release the buffer pointer while clearing this string.
596 * This allows to keep a pointer to the buffer after this object is deleted.
598 char* releaseBufferPointer() noexcept
600 char* ret
= fBufferLen
> 0 ? fBuffer
: nullptr;
603 fBufferAlloc
= false;
607 // -------------------------------------------------------------------
608 // base64 stuff, based on http://www.adp-gmbh.ch/cpp/common/base64.html
609 // Copyright (C) 2004-2008 René Nyffenegger
611 static CarlaString
asBase64(const void* const data
, const std::size_t dataSize
)
613 static const char* const kBase64Chars
=
614 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
615 "abcdefghijklmnopqrstuvwxyz"
618 static constexpr const std::size_t kTmpBufSize
= 65536U;
620 const uchar
* bytesToEncode((const uchar
*)data
);
623 uint charArray3
[3], charArray4
[4];
625 char strBuf
[kTmpBufSize
+1];
626 strBuf
[kTmpBufSize
] = '\0';
627 std::size_t strBufIndex
= 0;
631 for (std::size_t s
=0; s
<dataSize
; ++s
)
633 charArray3
[i
++] = *(bytesToEncode
++);
637 charArray4
[0] = (charArray3
[0] & 0xfc) >> 2;
638 charArray4
[1] = ((charArray3
[0] & 0x03) << 4) + ((charArray3
[1] & 0xf0) >> 4);
639 charArray4
[2] = ((charArray3
[1] & 0x0f) << 2) + ((charArray3
[2] & 0xc0) >> 6);
640 charArray4
[3] = charArray3
[2] & 0x3f;
643 strBuf
[strBufIndex
++] = kBase64Chars
[charArray4
[i
]];
645 if (strBufIndex
>= kTmpBufSize
-7)
647 strBuf
[strBufIndex
] = '\0';
659 charArray3
[j
] = '\0';
661 charArray4
[0] = (charArray3
[0] & 0xfc) >> 2;
662 charArray4
[1] = ((charArray3
[0] & 0x03) << 4) + ((charArray3
[1] & 0xf0) >> 4);
663 charArray4
[2] = ((charArray3
[1] & 0x0f) << 2) + ((charArray3
[2] & 0xc0) >> 6);
664 charArray4
[3] = charArray3
[2] & 0x3f;
666 for (j
=0; j
<4 && i
<3 && j
<i
+1; ++j
)
667 strBuf
[strBufIndex
++] = kBase64Chars
[charArray4
[j
]];
670 strBuf
[strBufIndex
++] = '=';
673 if (strBufIndex
!= 0)
675 strBuf
[strBufIndex
] = '\0';
682 // -------------------------------------------------------------------
685 operator const char*() const noexcept
690 char operator[](const std::size_t pos
) const noexcept
692 if (pos
< fBufferLen
)
695 carla_safe_assert("pos < fBufferLen", __FILE__
, __LINE__
);
697 static char fallback
= '\0';
701 char& operator[](const std::size_t pos
) noexcept
703 if (pos
< fBufferLen
)
706 carla_safe_assert("pos < fBufferLen", __FILE__
, __LINE__
);
708 static char fallback
= '\0';
712 bool operator==(const char* const strBuf
) const noexcept
714 return (strBuf
!= nullptr && std::strcmp(fBuffer
, strBuf
) == 0);
717 bool operator==(const CarlaString
& str
) const noexcept
719 return operator==(str
.fBuffer
);
722 bool operator!=(const char* const strBuf
) const noexcept
724 return !operator==(strBuf
);
727 bool operator!=(const CarlaString
& str
) const noexcept
729 return !operator==(str
.fBuffer
);
732 CarlaString
& operator=(const char* const strBuf
) noexcept
739 CarlaString
& operator=(const CarlaString
& str
) noexcept
746 CarlaString
& operator+=(const char* const strBuf
) noexcept
748 if (strBuf
== nullptr || strBuf
[0] == '\0')
751 const std::size_t strBufLen
= std::strlen(strBuf
);
753 // for empty strings, we can just take the appended string as our entire data
756 _dup(strBuf
, strBufLen
);
760 // we have some data ourselves, reallocate to add the new stuff
761 char* const newBuf
= (char*)realloc(fBuffer
, fBufferLen
+ strBufLen
+ 1);
762 CARLA_SAFE_ASSERT_RETURN(newBuf
!= nullptr, *this);
764 std::memcpy(newBuf
+ fBufferLen
, strBuf
, strBufLen
+ 1);
767 fBufferLen
+= strBufLen
;
772 CarlaString
& operator+=(const CarlaString
& str
) noexcept
774 return operator+=(str
.fBuffer
);
777 CarlaString
operator+(const char* const strBuf
) noexcept
779 if (strBuf
== nullptr || strBuf
[0] == '\0')
782 return CarlaString(strBuf
);
784 const std::size_t strBufLen
= std::strlen(strBuf
);
785 const std::size_t newBufSize
= fBufferLen
+ strBufLen
;
786 char* const newBuf
= (char*)std::malloc(newBufSize
+ 1);
787 CARLA_SAFE_ASSERT_RETURN(newBuf
!= nullptr, CarlaString());
789 std::memcpy(newBuf
, fBuffer
, fBufferLen
);
790 std::memcpy(newBuf
+ fBufferLen
, strBuf
, strBufLen
+ 1);
792 return CarlaString(newBuf
, false);
795 CarlaString
operator+(const CarlaString
& str
) noexcept
797 return operator+(str
.fBuffer
);
800 // needed for std::map compatibility
801 bool operator<(const CarlaString
& str
) const noexcept
803 return std::strcmp(fBuffer
, str
.fBuffer
) < 0;
806 // -------------------------------------------------------------------
809 char* fBuffer
; // the actual string buffer
810 std::size_t fBufferLen
; // string length
811 bool fBufferAlloc
; // wherever the buffer is allocated, not using _null()
814 * Static null string.
815 * Prevents allocation for new and/or empty strings.
817 static char* _null() noexcept
819 static char sNull
= '\0';
825 * Called whenever the string needs to be allocated.
828 * - Allocates string only if 'strBuf' is not null and new string contents are different
829 * - If 'strBuf' is null, 'size' must be 0
831 void _dup(const char* const strBuf
, const std::size_t size
= 0) noexcept
833 if (strBuf
!= nullptr)
835 // don't recreate string if contents match
836 if (std::strcmp(fBuffer
, strBuf
) == 0)
842 fBufferLen
= (size
> 0) ? size
: std::strlen(strBuf
);
843 fBuffer
= (char*)std::malloc(fBufferLen
+1);
845 if (fBuffer
== nullptr)
849 fBufferAlloc
= false;
855 std::strcpy(fBuffer
, strBuf
);
856 fBuffer
[fBufferLen
] = '\0';
860 CARLA_SAFE_ASSERT_UINT(size
== 0, static_cast<uint
>(size
));
862 // don't recreate null string
866 CARLA_SAFE_ASSERT(fBuffer
!= nullptr);
871 fBufferAlloc
= false;
875 CARLA_PREVENT_HEAP_ALLOCATION
878 // -----------------------------------------------------------------------
881 CarlaString
operator+(const CarlaString
& strBefore
, const char* const strBufAfter
) noexcept
883 if (strBufAfter
== nullptr || strBufAfter
[0] == '\0')
885 if (strBefore
.isEmpty())
886 return CarlaString(strBufAfter
);
888 const std::size_t strBeforeLen
= strBefore
.length();
889 const std::size_t strBufAfterLen
= std::strlen(strBufAfter
);
890 const std::size_t newBufSize
= strBeforeLen
+ strBufAfterLen
;
891 char* const newBuf
= (char*)std::malloc(newBufSize
+ 1);
892 CARLA_SAFE_ASSERT_RETURN(newBuf
!= nullptr, CarlaString());
894 std::memcpy(newBuf
, strBefore
.buffer(), strBeforeLen
);
895 std::memcpy(newBuf
+ strBeforeLen
, strBufAfter
, strBufAfterLen
+ 1);
897 return CarlaString(newBuf
, false);
901 CarlaString
operator+(const char* const strBufBefore
, const CarlaString
& strAfter
) noexcept
903 if (strAfter
.isEmpty())
904 return CarlaString(strBufBefore
);
905 if (strBufBefore
== nullptr || strBufBefore
[0] == '\0')
908 const std::size_t strBufBeforeLen
= std::strlen(strBufBefore
);
909 const std::size_t strAfterLen
= strAfter
.length();
910 const std::size_t newBufSize
= strBufBeforeLen
+ strAfterLen
;
911 char* const newBuf
= (char*)std::malloc(newBufSize
+ 1);
912 CARLA_SAFE_ASSERT_RETURN(newBuf
!= nullptr, CarlaString());
914 std::memcpy(newBuf
, strBufBefore
, strBufBeforeLen
);
915 std::memcpy(newBuf
+ strBufBeforeLen
, strAfter
.buffer(), strAfterLen
+ 1);
917 return CarlaString(newBuf
, false);
920 // -----------------------------------------------------------------------
922 #endif // CARLA_STRING_HPP_INCLUDED