17 #ifndef DISTRHO_STRING_HPP_INCLUDED 
   18 #define DISTRHO_STRING_HPP_INCLUDED 
   20 #include "../DistrhoUtils.hpp" 
   21 #include "../extra/ScopedSafeLocale.hpp" 
   25 START_NAMESPACE_DISTRHO
 
   42           fBufferAlloc(
false) {}
 
   47     explicit String(
const char c) noexcept
 
   62     explicit String(
char* 
const strBuf, 
const bool copyData = 
true) noexcept
 
   67         if (copyData || strBuf == 
nullptr)
 
   74             fBufferLen   = std::strlen(strBuf);
 
   82     explicit String(
const char* 
const strBuf) noexcept
 
   93     explicit String(
const int value) noexcept
 
   99         std::snprintf(strBuf, 0xff, 
"%d", value);
 
  108     explicit String(
const unsigned int value, 
const bool hexadecimal = 
false) noexcept
 
  114         std::snprintf(strBuf, 0xff, hexadecimal ? 
"0x%x" : 
"%u", value);
 
  123     explicit String(
const long value) noexcept
 
  129         std::snprintf(strBuf, 0xff, 
"%ld", value);
 
  138     explicit String(
const unsigned long value, 
const bool hexadecimal = 
false) noexcept
 
  144         std::snprintf(strBuf, 0xff, hexadecimal ? 
"0x%lx" : 
"%lu", value);
 
  153     explicit String(
const long long value) noexcept
 
  159         std::snprintf(strBuf, 0xff, 
"%lld", value);
 
  168     explicit String(
const unsigned long long value, 
const bool hexadecimal = 
false) noexcept
 
  174         std::snprintf(strBuf, 0xff, hexadecimal ? 
"0x%llx" : 
"%llu", value);
 
  183     explicit String(
const float value) noexcept
 
  192             std::snprintf(strBuf, 0xff, 
"%.12g", 
static_cast<double>(value));
 
  203     explicit String(
const double value) noexcept
 
  212             std::snprintf(strBuf, 0xff, 
"%.24g", value);
 
  242         DISTRHO_SAFE_ASSERT_RETURN(fBuffer != 
nullptr,);
 
  249         fBufferAlloc = 
false;
 
  258     std::size_t length() 
const noexcept
 
  266     bool isEmpty() 
const noexcept
 
  268         return (fBufferLen == 0);
 
  274     bool isNotEmpty() 
const noexcept
 
  276         return (fBufferLen != 0);
 
  282     bool contains(
const char c) 
const noexcept
 
  284         for (std::size_t i=0; i<fBufferLen; ++i)
 
  296     bool contains(
const char* 
const strBuf, 
const bool ignoreCase = 
false) 
const noexcept
 
  298         DISTRHO_SAFE_ASSERT_RETURN(strBuf != 
nullptr, 
false);
 
  303             return (strcasestr(fBuffer, strBuf) != 
nullptr);
 
  305             String tmp1(fBuffer), tmp2(strBuf);
 
  308             if (tmp1.fBuffer == _null() || tmp2.fBuffer == _null())
 
  313             return (std::strstr(tmp1, tmp2) != 
nullptr);
 
  317         return (std::strstr(fBuffer, strBuf) != 
nullptr);
 
  323     bool isDigit(
const std::size_t pos) 
const noexcept
 
  325         DISTRHO_SAFE_ASSERT_RETURN(pos < fBufferLen, 
false);
 
  327         return (fBuffer[pos] >= 
'0' && fBuffer[pos] <= 
'9');
 
  333     bool startsWith(
const char c) 
const noexcept
 
  335         DISTRHO_SAFE_ASSERT_RETURN(c != 
'\0', 
false);
 
  337         return (fBufferLen > 0 && fBuffer[0] == c);
 
  343     bool startsWith(
const char* 
const prefix) 
const noexcept
 
  345         DISTRHO_SAFE_ASSERT_RETURN(prefix != 
nullptr, 
false);
 
  347         const std::size_t prefixLen(std::strlen(prefix));
 
  349         if (fBufferLen < prefixLen)
 
  352         return (std::strncmp(fBuffer, prefix, prefixLen) == 0);
 
  358     bool endsWith(
const char c) 
const noexcept
 
  360         DISTRHO_SAFE_ASSERT_RETURN(c != 
'\0', 
false);
 
  362         return (fBufferLen > 0 && fBuffer[fBufferLen-1] == c);
 
  368     bool endsWith(
const char* 
const suffix) 
const noexcept
 
  370         DISTRHO_SAFE_ASSERT_RETURN(suffix != 
nullptr, 
false);
 
  372         const std::size_t suffixLen(std::strlen(suffix));
 
  374         if (fBufferLen < suffixLen)
 
  377         return (std::strncmp(fBuffer + (fBufferLen-suffixLen), suffix, suffixLen) == 0);
 
  384     std::size_t find(
const char c, 
bool* 
const found = 
nullptr) 
const noexcept
 
  386         if (fBufferLen == 0 || c == 
'\0')
 
  388             if (found != 
nullptr)
 
  393         for (std::size_t i=0; i < fBufferLen; ++i)
 
  397                 if (found != 
nullptr)
 
  403         if (found != 
nullptr)
 
  412     std::size_t find(
const char* 
const strBuf, 
bool* 
const found = 
nullptr) 
const noexcept
 
  414         if (fBufferLen == 0 || strBuf == 
nullptr || strBuf[0] == 
'\0')
 
  416             if (found != 
nullptr)
 
  421         if (
char* 
const subStrBuf = std::strstr(fBuffer, strBuf))
 
  423             const ssize_t ret(subStrBuf - fBuffer);
 
  428                 d_safe_assert_int(
"ret >= 0", __FILE__, __LINE__, 
int(ret));
 
  430                 if (found != 
nullptr)
 
  435             if (found != 
nullptr)
 
  437             return static_cast<std::size_t
>(ret);
 
  440         if (found != 
nullptr)
 
  449     std::size_t rfind(
const char c, 
bool* 
const found = 
nullptr) 
const noexcept
 
  451         if (fBufferLen == 0 || c == 
'\0')
 
  453             if (found != 
nullptr)
 
  458         for (std::size_t i=fBufferLen; i > 0; --i)
 
  460             if (fBuffer[i-1] == c)
 
  462                 if (found != 
nullptr)
 
  468         if (found != 
nullptr)
 
  477     std::size_t rfind(
const char* 
const strBuf, 
bool* 
const found = 
nullptr) 
const noexcept
 
  479         if (found != 
nullptr)
 
  482         if (fBufferLen == 0 || strBuf == 
nullptr || strBuf[0] == 
'\0')
 
  485         const std::size_t strBufLen(std::strlen(strBuf));
 
  487         std::size_t ret = fBufferLen;
 
  488         const char* tmpBuf = fBuffer;
 
  490         for (std::size_t i=0; i < fBufferLen; ++i)
 
  492             if (std::strstr(tmpBuf+1, strBuf) == 
nullptr && std::strncmp(tmpBuf, strBuf, strBufLen) == 0)
 
  494                 if (found != 
nullptr)
 
  503         return fBufferLen-ret;
 
  509     void clear() noexcept
 
  517     String& replace(
const char before, 
const char after) noexcept
 
  519         DISTRHO_SAFE_ASSERT_RETURN(before != 
'\0' && after != 
'\0', *
this);
 
  521         for (std::size_t i=0; i < fBufferLen; ++i)
 
  523             if (fBuffer[i] == before)
 
  533     String& remove(
const char c) noexcept
 
  535         DISTRHO_SAFE_ASSERT_RETURN(c != 
'\0', *
this);
 
  540         for (std::size_t i=0; i < fBufferLen; ++i)
 
  545                 std::memmove(fBuffer+i, fBuffer+i+1, fBufferLen-i);
 
  549         fBuffer[fBufferLen] = 
'\0';
 
  556     String& truncate(
const std::size_t n) noexcept
 
  570     String& toBasic() noexcept
 
  572         for (std::size_t i=0; i < fBufferLen; ++i)
 
  574             if (fBuffer[i] >= 
'0' && fBuffer[i] <= 
'9')
 
  576             if (fBuffer[i] >= 
'A' && fBuffer[i] <= 
'Z')
 
  578             if (fBuffer[i] >= 
'a' && fBuffer[i] <= 
'z')
 
  580             if (fBuffer[i] == 
'_')
 
  592     String& toLower() noexcept
 
  594         static const char kCharDiff(
'a' - 
'A');
 
  596         for (std::size_t i=0; i < fBufferLen; ++i)
 
  598             if (fBuffer[i] >= 
'A' && fBuffer[i] <= 
'Z')
 
  599                 fBuffer[i] = 
static_cast<char>(fBuffer[i] + kCharDiff);
 
  608     String& toUpper() noexcept
 
  610         static const char kCharDiff(
'a' - 
'A');
 
  612         for (std::size_t i=0; i < fBufferLen; ++i)
 
  614             if (fBuffer[i] >= 
'a' && fBuffer[i] <= 
'z')
 
  615                 fBuffer[i] = 
static_cast<char>(fBuffer[i] - kCharDiff);
 
  624     const char* buffer() 
const noexcept
 
  634     char* getAndReleaseBuffer() noexcept
 
  636         char* ret = fBufferLen > 0 ? fBuffer : 
nullptr;
 
  639         fBufferAlloc = 
false;
 
  647     static String asBase64(
const void* 
const data, 
const std::size_t dataSize)
 
  649         static const char* 
const kBase64Chars =
 
  650             "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 
  651             "abcdefghijklmnopqrstuvwxyz" 
  655         const std::size_t kTmpBufSize = std::min(d_nextPowerOf2(
static_cast<uint32_t
>(dataSize/3)), 65536U);
 
  657         constexpr std::size_t kTmpBufSize = 65536U;
 
  660         const uchar* bytesToEncode((
const uchar*)data);
 
  663         uint charArray3[3], charArray4[4];
 
  665         char strBuf[kTmpBufSize + 1];
 
  666         strBuf[kTmpBufSize] = 
'\0';
 
  667         std::size_t strBufIndex = 0;
 
  671         for (std::size_t s=0; s<dataSize; ++s)
 
  673             charArray3[i++] = *(bytesToEncode++);
 
  677                 charArray4[0] =  (charArray3[0] & 0xfc) >> 2;
 
  678                 charArray4[1] = ((charArray3[0] & 0x03) << 4) + ((charArray3[1] & 0xf0) >> 4);
 
  679                 charArray4[2] = ((charArray3[1] & 0x0f) << 2) + ((charArray3[2] & 0xc0) >> 6);
 
  680                 charArray4[3] =   charArray3[2] & 0x3f;
 
  683                     strBuf[strBufIndex++] = kBase64Chars[charArray4[i]];
 
  685                 if (strBufIndex >= kTmpBufSize-7)
 
  687                     strBuf[strBufIndex] = 
'\0';
 
  699               charArray3[j] = 
'\0';
 
  701             charArray4[0] =  (charArray3[0] & 0xfc) >> 2;
 
  702             charArray4[1] = ((charArray3[0] & 0x03) << 4) + ((charArray3[1] & 0xf0) >> 4);
 
  703             charArray4[2] = ((charArray3[1] & 0x0f) << 2) + ((charArray3[2] & 0xc0) >> 6);
 
  704             charArray4[3] =   charArray3[2] & 0x3f;
 
  706             for (j=0; j<4 && i<3 && j<i+1; ++j)
 
  707                 strBuf[strBufIndex++] = kBase64Chars[charArray4[j]];
 
  710                 strBuf[strBufIndex++] = 
'=';
 
  713         if (strBufIndex != 0)
 
  715             strBuf[strBufIndex] = 
'\0';
 
  725     operator const char*() 
const noexcept
 
  730     char operator[](
const std::size_t pos) 
const noexcept
 
  732         if (pos < fBufferLen)
 
  735         d_safe_assert(
"pos < fBufferLen", __FILE__, __LINE__);
 
  737         static char fallback;
 
  742     char& operator[](
const std::size_t pos) noexcept
 
  744         if (pos < fBufferLen)
 
  747         d_safe_assert(
"pos < fBufferLen", __FILE__, __LINE__);
 
  749         static char fallback;
 
  754     bool operator==(
const char* 
const strBuf) 
const noexcept
 
  756         return (strBuf != 
nullptr && std::strcmp(fBuffer, strBuf) == 0);
 
  759     bool operator==(
const String& str) 
const noexcept
 
  761         return operator==(str.fBuffer);
 
  764     bool operator!=(
const char* 
const strBuf) 
const noexcept
 
  766         return !operator==(strBuf);
 
  769     bool operator!=(
const String& str) 
const noexcept
 
  771         return !operator==(str.fBuffer);
 
  774     String& operator=(
const char* 
const strBuf) noexcept
 
  788     String& operator+=(
const char* 
const strBuf) noexcept
 
  790         if (strBuf == 
nullptr || strBuf[0] == 
'\0')
 
  793         const std::size_t strBufLen = std::strlen(strBuf);
 
  798             _dup(strBuf, strBufLen);
 
  803         char* 
const newBuf = (
char*)realloc(fBuffer, fBufferLen + strBufLen + 1);
 
  804         DISTRHO_SAFE_ASSERT_RETURN(newBuf != 
nullptr, *
this);
 
  806         std::memcpy(newBuf + fBufferLen, strBuf, strBufLen + 1);
 
  809         fBufferLen += strBufLen;
 
  816         return operator+=(str.fBuffer);
 
  819     String operator+(
const char* 
const strBuf) noexcept
 
  821         if (strBuf == 
nullptr || strBuf[0] == 
'\0')
 
  826         const std::size_t strBufLen = std::strlen(strBuf);
 
  827         const std::size_t newBufSize = fBufferLen + strBufLen;
 
  828         char* 
const newBuf = (
char*)malloc(newBufSize + 1);
 
  829         DISTRHO_SAFE_ASSERT_RETURN(newBuf != 
nullptr, 
String());
 
  831         std::memcpy(newBuf, fBuffer, fBufferLen);
 
  832         std::memcpy(newBuf + fBufferLen, strBuf, strBufLen + 1);
 
  839         return operator+(str.fBuffer);
 
  846     std::size_t fBufferLen;   
 
  853     static char* _null() noexcept
 
  855         static char sNull = 
'\0';
 
  867     void _dup(
const char* 
const strBuf, 
const std::size_t size = 0) noexcept
 
  869         if (strBuf != 
nullptr)
 
  872             if (std::strcmp(fBuffer, strBuf) == 0)
 
  878             fBufferLen = (size > 0) ? size : std::strlen(strBuf);
 
  879             fBuffer    = (
char*)std::malloc(fBufferLen+1);
 
  881             if (fBuffer == 
nullptr)
 
  885                 fBufferAlloc = 
false;
 
  891             std::strcpy(fBuffer, strBuf);
 
  892             fBuffer[fBufferLen] = 
'\0';
 
  896             DISTRHO_SAFE_ASSERT_UINT(size == 0, 
static_cast<uint
>(size));
 
  902             DISTRHO_SAFE_ASSERT(fBuffer != 
nullptr);
 
  907             fBufferAlloc = 
false;
 
  911     DISTRHO_PREVENT_HEAP_ALLOCATION
 
  917 String operator+(
const String& strBefore, 
const char* 
const strBufAfter) noexcept
 
  919     if (strBufAfter == 
nullptr || strBufAfter[0] == 
'\0')
 
  921     if (strBefore.isEmpty())
 
  922         return String(strBufAfter);
 
  924     const std::size_t strBeforeLen = strBefore.length();
 
  925     const std::size_t strBufAfterLen = std::strlen(strBufAfter);
 
  926     const std::size_t newBufSize = strBeforeLen + strBufAfterLen;
 
  927     char* 
const newBuf = (
char*)malloc(newBufSize + 1);
 
  928     DISTRHO_SAFE_ASSERT_RETURN(newBuf != 
nullptr, 
String());
 
  930     std::memcpy(newBuf, strBefore.buffer(), strBeforeLen);
 
  931     std::memcpy(newBuf + strBeforeLen, strBufAfter, strBufAfterLen + 1);
 
  937 String operator+(
const char* 
const strBufBefore, 
const String& strAfter) noexcept
 
  939     if (strAfter.isEmpty())
 
  940         return String(strBufBefore);
 
  941     if (strBufBefore == 
nullptr || strBufBefore[0] == 
'\0')
 
  944     const std::size_t strBufBeforeLen = std::strlen(strBufBefore);
 
  945     const std::size_t strAfterLen = strAfter.length();
 
  946     const std::size_t newBufSize = strBufBeforeLen + strAfterLen;
 
  947     char* 
const newBuf = (
char*)malloc(newBufSize + 1);
 
  948     DISTRHO_SAFE_ASSERT_RETURN(newBuf != 
nullptr, 
String());
 
  950     std::memcpy(newBuf, strBufBefore, strBufBeforeLen);
 
  951     std::memcpy(newBuf + strBufBeforeLen, strAfter.buffer(), strAfterLen + 1);
 
  958 END_NAMESPACE_DISTRHO
 
  960 #endif // DISTRHO_STRING_HPP_INCLUDED