59#pragma warning (disable : 4244)
60#pragma warning (disable : 4267)
61#pragma warning (disable : 4996)
66#define malloc(s) _malloc_dbg(s, _NORMAL_BLOCK, __FILE__, __LINE__)
67#define realloc(p,s) _realloc_dbg(p,s, _NORMAL_BLOCK, __FILE__, __LINE__)
68#define free(p) _free_dbg(p, _NORMAL_BLOCK)
74#ifndef kPrintfBufferSize
75#define kPrintfBufferSize 4096
79#include <CoreFoundation/CoreFoundation.h>
80#include <CoreFoundation/CFString.h>
81#include <CoreFoundation/CFStringEncodingExt.h>
84#if defined (__GNUC__) && (__GNUC__ >= 4) && !__LP64__
86#pragma GCC diagnostic ignored "-Wformat"
89#define SMTG_ENABLE_DEBUG_CFALLOCATOR 0
90#define SMTG_DEBUG_CFALLOCATOR (DEVELOPMENT && SMTG_ENABLE_DEBUG_CFALLOCATOR)
92#if SMTG_DEBUG_CFALLOCATOR
93#include <libkern/OSAtomic.h>
98#if SMTG_DEBUG_CFALLOCATOR
99static CFAllocatorRef kCFAllocator = NULL;
101struct CFStringDebugAllocator : CFAllocatorContext
103 CFStringDebugAllocator ()
109 copyDescription =
nullptr;
110 allocate = allocateCallBack;
111 reallocate = reallocateCallBack;
112 deallocate = deallocateCallBack;
113 preferredSize = preferredSizeCallBack;
115 numAllocations = allocationSize = numDeallocations = 0;
116 cfAllocator = CFAllocatorCreate (kCFAllocatorUseContext,
this);
119 if (dladdr ((
const void*)CFStringDebugAllocator::allocateCallBack, &info))
121 moduleName = info.dli_fname;
123 kCFAllocator = cfAllocator;
126 ~CFStringDebugAllocator ()
128 kCFAllocator = kCFAllocatorDefault;
129 CFRelease (cfAllocator);
130 FDebugPrint (
"CFStringDebugAllocator (%s):\n", moduleName.text8 ());
131 FDebugPrint (
"\tNumber of allocations : %u\n", numAllocations);
132 FDebugPrint (
"\tNumber of deallocations: %u\n", numDeallocations);
133 FDebugPrint (
"\tAllocated Bytes : %u\n", allocationSize);
137 CFAllocatorRef cfAllocator;
138 volatile int64_t numAllocations;
139 volatile int64_t numDeallocations;
140 volatile int64_t allocationSize;
142 void* doAllocate (CFIndex allocSize, CFOptionFlags hint)
144 void* ptr = CFAllocatorAllocate (kCFAllocatorDefault, allocSize, hint);
145 OSAtomicIncrement64 (&numAllocations);
146 OSAtomicAdd64 (allocSize, &allocationSize);
149 void* doReallocate (
void* ptr, CFIndex newsize, CFOptionFlags hint)
151 void* newPtr = CFAllocatorReallocate (kCFAllocatorDefault, ptr, newsize, hint);
154 void doDeallocate (
void* ptr)
156 CFAllocatorDeallocate (kCFAllocatorDefault, ptr);
157 OSAtomicIncrement64 (&numDeallocations);
159 CFIndex getPreferredSize (CFIndex size, CFOptionFlags hint)
161 return CFAllocatorGetPreferredSizeForSize (kCFAllocatorDefault, size, hint);
164 static void* allocateCallBack (CFIndex allocSize, CFOptionFlags hint,
void* info)
166 return static_cast<CFStringDebugAllocator*
> (info)->doAllocate (allocSize, hint);
168 static void* reallocateCallBack (
void* ptr, CFIndex newsize, CFOptionFlags hint,
void* info)
170 return static_cast<CFStringDebugAllocator*
> (info)->doReallocate (ptr, newsize, hint);
173 static void deallocateCallBack (
void* ptr,
void* info)
175 static_cast<CFStringDebugAllocator*
> (info)->doDeallocate (ptr);
177 static CFIndex preferredSizeCallBack (CFIndex size, CFOptionFlags hint,
void* info)
179 return static_cast<CFStringDebugAllocator*
> (info)->getPreferredSize (size, hint);
182static CFStringDebugAllocator gDebugAllocator;
185static const CFAllocatorRef kCFAllocator = ::kCFAllocatorDefault;
190static void* toCFStringRef (
const Steinberg::char8* source, Steinberg::uint32 encoding)
192 if (encoding == 0xFFFF)
193 encoding = kCFStringEncodingASCII;
195 return (
void*)CFStringCreateWithCString (Steinberg::kCFAllocator, source, encoding);
197 return (
void*)CFStringCreateWithCString (Steinberg::kCFAllocator,
"", encoding);
201static bool fromCFStringRef (Steinberg::char8* dest, Steinberg::int32 destSize,
const void* cfStr, Steinberg::uint32 encoding)
204 CFRange range = {0, CFStringGetLength ((CFStringRef)cfStr)};
205 bool result = CFStringGetBytes ((CFStringRef)cfStr, range, encoding,
'?',
false, (UInt8*)dest, destSize, &usedBytes);
213static inline int stricmp16 (
const Steinberg::tchar* s1,
const Steinberg::tchar* s2)
215 return wcsicmp (Steinberg::wscast (s1), Steinberg::wscast (s2));
219static inline int strnicmp16 (
const Steinberg::tchar* s1,
const Steinberg::tchar* s2,
size_t l)
221 return wcsnicmp (Steinberg::wscast (s1), Steinberg::wscast (s2), l);
225static inline int vsnwprintf (Steinberg::char16* buffer,
size_t bufferSize,
226 const Steinberg::char16* format,
va_list args)
228 return _vsnwprintf (Steinberg::wscast (buffer), bufferSize, Steinberg::wscast (format), args);
232static inline Steinberg::int32 sprintf16 (Steinberg::char16* str,
const Steinberg::char16* format, ...)
236 return vsnwprintf (str, -1, format, marker);
252static ConverterFacet& converterFacet ()
254 static ConverterFacet gFacet;
259static Converter& converter ()
261 static Converter gConverter;
266static inline int stricasecmp (
const Steinberg::char8* s1,
const Steinberg::char8* s2)
268 return ::strcasecmp (s1, s2);
272static inline int strnicasecmp (
const Steinberg::char8* s1,
const Steinberg::char8* s2,
size_t n)
274 return ::strncasecmp (s1, s2, n);
278static inline int stricmp16 (
const Steinberg::char16* s1,
const Steinberg::char16* s2)
280 auto str1 = converter ().to_bytes (s1);
281 auto str2 = converter ().to_bytes (s2);
282 return stricasecmp (str1.data (), str2.data ());
286static inline int strnicmp16 (
const Steinberg::char16* s1,
const Steinberg::char16* s2,
int n)
288 auto str1 = converter ().to_bytes (s1);
289 auto str2 = converter ().to_bytes (s2);
290 return strnicasecmp (str1.data (), str2.data (), n);
294static inline int sprintf16 (Steinberg::char16* wcs,
const Steinberg::char16* format, ...)
296 assert (
false &&
"DEPRECATED No Linux implementation");
301static inline int vsnwprintf (Steinberg::char16* wcs,
size_t maxlen,
302 const Steinberg::char16* format,
va_list args)
304 Steinberg::char8 str8[kPrintfBufferSize];
305 auto format_utf8 = converter ().to_bytes(format);
306 auto len =
vsnprintf (str8, kPrintfBufferSize, format_utf8.data (), args);
308 auto tmp_str = converter ().from_bytes (str8, str8 + len);
309 auto target_len =
std::min (tmp_str.size (), maxlen - 1);
310 tmp_str.copy (wcs, target_len);
311 wcs[target_len] =
'\0';
313 return tmp_str.size ();
317static inline Steinberg::char16* strrchr16 (
const Steinberg::char16* str, Steinberg::char16 c)
319 assert (
false &&
"DEPRECATED No Linux implementation");
324#define tstrtoi64 strtoll
325#define stricmp strcasecmp
326#define strnicmp strncasecmp
329static inline Steinberg::int32 strnicmp16 (
const Steinberg::char16* str1,
const Steinberg::char16* str2,
size_t size)
334 CFIndex str1Len = Steinberg::strlen16 (str1);
335 CFIndex str2Len = Steinberg::strlen16 (str2);
336 if (
static_cast<CFIndex
> (size) < str2Len)
338 CFStringRef cfStr1 = CFStringCreateWithCharactersNoCopy (Steinberg::kCFAllocator, (UniChar*)str1, str1Len, kCFAllocatorNull);
339 CFStringRef cfStr2 = CFStringCreateWithCharactersNoCopy (Steinberg::kCFAllocator, (UniChar*)str2, str2Len, kCFAllocatorNull);
340 CFComparisonResult result = CFStringCompareWithOptions (cfStr1, cfStr2, CFRangeMake (0, size), kCFCompareCaseInsensitive);
345 case kCFCompareEqualTo:
return 0;
346 case kCFCompareLessThan:
return -1;
347 case kCFCompareGreaterThan:
353static inline Steinberg::int32 stricmp16 (
const Steinberg::char16* str1, CFIndex str1Len,
const Steinberg::char16* str2, CFIndex str2Len)
355 CFStringRef cfStr1 = CFStringCreateWithCharactersNoCopy (Steinberg::kCFAllocator, (UniChar*)str1, str1Len, kCFAllocatorNull);
356 CFStringRef cfStr2 = CFStringCreateWithCharactersNoCopy (Steinberg::kCFAllocator, (UniChar*)str2, str2Len, kCFAllocatorNull);
357 CFComparisonResult result = CFStringCompare (cfStr1, cfStr2, kCFCompareCaseInsensitive);
362 case kCFCompareEqualTo:
return 0;
363 case kCFCompareLessThan:
return -1;
364 case kCFCompareGreaterThan:
376static inline Steinberg::int32 stricmp16 (
const Steinberg::char16* str1,
const Steinberg::char16* str2)
378 CFIndex str1Len = Steinberg::strlen16 (str1);
379 CFIndex str2Len = Steinberg::strlen16 (str2);
380 return stricmp16 (str1, str1Len, str2, str2Len);
384static inline Steinberg::char16* strrchr16 (
const Steinberg::char16* str, Steinberg::char16 c)
390 return const_cast<Steinberg::char16*
>(str + len);
397static inline Steinberg::int32 vsnwprintf (Steinberg::char16* str, Steinberg::int32 size,
const Steinberg::char16* format,
va_list ap)
400 CFMutableStringRef formatString = (CFMutableStringRef)
Steinberg::ConstString (format).toCFStringRef (0xFFFF,
true);
401 CFStringFindAndReplace (formatString, CFSTR(
"%s"), CFSTR(
"%S"), CFRangeMake (0, CFStringGetLength (formatString)), 0);
402 CFStringRef resultString = CFStringCreateWithFormatAndArguments (Steinberg::kCFAllocator, 0, formatString, ap);
403 CFRelease (formatString);
407 res.fromCFStringRef (resultString);
408 res.copyTo16 (str, 0, size);
409 CFRelease (resultString);
416static inline Steinberg::int32 sprintf16 (Steinberg::char16* str,
const Steinberg::char16* format, ...)
420 return vsnwprintf (str, -1, format, marker);
444ConstString::ConstString (
const char8* str, int32 length)
445: buffer8 ((char8*)str)
446, len (length < 0 ? (str ? static_cast<uint32> (
strlen (str)) : 0) : length)
452ConstString::ConstString (
const char16* str, int32 length)
453: buffer16 ((char16*)str)
454, len (length < 0 ? (str ? strlen16 (str) : 0) : length)
460ConstString::ConstString (
const ConstString& str, int32 offset, int32 length)
462, len (length < 0 ? (str.len - (offset > 0 ? offset : 0)) : length)
480 switch (var.getType ())
482 case FVariant::kString8:
483 buffer8 = (char8*)var.getString8 ();
484 len = buffer8 ? strlen8 (buffer8) : 0;
488 case FVariant::kString16:
489 buffer16 = (char16*)var.getString16 ();
490 len = buffer16 ? strlen16 (buffer16) : 0;
497ConstString::ConstString ()
512 char8 src[] = {c, 0};
513 char16 dest[2] = {0};
515 return buffer16[index] == dest[0];
518 return buffer8[index] == c;
522bool ConstString::testChar16 (uint32 index, char16 c)
const
529 char16 src[] = {c, 0};
532 return buffer8[index] == dest[0];
535 return buffer16[index] == c;
544 if (len == 0|| idx >= len)
547 if ((idx + n > len) || n < 0)
551 result.
assign (buffer16 + idx, n);
553 result.
assign (buffer8 + idx, n);
559int32 ConstString::copyTo8 (char8* str, uint32 idx, int32 n)
const
567 if (tmp.toMultiByte () ==
false)
569 return tmp.copyTo8 (str, idx, n);
572 if (
isEmpty () || idx >= len || !buffer8)
578 if ((idx + n > len) || n < 0)
581 memcpy (str, &(buffer8[idx]), n *
sizeof (char8));
587int32 ConstString::copyTo16 (char16* str, uint32 idx, int32 n)
const
594 String tmp (
text8 ());
595 if (tmp.toWideString () ==
false)
597 return tmp.copyTo16 (str, idx, n);
600 if (
isEmpty () || idx >= len || !buffer16)
606 if ((idx + n > len) || n < 0)
609 memcpy (str, &(buffer16[idx]), n *
sizeof (char16));
615int32 ConstString::copyTo (tchar* str, uint32 idx, int32 n)
const
618 return copyTo16 (str, idx, n);
620 return copyTo8 (str, idx, n);
629 result->setText (
text8 ());
636 iStr->setText16 (
text16 ());
642 result->setText (tmp.
text8 ());
648void ConstString::copyTo (
IString&
string)
const
651 string.setText16 (
text16 ());
653 string.setText8 (
text8 ());
673 if (!isWide && !str.isWide)
677 if (isCaseSensitive (mode))
678 return strcmp (*
this, str);
679 return stricmp (*
this, str);
681 if (isCaseSensitive (mode))
682 return strncmp (*
this, str, n);
683 return strnicmp (*
this, str, n);
685 if (isWide && str.isWide)
689 if (isCaseSensitive (mode))
690 return strcmp16 (*
this, str);
691 return stricmp16 (*
this, str);
693 if (isCaseSensitive (mode))
694 return strncmp16 (*
this, str, n);
695 return strnicmp16 (*
this, str, n);
703 return compare (str, -1, mode);
721 if (!isWide && !str.isWide)
723 char8* toCompare = buffer8;
737 if (isCaseSensitive (mode))
738 return strcmp (toCompare, str);
739 return stricmp (toCompare, str);
741 if (isCaseSensitive (mode))
742 return strncmp (toCompare, str, n);
743 return strnicmp (toCompare, str, n);
745 if (isWide && str.isWide)
747 char16* toCompare = buffer16;
761 if (isCaseSensitive (mode))
762 return strcmp16 (toCompare, str.
text16 ());
763 return stricmp16 (toCompare, str.
text16 ());
765 if (isCaseSensitive (mode))
766 return strncmp16 (toCompare, str.
text16 (), n);
767 return strnicmp16 (toCompare, str.
text16 (), n);
781 return tmp.
compareAt (index, str, n, mode);
785Steinberg::int32 ConstString::naturalCompare (
const ConstString& str, CompareMode mode )
const
796 if (!isWide && !str.isWide)
797 return strnatcmp8 (buffer8, str.
text8 (), isCaseSensitive (mode));
798 if (isWide && str.isWide)
799 return strnatcmp16 (buffer16, str.
text16 (), isCaseSensitive (mode));
803 String tmp (str.
text8 ());
805 return strnatcmp16 (buffer16, tmp.text16 (), isCaseSensitive (mode));
807 String tmp (
text8 ());
809 return strnatcmp16 (tmp.text16 (), str.
text16 (), isCaseSensitive (mode));
827 if (!isWide && !str.isWide)
829 if (isCaseSensitive (mode))
831 return strnicmp (buffer8, str.buffer8, str.
length ()) == 0;
833 if (isWide && str.isWide)
835 if (isCaseSensitive (mode))
836 return strncmp16 (buffer16, str.buffer16, str.
length ()) == 0;
837 return strnicmp16 (buffer16, str.buffer16, str.
length ()) == 0;
845 if (isCaseSensitive (mode))
846 return strncmp16 (buffer16, tmp.buffer16, tmp.
length ()) == 0;
847 return strnicmp16 (buffer16, tmp.buffer16, tmp.
length ()) == 0;
853 if (isCaseSensitive (mode))
854 return strncmp16 (tmp.buffer16, str.buffer16, str.
length ()) == 0;
855 return strnicmp16 (tmp.buffer16, str.buffer16, str.
length ()) == 0;
873 if (!isWide && !str.isWide)
875 if (isCaseSensitive (mode))
877 return strnicmp (buffer8 + (
length () - str.
length ()), str.buffer8, str.
length ()) == 0;
879 if (isWide && str.isWide)
881 if (isCaseSensitive (mode))
882 return strncmp16 (buffer16 + (
length () - str.
length ()), str.buffer16, str.
length ()) == 0;
883 return strnicmp16 (buffer16 + (
length () - str.
length ()), str.buffer16, str.
length ()) == 0;
891 if (isCaseSensitive (mode))
892 return strncmp16 (buffer16 + (
length () - tmp.
length ()), tmp.buffer16, tmp.
length ()) == 0;
893 return strnicmp16 (buffer16 + (
length () - tmp.
length ()), tmp.buffer16, tmp.
length ()) == 0;
899 if (isCaseSensitive (mode))
900 return strncmp16 (tmp.buffer16 + (tmp.
length () - str.
length ()), str.buffer16, str.
length ()) == 0;
901 return strnicmp16 (tmp.buffer16 + (tmp.
length () - str.
length ()), str.buffer16, str.
length ()) == 0;
907 return findFirst (str, -1, m) != -1;
911int32 ConstString::findNext (int32 startIndex,
const ConstString& str, int32 n, CompareMode mode, int32 endIndex)
const
913 uint32 endLength = len;
914 if (endIndex > -1 && (uint32)endIndex < len)
915 endLength = endIndex + 1;
917 if (isWide && str.isWide)
922 uint32 stringLength = str.
length ();
923 n = n < 0 ? stringLength : Min<uint32> (n, stringLength);
929 if (isCaseSensitive (mode))
931 for (i = startIndex; i < endLength; i++)
932 if (strncmp16 (buffer16 + i, str, n) == 0)
937 for (i = startIndex; i < endLength; i++)
938 if (strnicmp16 (buffer16 + i, str, n) == 0)
944 if (!isWide && !str.isWide)
946 uint32 stringLength = str.
length ();
947 n = n < 0 ? stringLength : Min<uint32> (n, stringLength);
956 if (isCaseSensitive (mode))
958 for (i = startIndex; i < endLength; i++)
959 if (strncmp (buffer8 + i, str, n) == 0)
964 for (i = startIndex; i < endLength; i++)
965 if (strnicmp (buffer8 + i, str, n) == 0)
976 return findNext (startIndex, tmp, n , mode, endIndex);
980 return tmp.findNext (startIndex, str, n, mode, endIndex);
984int32 ConstString::findNext (int32 startIndex, char8 c, CompareMode mode, int32 endIndex)
const
986 uint32 endLength = len;
987 if (endIndex > -1 && (uint32)endIndex < len)
988 endLength = endIndex + 1;
992 char8 src[] = {c, 0};
993 char16 dest[8] = {0};
995 return findNext (startIndex, dest[0], mode, endIndex);
1003 if (isCaseSensitive (mode))
1005 for (i = startIndex; i < endLength; i++)
1007 if (buffer8[i] == c)
1014 for (i = startIndex; i < endLength; i++)
1016 if (
toLower (buffer8[i]) == c)
1024int32 ConstString::findNext (int32 startIndex, char16 c, CompareMode mode, int32 endIndex)
const
1026 uint32 endLength = len;
1027 if (endIndex > -1 && (uint32)endIndex < len)
1028 endLength = endIndex + 1;
1032 char16 src[] = {c, 0};
1033 char8 dest[8] = {0};
1035 return findNext (startIndex, dest[0], mode, endIndex);
1044 if (isCaseSensitive (mode))
1046 for (i = startIndex; i < endLength; i++)
1048 if (buffer16[i] == c)
1055 for (i = startIndex; i < endLength; i++)
1057 if (
toLower (buffer16[i]) == c)
1065int32 ConstString::findPrev (int32 startIndex, char8 c, CompareMode mode)
const
1072 char8 src[] = {c, 0};
1073 char16 dest[8] = {0};
1075 return findPrev (startIndex, dest[0], mode);
1079 if (startIndex < 0 || startIndex > (int32)len)
1084 if (isCaseSensitive (mode))
1086 for (i = startIndex; i >= 0; i--)
1088 if (buffer8[i] == c)
1095 for (i = startIndex; i >= 0; i--)
1097 if (
toLower (buffer8[i]) == c)
1105int32 ConstString::findPrev (int32 startIndex, char16 c, CompareMode mode)
const
1112 char16 src[] = {c, 0};
1113 char8 dest[8] = {0};
1115 return findPrev (startIndex, dest[0], mode);
1120 if (startIndex < 0 || startIndex > (int32)len)
1125 if (isCaseSensitive (mode))
1127 for (i = startIndex; i >= 0; i--)
1129 if (buffer16[i] == c)
1136 for (i = startIndex; i >= 0; i--)
1138 if (
toLower (buffer16[i]) == c)
1146int32 ConstString::findPrev (int32 startIndex,
const ConstString& str, int32 n, CompareMode mode)
const
1148 if (isWide && str.isWide)
1150 uint32 stringLength = str.length ();
1151 n = n < 0 ? stringLength : Min<uint32> (n, stringLength);
1153 if (startIndex < 0 || startIndex >= (int32)len)
1154 startIndex = len - 1;
1160 if (isCaseSensitive (mode))
1162 for (i = startIndex; i >= 0; i--)
1163 if (strncmp16 (buffer16 + i, str, n) == 0)
1168 for (i = startIndex; i >= 0; i--)
1169 if (strnicmp16 (buffer16 + i, str, n) == 0)
1175 if (!isWide && !str.isWide)
1177 uint32 stringLength = str.length ();
1178 n = n < 0 ? stringLength : Min<uint32> (n, stringLength);
1180 if (startIndex < 0 || startIndex >= (int32)len)
1181 startIndex = len - 1;
1187 if (isCaseSensitive (mode))
1189 for (i = startIndex; i >= 0; i--)
1190 if (strncmp (buffer8 + i, str, n) == 0)
1195 for (i = startIndex; i >= 0; i--)
1196 if (strnicmp (buffer8 + i, str, n) == 0)
1204 String tmp (str.text8 ());
1205 tmp.toWideString ();
1206 return findPrev (startIndex, tmp, n, mode);
1208 String tmp (
text8 ());
1209 tmp.toWideString ();
1210 return tmp.findPrev (startIndex, str, n, mode);
1218 char8 src[] = {c, 0};
1219 char16 dest[8] = {0};
1226 int32 next = startIndex;
1229 next = findNext (next, c, mode);
1246 char16 src[] = {c, 0};
1247 char8 dest[8] = {0};
1254 int32
next = startIndex;
1257 next = findNext (next, c, mode);
1272 if (str.isWide != isWide)
1289 uint32 len2 = str.len;
1294 if (isCaseSensitive (mode))
1296 for (i = 0; i <= len1 && i <= len2; i++)
1298 if (buffer16[i] != str.buffer16[i])
1304 for (i = 0; i <= len1 && i <= len2; i++)
1313 if (isCaseSensitive (mode))
1315 for (i = 0; i <= len1 && i <= len2; i++)
1317 if (buffer8[i] != str.buffer8[i])
1323 for (i = 0; i <= len1 && i <= len2; i++)
1336 if (
isEmpty () || offset >= len)
1340 return scanInt64_16 (buffer16 + offset, value, scanToEnd);
1341 return scanInt64_8 (buffer8 + offset, value, scanToEnd);
1347 if (
isEmpty () || offset >= len)
1352 return scanUInt64_8 (buffer8 + offset, value, scanToEnd);
1358 if (
isEmpty () || offset >= len)
1362 return scanHex_16 (buffer16 + offset, value, scanToEnd);
1363 return scanHex_8 (buffer8 + offset, value, scanToEnd);
1369 if (
isEmpty () || offset >= len)
1373 return scanInt32_16 (buffer16 + offset, value, scanToEnd);
1374 return scanInt32_8 (buffer8 + offset, value, scanToEnd);
1380 if (
isEmpty () || offset >= len)
1385 return scanUInt32_8 (buffer8 + offset, value, scanToEnd);
1393 if (
sscanf (
text,
"%" FORMAT_INT64A, &value) == 1)
1395 if (scanToEnd ==
false)
1419 if (
sscanf (
text,
"%" FORMAT_UINT64A, &value) == 1)
1421 if (scanToEnd ==
false)
1471 if (scanToEnd ==
false)
1485 return scanHex_8 (str, value, scanToEnd);
1503 if (
isEmpty () || offset >= len)
1510 if ((pos = str.findNext (offset, STR(
','))) >= 0 && ((uint32)pos) >= offset)
1511 str.setChar (pos, STR(
'.'));
1517 if ((pos = str.findNext (offset,
',')) >= 0 && ((uint32)pos) >= offset)
1518 str.setChar (pos,
'.');
1521 const char8* txt = str.
text8 () + offset;
1522 while (txt && txt[0])
1524 if (
sscanf (txt,
"%lf", &value) == 1)
1526 if (scanToEnd ==
false)
1537 WCHAR temp[2] = {c, 0};
1538 ::CharLowerW (temp);
1542 UniChar characters [2] = {0};
1544 CFMutableStringRef str = CFStringCreateMutableWithExternalCharactersNoCopy (kCFAllocator, characters, 1, 2, kCFAllocatorNull);
1547 CFStringLowercase (str, NULL);
1549 if (characters[1] == 0)
1550 return characters[0];
1554 assert (
false &&
"DEPRECATED No Linux implementation");
1565 WCHAR temp[2] = {c, 0};
1566 ::CharUpperW (temp);
1570 UniChar characters [2] = {0};
1572 CFMutableStringRef str = CFStringCreateMutableWithExternalCharactersNoCopy (kCFAllocator, characters, 1, 2, kCFAllocatorNull);
1575 CFStringUppercase (str, NULL);
1577 if (characters[1] == 0)
1578 return characters[0];
1582 assert (
false &&
"DEPRECATED No Linux implementation");
1592 if ((c >=
'A') && (c <=
'Z'))
1593 return c + (
'a' -
'A');
1595 CHAR temp[2] = {c, 0};
1596 ::CharLowerA (temp);
1599 return static_cast<char8
> (
tolower (c));
1606 if ((c >=
'a') && (c <=
'z'))
1607 return c - (
'a' -
'A');
1609 CHAR temp[2] = {c, 0};
1610 ::CharUpperA (temp);
1613 return static_cast<char8
> (
toupper (c));
1620 return isspace (character) != 0;
1651 return isalpha (character) != 0;
1663 return isalnum (character) != 0;
1675 return isdigit (character) != 0;
1687 return character >= 0;
1693 return character < 128;
1697bool ConstString::isCharUpper (char8 character)
1699 return toUpper (character) == character;
1703bool ConstString::isCharUpper (char16 character)
1705 return toUpper (character) == character;
1709bool ConstString::isCharLower (char8 character)
1711 return toLower (character) == character;
1715bool ConstString::isCharLower (char16 character)
1717 return toLower (character) == character;
1723 if (
isEmpty () || index >= len)
1737 int32 endIndex = len - 1;
1739 while (
isDigit ((uint32) i) && i >= 0)
1745 if (width > 0 && (endIndex - i !=
static_cast<int32
> (width)))
1771void ConstString::toVariant (
FVariant& var)
const
1775 var.setString16 (buffer16);
1779 var.setString8 (buffer8);
1789 for (i = 0; i < len; i++)
1795 for (i = 0; i < len; i++)
1804uint32 kDefaultSystemEncoding = kCFStringEncodingMacRoman;
1806static CFStringEncoding MBCodePageToCFStringEncoding (uint32 codePage)
1810 case kCP_ANSI:
return kDefaultSystemEncoding;
1812 case kCP_ANSI_WEL:
return kCFStringEncodingWindowsLatin1;
1813 case kCP_MAC_CEE:
return kCFStringEncodingMacCentralEurRoman;
1814 case kCP_Utf8:
return kCFStringEncodingUTF8;
1815 case kCP_ShiftJIS:
return kCFStringEncodingShiftJIS_X0213_00;
1818 return kCFStringEncodingASCII;
1825 if (source ==
nullptr || source[0] == 0)
1827 if (dest && charCount > 0)
1835 result = MultiByteToWideChar (sourceCodePage, MB_ERR_INVALID_CHARS, source, -1, wscast (dest), charCount);
1840 (CFStringRef)::toCFStringRef (source, MBCodePageToCFStringEncoding (sourceCodePage));
1843 CFRange range = {0, CFStringGetLength (cfStr)};
1845 if (CFStringGetBytes (cfStr, range, kCFStringEncodingUnicode,
' ',
false, (UInt8*)dest,
1846 charCount * 2, &usedBytes) > 0)
1848 result =
static_cast<int32
> (usedBytes / 2 + 1);
1850 dest[usedBytes / 2] = 0;
1860 if (dest ==
nullptr)
1864 result = converterFacet ().length (state, source, source +
strlen (source), maxChars);
1868 auto utf16Str = converter ().from_bytes (source);
1869 if (!utf16Str.empty ())
1871 result = std::min<int32> (charCount, utf16Str.size ());
1872 memcpy (dest, utf16Str.data (), result * sizeof (char16));
1879 assert (
false &&
"DEPRECATED No Linux implementation");
1892 return WideCharToMultiByte (destCodePage, 0, wscast (wideString), -1, dest, charCount,
nullptr,
nullptr);
1896 if (wideString != 0)
1900 CFStringRef cfStr = CFStringCreateWithCharactersNoCopy (kCFAllocator, (
const UniChar*)wideString, strlen16 (wideString), kCFAllocatorNull);
1903 if (fromCFStringRef (dest, charCount, cfStr, MBCodePageToCFStringEncoding (destCodePage)))
1904 result =
static_cast<int32
> (
strlen (dest) + 1);
1910 return static_cast<int32
> (CFStringGetMaximumSizeForEncoding (strlen16 (wideString), MBCodePageToCFStringEncoding (destCodePage)));
1919 if (dest ==
nullptr)
1921 auto maxChars = charCount ? charCount : tstrlen (wideString);
1922 result = converterFacet ().max_length () * maxChars;
1926 auto utf8Str = converter ().to_bytes (wideString);
1927 if (!utf8Str.empty ())
1929 result = std::min<int32> (charCount, utf8Str.size ());
1930 memcpy (dest, utf8Str.data (), result * sizeof (char8));
1937 if (dest ==
nullptr)
1939 result = strlen16 (wideString) + 1;
1944 for (; i < charCount; ++i)
1946 if (wideString[i] == 0)
1948 if (wideString[i] <= 0x007F)
1949 dest[i] = wideString[i];
1959 assert (
false &&
"DEPRECATED No Linux implementation");
1964 assert (
false &&
"DEPRECATED No Linux implementation");
1973 if (isWide ==
false)
1980 uint32 normCharCount =
static_cast<uint32
> (FoldString (MAP_PRECOMPOSED, wscast (buffer16), len,
nullptr, 0));
1981 return (normCharCount == len);
1990 CFStringRef cfStr = (CFStringRef)toCFStringRef ();
1991 CFIndex charCount = CFStringGetLength (cfStr);
1993 return (charCount == len);
2004 isWide = kWideStringDefault ? 1 : 0;
2008String::String (
const char8* str,
MBCodePage codePage, int32 n,
bool isTerminated)
2013 if (isTerminated && n >= 0 && str[n] != 0)
2016 isTerminated =
false;
2021 assign (str, n, isTerminated);
2027 n =
static_cast<int32
> (
strlen (str));
2029 _toWideString (str, n, codePage);
2035String::String (
const char8* str, int32 n,
bool isTerminated)
2038 assign (str, n, isTerminated);
2042String::String (
const char16* str, int32 n,
bool isTerminated)
2046 assign (str, n, isTerminated);
2068 isWide = kWideStringDefault ? 1 : 0;
2089#if SMTG_CPP11_STDLIBSUPPORT
2091String::String (String&& str)
2093 *
this = std::move (str);
2099 SMTG_ASSERT (buffer ==
nullptr || buffer != str.buffer);
2102 isWide = str.isWide;
2103 buffer = str.buffer;
2105 str.buffer =
nullptr;
2115 len = strlen16 (
text16 ());
2117 len = strlen8 (
text8 ());
2123 if (!isWide && buffer8 && len > 0)
2124 return _toWideString (buffer8, len, sourceCodePage);
2130bool String::_toWideString (
const char8* src, int32 length, uint32 sourceCodePage)
2139 bytesNeeded +=
sizeof (char16);
2140 char16* newStr = (char16*)malloc (bytesNeeded);
2163#define SMTG_STRING_CHECK_CONVERSION 1
2164#define SMTG_STRING_CHECK_CONVERSION_NO_BREAK 1
2166#if SMTG_STRING_CHECK_CONVERSION_NO_BREAK
2167 #define SMTG_STRING_CHECK_MSG FDebugPrint
2169 #define SMTG_STRING_CHECK_MSG FDebugBreak
2172bool String::checkToMultiByte (uint32 destCodePage)
const
2177#if DEVELOPMENT && SMTG_STRING_CHECK_CONVERSION
2178 int debugLen =
length ();
2179 int debugNonASCII = 0;
2180 for (int32 i = 0; i <
length (); i++)
2182 if (buffer16[i] > 127)
2186 String* backUp =
nullptr;
2187 if (debugNonASCII > 0)
2188 backUp = NEW String (*
this);
2192 bool result =
const_cast <String&
> (*this).toMultiByte (destCodePage);
2194#if DEVELOPMENT && SMTG_STRING_CHECK_CONVERSION
2197 String temp (*
this);
2198 temp.toWideString (destCodePage);
2200 if (temp != *backUp)
2202 backUp->toMultiByte (kCP_Utf8);
2203 SMTG_STRING_CHECK_MSG (
"Indirect string conversion information loss ! %d/%d non ASCII chars: \"%s\" -> \"%s\"\n", debugNonASCII, debugLen, backUp->buffer8, buffer8);
2206 SMTG_STRING_CHECK_MSG (
"Indirect string potential conversion information loss ! %d/%d non ASCII chars result: \"%s\"\n", debugNonASCII, debugLen, buffer8);
2216bool String::toMultiByte (uint32 destCodePage)
2220 if (buffer16 && len > 0)
2223 char8* newStr = (char8*) malloc (numChars *
sizeof (char8));
2236 else if (destCodePage != kCP_Default)
2240 return toMultiByte (destCodePage);
2249 _toWideString (utf8String,
static_cast<int32
> (
strlen (utf8String)),
kCP_Utf8);
2255 if (isWide ==
false)
2258 if (buffer16 ==
nullptr)
2266 uint32 normCharCount =
static_cast<uint32
> (FoldString (MAP_PRECOMPOSED, wscast (buffer16), len,
nullptr, 0));
2267 if (normCharCount == len)
2270 char16* newString = (char16*)
malloc ((normCharCount + 1) *
sizeof (char16));
2271 uint32 converterCount =
static_cast<uint32
> (FoldString (MAP_PRECOMPOSED, wscast (buffer16), len, wscast (newString), normCharCount + 1));
2272 if (converterCount != normCharCount)
2277 newString [converterCount] = 0;
2279 buffer16 = newString;
2287 CFMutableStringRef origStr = (CFMutableStringRef)toCFStringRef (0xFFFF,
true);
2290 CFStringNormalizationForm normForm = kCFStringNormalizationFormD;
2293 case kUnicodeNormC: normForm = kCFStringNormalizationFormC;
break;
2294 case kUnicodeNormD: normForm = kCFStringNormalizationFormD;
break;
2295 case kUnicodeNormKC: normForm = kCFStringNormalizationFormKC;
break;
2296 case kUnicodeNormKD: normForm = kCFStringNormalizationFormKD;
break;
2298 CFStringNormalize (origStr, normForm);
2299 bool result = fromCFStringRef (origStr);
2300 CFRelease (origStr);
2310void String::tryFreeBuffer ()
2320bool String::resize (uint32 newLength,
bool wide,
bool fill)
2326 isWide = wide ? 1 : 0;
2330 size_t newCharSize = wide ?
sizeof (char16) : sizeof (char8);
2331 size_t oldCharSize = (isWide != 0) ?
sizeof (char16) :
sizeof (char8);
2333 size_t newBufferSize = (newLength + 1) * newCharSize;
2334 size_t oldBufferSize = (len + 1) * oldCharSize;
2336 isWide = wide ? 1 : 0;
2340 if (newBufferSize != oldBufferSize)
2342 void* newstr =
realloc (buffer, newBufferSize);
2343 if (newstr ==
nullptr)
2347 buffer16[newLength] = 0;
2349 buffer8[newLength] = 0;
2351 else if (wide && newCharSize != oldCharSize)
2352 buffer16[newLength] = 0;
2356 void* newstr =
malloc (newBufferSize);
2357 if (newstr ==
nullptr)
2363 buffer16[newLength] = 0;
2368 buffer8[newLength] = 0;
2372 if (fill && len < newLength && buffer)
2377 for (uint32 i = len; i < newLength; i++)
2382 memset (buffer8 + len,
' ', newLength - len);
2390bool String::setChar8 (uint32 index, char8 c)
2392 if (index == len && c == 0)
2399 if (resize (index, isWide,
true) ==
false)
2405 if (resize (index + 1, isWide,
true) ==
false)
2410 if (index < len && buffer)
2415 buffer16[index] = 0;
2418 char8 src[] = {c, 0};
2419 char16 dest[8] = {0};
2421 buffer16[index] = dest[0];
2440bool String::setChar16 (uint32 index, char16 c)
2442 if (index == len && c == 0)
2449 if (resize (index, isWide,
true) ==
false)
2454 if (resize (index + 1, isWide,
true) ==
false)
2459 if (index < len && buffer)
2463 buffer16[index] = c;
2469 char16 src[] = {c, 0};
2470 char8 dest[8] = {0};
2472 buffer8[index] = dest[0];
2501 uint32 stringLength = (uint32)((str) ?
strlen (str) : 0);
2502 n = n < 0 ? stringLength : Min<uint32> (n, stringLength);
2507 if (resize (n,
false))
2509 if (buffer8 && n > 0 && str)
2511 memcpy (buffer8, str, n *
sizeof (char8));
2523 if (str == buffer16)
2528 uint32 stringLength = (uint32)((str) ? strlen16 (str) : 0);
2529 n = n < 0 ? stringLength : Min<uint32> (n, stringLength);
2534 if (resize (n,
true))
2536 if (buffer16 && n > 0 && str)
2538 memcpy (buffer16, str, n *
sizeof (char16));
2550 if (resize (n,
false))
2552 if (buffer8 && n > 0)
2554 memset (buffer8, c, n *
sizeof (char8));
2567 if (resize (n,
true))
2569 if (buffer && n > 0)
2571 for (int32 i = 0; i < n; i++)
2604 return append (tmp.buffer16, n);
2607 uint32 stringLength = (uint32)((str) ?
strlen (str) : 0);
2608 n = n < 0 ? stringLength : Min<uint32> (n, stringLength);
2612 int32 newlen = n + len;
2613 if (!resize (newlen,
false))
2618 memcpy (buffer8 + len, str, n *
sizeof (char8));
2630 if (str == buffer16)
2642 uint32 stringLength = (uint32)((str) ? strlen16 (str) : 0);
2643 n = n < 0 ? stringLength : Min<uint32> (n, stringLength);
2647 int32 newlen = n + len;
2648 if (!resize (newlen,
true))
2651 if (buffer16 && str)
2653 memcpy (buffer16 + len, str, n *
sizeof (char16));
2665 char8 str[] = {c, 0};
2678 return append (tmp.buffer16[0], n);
2681 int32 newlen = n + len;
2682 if (!resize (newlen,
false))
2687 memset (buffer8 + len, c, n *
sizeof (char8));
2701 char16 str[] = {c, 0};
2712 int32 newlen = n + len;
2713 if (!resize (newlen,
true))
2718 for (int32 i = len; i < newlen; i++)
2747 return insertAt (idx, tmp.buffer16, n);
2750 uint32 stringLength = (uint32)((str) ?
strlen (str) : 0);
2751 n = n < 0 ? stringLength : Min<uint32> (n, stringLength);
2755 int32 newlen = len + n;
2756 if (!resize (newlen,
false))
2762 memmove (buffer8 + idx + n, buffer8 + idx, (len - idx) *
sizeof (char8));
2763 memcpy (buffer8 + idx, str, n *
sizeof (char8));
2784 uint32 stringLength = (uint32)((str) ? strlen16 (str) : 0);
2785 n = n < 0 ? stringLength : Min<uint32> (n, stringLength);
2789 int32 newlen = len + n;
2790 if (!resize (newlen,
true))
2796 memmove (buffer16 + idx + n, buffer16 + idx, (len - idx) *
sizeof (char16));
2797 memcpy (buffer16 + idx, str, n *
sizeof (char16));
2819 if (idx > len || str ==
nullptr)
2827 if (tmp.
length () == 0 || n2 == 0)
2829 return replace (idx, n1, tmp.buffer16, n2);
2832 if (n1 < 0 || idx + n1 > len)
2837 uint32 stringLength = (uint32)((str) ?
strlen (str) : 0);
2838 n2 = n2 < 0 ? stringLength : Min<uint32> (n2, stringLength);
2840 uint32 newlen = len - n1 + n2;
2842 if (!resize (newlen,
false))
2847 memmove (buffer8 + idx + n2, buffer8 + idx + n1, (len - (idx + n1)) *
sizeof (char8));
2848 memcpy (buffer8 + idx, str, n2 *
sizeof (char8));
2849 buffer8[newlen] = 0;
2860 if (idx > len || str ==
nullptr)
2869 if (n1 < 0 || idx + n1 > len)
2874 uint32 stringLength = (uint32)((str) ? strlen16 (str) : 0);
2875 n2 = n2 < 0 ? stringLength : Min<uint32> (n2, stringLength);
2877 uint32 newlen = len - n1 + n2;
2879 if (!resize (newlen,
true))
2884 memmove (buffer16 + idx + n2, buffer16 + idx + n1, (len - (idx + n1)) *
sizeof (char16));
2885 memcpy (buffer16 + idx, str, n2 *
sizeof (char16));
2886 buffer16[newlen] = 0;
2897 if (toReplace ==
nullptr || toReplaceWith ==
nullptr)
2902 int32 idx = findFirst (toReplace, -1, m);
2905 int32 toReplaceLen =
static_cast<int32
> (
strlen (toReplace));
2906 int32 toReplaceWithLen =
static_cast<int32
> (
strlen (toReplaceWith));
2909 replace (idx, toReplaceLen, toReplaceWith, toReplaceWithLen);
2913 idx = findNext (idx + toReplaceWithLen , toReplace, -1, m);
2925 if (toReplace ==
nullptr || toReplaceWith ==
nullptr)
2930 int32 idx = findFirst (toReplace, -1, m);
2933 int32 toReplaceLen = strlen16 (toReplace);
2934 int32 toReplaceWithLen = strlen16 (toReplaceWith);
2937 replace (idx, toReplaceLen, toReplaceWith, toReplaceWithLen);
2941 idx = findNext (idx + toReplaceWithLen, toReplace, -1, m);
2951static bool performReplace (T* str,
const T* toReplace, T toReplaceBy)
2953 bool anyReplace =
false;
2957 const T* rep = toReplace;
2981 String toReplaceW (toReplace);
2985 char8 src[] = {toReplaceBy, 0};
2986 char16 dest[2] = {0};
2989 return replaceChars16 (toReplaceW.
text16 (), dest[0]);
2994 if (toReplaceBy == 0)
2997 return performReplace<char8> (buffer8, toReplace, toReplaceBy);
3001bool String::replaceChars16 (
const char16* toReplace, char16 toReplaceBy)
3008 String toReplaceA (toReplace);
3009 if (toReplaceA.toMultiByte () ==
false)
3012 if (toReplaceA.length () > 1)
3014 SMTG_WARNING(
"cannot replace non ASCII chars on non Wide String")
3018 char16 src[] = {toReplaceBy, 0};
3019 char8 dest[8] = {0};
3026 if (toReplaceBy == 0)
3027 toReplaceBy =
STR16 (
' ');
3029 return performReplace<char16> (buffer16, toReplace, toReplaceBy);
3037 if (
isEmpty () || idx >= len || n == 0)
3040 if ((idx + n > len) || n < 0)
3044 int32 toMove = len - idx - n;
3048 memmove (buffer16 + idx, buffer16 + idx + n, toMove *
sizeof (char16));
3050 memmove (buffer8 + idx, buffer8 + idx + n, toMove *
sizeof (char8));
3054 resize (len - n, isWide);
3061bool String::removeSubString (
const ConstString& subString,
bool allOccurences)
3063 bool removed =
false;
3064 while (!removed || allOccurences)
3066 int32 idx = findFirst (subString);
3069 remove (idx, subString.
length ());
3076template <
class T,
class F>
3077static uint32 performTrim (T* str, uint32
length, F func,
bool funcResult)
3079 uint32 toRemoveAtHead = 0;
3080 uint32 toRemoveAtTail = 0;
3084 while ((*p) && ((func (*p) != 0) == funcResult))
3087 toRemoveAtHead =
static_cast<uint32
> (p - str);
3089 if (toRemoveAtHead <
length)
3093 while (((func (*p) != 0) == funcResult) && (p > str))
3100 uint32 newLength =
length - (toRemoveAtHead + toRemoveAtTail);
3104 memmove (str, str + toRemoveAtHead, newLength *
sizeof (T));
3122 newLength = performTrim<char16> (buffer16, len,
iswspace,
true);
3124 newLength = performTrim<char8> (buffer8, len,
isspace,
true);
3129 newLength = performTrim<char16> (buffer16, len,
iswalnum,
false);
3131 newLength = performTrim<char8> (buffer8, len,
isalnum,
false);
3136 newLength = performTrim<char16> (buffer16, len,
iswalpha,
false);
3138 newLength = performTrim<char8> (buffer8, len,
isalpha,
false);
3145 if (newLength != len)
3147 resize (newLength, isWide);
3155template <
class T,
class F>
3156static uint32 performRemove (T* str, uint32
length, F func,
bool funcResult)
3162 if ((func (*p) != 0) == funcResult)
3164 size_t toMove =
length - (p - str);
3165 memmove (p, p + 1, toMove *
sizeof (T));
3185 newLength = performRemove<char16> (buffer16, len,
iswspace,
true);
3187 newLength = performRemove<char8> (buffer8, len,
isspace,
true);
3192 newLength = performRemove<char16> (buffer16, len,
iswalnum,
false);
3194 newLength = performRemove<char8> (buffer8, len,
isalnum,
false);
3199 newLength = performRemove<char16> (buffer16, len,
iswalpha,
false);
3201 newLength = performRemove<char8> (buffer8, len,
isalpha,
false);
3208 if (newLength != len)
3210 resize (newLength, isWide);
3217static uint32 performRemoveChars (T* str, uint32
length,
const T* toRemove)
3224 const T* rem = toRemove;
3237 size_t toMove =
length - (p - str);
3238 memmove (p, p + 1, toMove *
sizeof (T));
3250 if (
isEmpty () || toRemove ==
nullptr)
3261 uint32 newLength = performRemoveChars<char8> (buffer8, len, toRemove);
3263 if (newLength != len)
3265 resize (newLength,
false);
3274 if (
isEmpty () || toRemove ==
nullptr)
3280 if (str8.toMultiByte () ==
false)
3285 uint32 newLength = performRemoveChars<char16> (buffer16, len, toRemove);
3287 if (newLength != len)
3289 resize (newLength,
true);
3298 char8
string[kPrintfBufferSize];
3303 vsnprintf (
string, kPrintfBufferSize-1, format, marker);
3311 char16
string[kPrintfBufferSize];
3316 vsnwprintf (
string, kPrintfBufferSize-1, format, marker);
3323 char8
string[kPrintfBufferSize];
3325 vsnprintf (
string, kPrintfBufferSize-1, format, args);
3330String& String::vprintf (
const char16* format,
va_list args)
3332 char16
string[kPrintfBufferSize];
3334 vsnwprintf (
string, kPrintfBufferSize-1, format, args);
3339String& String::printInt64 (int64 value)
3356 static constexpr auto kMaxAfterCommaResolution = 16;
3359 if (withinInt64Boundaries && (maxPrecision == 0 ||
std::round (value) == value))
3360 return printInt64 (value);
3362 const auto absValue = std::abs (value);
3363 const uint32 valueExponent = absValue >= 1 ?
std::log10 (absValue) : -
std::log10 (absValue) + 1;
3365 maxPrecision = std::min<uint32> (kMaxAfterCommaResolution - valueExponent, maxPrecision);
3368 printf (STR (
"%s%dlf"), STR (
"%."), maxPrecision);
3370 printf (
"%s%dlf",
"%.", maxPrecision);
3378 for (int32 i =
length () - 1; i >= 0; i--)
3380 if (isWide && testChar16 (i,
'0') ||
testChar8 (i,
'0'))
3382 else if (isWide && testChar16(i,
'.') ||
testChar8(i,
'.'))
3405 if (!applyOnlyFormat)
3408 if (separator != 0 && index > 0 && testChar (index - 1, separator) ==
true)
3414 if (number < minNumber)
3421 if (separator &&
isEmpty () ==
false)
3423 sprintf16 (format,
STR16 (
"%%c%%0%uu"), width);
3424 sprintf16 (trail, format, separator, (uint32) number);
3428 sprintf16 (format,
STR16 (
"%%0%uu"), width);
3429 sprintf16 (trail, format, (uint32) number);
3435 static constexpr auto kFormatSize = 64u;
3436 static constexpr auto kTrailSize = 64u;
3437 char format[kFormatSize];
3438 char trail[kTrailSize];
3439 if (separator &&
isEmpty () ==
false)
3441 snprintf (format, kFormatSize,
"%%c%%0%uu", width);
3442 snprintf (trail, kTrailSize, format, separator, (uint32) number);
3446 snprintf (format, kFormatSize,
"%%0%uu", width);
3447 snprintf (trail, kTrailSize, format, (uint32) number);
3458 if (buffer && index < len)
3471 if (buffer && i > 0)
3476 CFMutableStringRef cfStr = CFStringCreateMutableWithExternalCharactersNoCopy (kCFAllocator, (UniChar*)buffer16, len, len+1, kCFAllocatorNull);
3477 CFStringLowercase (cfStr, NULL);
3480 char16* c = buffer16;
3503 if (buffer && index < len)
3516 if (buffer && i > 0)
3521 CFMutableStringRef cfStr = CFStringCreateMutableWithExternalCharactersNoCopy (kCFAllocator, (UniChar*)buffer16, len, len+1, kCFAllocatorNull);
3522 CFStringUppercase (cfStr, NULL);
3525 char16* c = buffer16;
3548 switch (var.getType ())
3550 case FVariant::kString8:
3551 assign (var.getString8 ());
3554 case FVariant::kString16:
3555 assign (var.getString16 ());
3558 case FVariant::kFloat:
3562 case FVariant::kInteger:
3563 printInt64 (var.getInt ());
3573void String::toVariant (
FVariant& var)
const
3577 var.setString16 (
text16 ());
3581 var.setString8 (
text8 ());
3589 if (a->
get (attrID, variant) == kResultTrue)
3595bool String::toAttributes (
IAttributes* a, IAttrID attrID)
3598 toVariant (variant);
3599 if (a->
set (attrID, variant) == kResultTrue)
3608 void* tmp = s.buffer;
3609 uint32 tmpLen = s.len;
3610 bool tmpWide = s.isWide;
3622 resize (0, other.isWide);
3623 buffer = other.buffer;
3626 other.buffer =
nullptr;
3640void* String::pass ()
3651 void* passed = pass ();
3657 var.setString16 ((
const char16*)passed);
3658 var.setOwner (
true);
3661 var.setString16 (kEmptyString16);
3667 var.setString8 ((
const char8*)passed);
3668 var.setOwner (
true);
3671 var.setString8 (kEmptyString8);
3710 resize (
length + 1,
false);
3721bool String::fromCFStringRef (
const void* cfStr, uint32 encoding)
3726 CFStringRef strRef = (CFStringRef)cfStr;
3729 CFRange range = { 0, CFStringGetLength (strRef)};
3731 if (resize (
static_cast<int32
> (range.length + 1),
true))
3733 if (encoding == 0xFFFF)
3734 encoding = kCFStringEncodingUnicode;
3735 if (CFStringGetBytes (strRef, range, encoding,
' ',
false, (UInt8*)buffer16, range.length * 2, &usedBytes) > 0)
3737 buffer16[usedBytes/2] = 0;
3738 this->len = strlen16 (buffer16);
3747 if (encoding == 0xFFFF)
3748 encoding = kCFStringEncodingASCII;
3749 int32 len =
static_cast<int32
> (CFStringGetLength (strRef) * 2);
3750 if (resize (++len,
false))
3752 if (CFStringGetCString (strRef, buffer8, len, encoding))
3754 this->len =
static_cast<int32
> (
strlen (buffer8));
3764void* ConstString::toCFStringRef (uint32 encoding,
bool mutableCFString)
const
3766 if (mutableCFString)
3768 CFMutableStringRef str = CFStringCreateMutable (kCFAllocator, 0);
3771 CFStringAppendCharacters (str, (
const UniChar *)buffer16, len);
3776 if (encoding == 0xFFFF)
3777 encoding = kCFStringEncodingASCII;
3778 CFStringAppendCString (str, buffer8, encoding);
3786 if (encoding == 0xFFFF)
3787 encoding = kCFStringEncodingUnicode;
3788 return (
void*)CFStringCreateWithBytes (kCFAllocator, (
const unsigned char*)buffer16, len * 2, encoding,
false);
3792 if (encoding == 0xFFFF)
3793 encoding = kCFStringEncodingASCII;
3795 return (
void*)CFStringCreateWithCString (kCFAllocator, buffer8, encoding);
3797 return (
void*)CFStringCreateWithCString (kCFAllocator,
"", encoding);
3806uint32 hashString8 (
const char8* s, uint32 m)
3811 for (h = 0; *s !=
'\0'; s++)
3812 h = (64 * h + *s) % m;
3818uint32 hashString16 (
const char16* s, uint32 m)
3823 for (h = 0; *s != 0; s++)
3824 h = (64 * h + *s) % m;
3830template <
class T> int32 tstrnatcmp (
const T* s1,
const T* s2,
bool caseSensitive =
true)
3832 if (s1 ==
nullptr && s2 ==
nullptr)
3843 int32 s1LeadingZeros = 0;
3849 int32 s2LeadingZeros = 0;
3856 int32 countS1Digits = 0;
3859 int32 countS2Digits = 0;
3863 if (countS1Digits != countS2Digits)
3864 return countS1Digits - countS2Digits;
3866 for (int32 i = 0; i < countS1Digits; i++)
3870 return (int32)(*s1 - *s2);
3875 if (s1LeadingZeros != s2LeadingZeros)
3876 return s1LeadingZeros - s2LeadingZeros;
3880 if (caseSensitive ==
false)
3882 T srcToUpper =
static_cast<T
> (
toupper (*s1));
3883 T dstToUpper =
static_cast<T
> (
toupper (*s2));
3884 if (srcToUpper != dstToUpper)
3885 return (int32)(srcToUpper - dstToUpper);
3887 else if (*s1 != *s2)
3888 return (int32)(*s1 - *s2);
3895 if (*s1 == 0 && *s2 == 0)
3901 return (int32)(*s1 - *s2);
3905int32 strnatcmp8 (
const char8* s1,
const char8* s2,
bool caseSensitive )
3907 return tstrnatcmp (s1, s2, caseSensitive);
3911int32 strnatcmp16 (
const char16* s1,
const char16* s2,
bool caseSensitive )
3913 return tstrnatcmp (s1, s2, caseSensitive);
3919void PLUGIN_API StringObject::setText (
const char8*
text)
virtual const char8 * text8() const
Returns pointer to string of type char8.
int32 getFirstDifferent(const ConstString &str, CompareMode=kCaseSensitive) const
Returns position of first different character.
int64 getTrailingNumber(int64 fallback=0) const
Returns result of scanInt64 or the fallback.
bool isAsciiString() const
Checks if all characters in string are in ascii range.
virtual const tchar * text() const
Returns pointer to string of type tchar.
static bool scanUInt32_16(const char16 *text, uint32 &value, bool scanToEnd=true)
Converts string of type char16 to int32 value.
static bool scanInt32_8(const char8 *text, int32 &value, bool scanToEnd=true)
Converts string of type char8 to int32 value.
static bool isCharSpace(char8 character)
Returns true if character is a space.
static bool scanUInt64_16(const char16 *text, uint64 &value, bool scanToEnd=true)
Converts string of type char16 to uint64 value.
static int32 wideStringToMultiByte(char8 *dest, const char16 *source, int32 char8Count, uint32 destCodePage=kCP_Default)
If dest is zero, this returns the maximum number of bytes needed to convert source.
@ kCaseSensitive
Comparison is done with regard to character's case.
bool endsWith(const ConstString &str, CompareMode m=kCaseSensitive) const
Check if this ends with str.
bool isDigit(uint32 index) const
Returns true if character at position is a digit.
static bool scanHex_16(const char16 *text, uint8 &value, bool scanToEnd=true)
Converts string of type char16 to hex/unit8 value.
bool testChar8(uint32 index, char8 c) const
Returns true if character is equal at position 'index'.
bool scanInt32(int32 &value, uint32 offset=0, bool scanToEnd=true) const
Converts string to int32 value starting at offset.
static bool scanHex_8(const char8 *text, uint8 &value, bool scanToEnd=true)
Converts string of type char8 to hex/unit8 value.
bool scanHex(uint8 &value, uint32 offset=0, bool scanToEnd=true) const
Converts string to hex/uint8 value starting at offset.
bool scanUInt32(uint32 &value, uint32 offset=0, bool scanToEnd=true) const
Converts string to uint32 value starting at offset.
bool extract(String &result, uint32 idx, int32 n=-1) const
Get n characters long substring starting at index (n=-1: until end)
static char8 toLower(char8 c)
Converts to lower case.
static bool isCharAlphaNum(char8 character)
Returns true if character is an alphanumeric character.
int32 countOccurences(char8 c, uint32 startIndex, CompareMode=kCaseSensitive) const
Counts occurences of c within this starting at index.
bool isWideString() const
Returns true if string is wide.
bool startsWith(const ConstString &str, CompareMode m=kCaseSensitive) const
Check if this starts with str.
int32 getTrailingNumberIndex(uint32 width=0) const
Returns start index of trailing number.
bool scanUInt64(uint64 &value, uint32 offset=0, bool scanToEnd=true) const
Converts string to uint64 value starting at offset.
bool isEmpty() const
Return true if string is empty.
static int32 multiByteToWideString(char16 *dest, const char8 *source, int32 wcharCount, uint32 sourceCodePage=kCP_Default)
If dest is zero, this returns the maximum number of bytes needed to convert source.
bool contains(const ConstString &str, CompareMode m=kCaseSensitive) const
Check if this contains str
static bool scanInt64_8(const char8 *text, int64 &value, bool scanToEnd=true)
Converts string of type char8 to int64 value.
static bool isCharAscii(char8 character)
Returns true if character is in ASCII range.
static bool scanInt64_16(const char16 *text, int64 &value, bool scanToEnd=true)
Converts string of type char16 to int64 value.
static bool isCharDigit(char8 character)
Returns true if character is a number.
static bool isCharAlpha(char8 character)
Returns true if character is an alphabetic character.
bool isNormalized(UnicodeNormalization=kUnicodeNormC)
On PC only kUnicodeNormC is working.
bool scanFloat(double &value, uint32 offset=0, bool scanToEnd=true) const
Converts string to double value starting at offset.
bool scanInt64(int64 &value, uint32 offset=0, bool scanToEnd=true) const
Converts string to int64 value starting at offset.
static bool scanUInt64_8(const char8 *text, uint64 &value, bool scanToEnd=true)
Converts string of type char8 to uint64 value.
int32 compareAt(uint32 index, const ConstString &str, int32 n=-1, CompareMode m=kCaseSensitive) const
Compare n characters of str with n characters of this starting at index (return: see above)
int32 compare(const ConstString &str, int32 n, CompareMode m=kCaseSensitive) const
Compare n characters of str with n characters of this (return: see above)
static bool scanUInt32_8(const char8 *text, uint32 &value, bool scanToEnd=true)
Converts string of type char8 to int32 value.
virtual const char16 * text16() const
Returns pointer to string of type char16.
virtual int32 length() const
Return length of string.
static char8 toUpper(char8 c)
Converts to upper case.
static bool scanInt32_16(const char16 *text, int32 &value, bool scanToEnd=true)
Converts string of type char16 to int32 value.
FUnknownPtr - automatic interface conversion and smart pointer in one.
A Value of variable type.
Object Data Archive Interface.
virtual tresult PLUGIN_API set(IAttrID attrID, const FVariant &data)=0
Store any data in the archive.
virtual tresult PLUGIN_API get(IAttrID attrID, FVariant &data)=0
Get data previously stored to the archive.
Interface to return an ascii string of variable size.
Interface to a string of variable size and encoding.
virtual bool PLUGIN_API isWideString() const =0
Returns true if the string is in unicode format, returns false if the string is ASCII.
virtual const char8 *PLUGIN_API getText8()=0
Return ASCII string.
virtual const char16 *PLUGIN_API getText16()=0
Return unicode string.
const char8 *PLUGIN_API getText8() SMTG_OVERRIDE
Return ASCII string.
void PLUGIN_API take(void *s, bool _isWide) SMTG_OVERRIDE
!Do not use this method! Early implementations take the given pointer as internal string and this wil...
void PLUGIN_API setText8(const char8 *text) SMTG_OVERRIDE
Assign ASCII string.
const char16 *PLUGIN_API getText16() SMTG_OVERRIDE
Return unicode string.
void PLUGIN_API setText16(const char16 *text) SMTG_OVERRIDE
Assign unicode string.
bool PLUGIN_API isWideString() const SMTG_OVERRIDE
Returns true if the string is in unicode format, returns false if the string is ASCII.
String & printf(const char8 *format,...)
Print formatted data into string.
String & assign(const ConstString &str, int32 n=-1)
Assign n characters of str (-1: all)
bool replaceChars8(const char8 *toReplace, char8 toReplaceBy)
Returns true when any replacement was done.
const char8 * text8() const SMTG_OVERRIDE
Returns pointer to string of type char8.
void swapContent(String &s)
Swaps ownership of the strings pointed to.
void toUpper()
Upper case the string.
bool normalize(UnicodeNormalization=kUnicodeNormC)
On PC only kUnicodeNormC is working.
bool fromAttributes(IAttributes *a, IAttrID attrID)
Assigns string from FAttributes.
bool fromVariant(const FVariant &var)
Assigns string from FVariant.
bool removeChars8(const char8 *which)
Remove all occurrences of each char in 'which'.
String & insertAt(uint32 idx, const ConstString &str, int32 n=-1)
Insert n characters of str at position idx (n=-1: all)
bool removeChars16(const char16 *which)
Remove all occurrences of each char in 'which'.
const String & fromPascalString(const unsigned char *buf)
Pascal string conversion.
bool toWideString(uint32 sourceCodePage=kCP_Default)
Converts to wide string according to sourceCodePage.
void take(String &str)
Take ownership of the string of 'str'.
unsigned char * toPascalString(unsigned char *buf)
Pascal string conversion.
String & append(const ConstString &str, int32 n=-1)
Append n characters of str to this (n=-1: all)
String & operator=(const char8 *str)
Assign from a string of type char8.
const char16 * text16() const SMTG_OVERRIDE
Returns pointer to string of type char16.
bool incrementTrailingNumber(uint32 width=2, tchar separator=STR(' '), uint32 minNumber=1, bool applyOnlyFormat=false)
Increment the trailing number if present else start with minNumber, width specifies the string width ...
String & remove(uint32 index=0, int32 n=-1)
Remove n characters from string starting at index (n=-1: until end)
void fromUTF8(const char8 *utf8String)
Assigns from UTF8 string.
void passToVariant(FVariant &var)
Pass ownership of buffer to Variant - sets Variant ownership.
bool trim(CharGroup mode=kSpace)
Trim lead/trail.
String & printFloat(double value, uint32 maxPrecision=6)
print a float into a string, trailing zeros will be trimmed
void updateLength()
Call this when the string is truncated outside (not recommended though)
void toLower()
Lower case the string.
String & replace(uint32 idx, int32 n1, const ConstString &str, int32 n2=-1)
Replace n1 characters of this (starting at idx) with n2 characters of str (n1,n2=-1: until end)
void removeChars(CharGroup mode=kSpace)
Removes all of group.
#define SMTG_ASSERT(f)
if DEVELOPMENT is not set, these macros will do nothing.
#define STR16(x)
string methods defines unicode / ASCII
@ kCP_MAC_ROMAN
Default Mac codepage.
@ kCP_ShiftJIS
Shifted Japan Industrial Standard Encoding.
@ kCP_US_ASCII
US-ASCII (7-bit).
@ kCP_Default
Default ANSI codepage.
@ kCP_MAC_CEE
Mac Central European Encoding.
@ kCP_ANSI_WEL
West European Latin Encoding.
@ kCP_ANSI
Default ANSI codepage.
@ kUnicodeNormKD
Unicode normalization form KD, compatibility decomposition.
@ kUnicodeNormKC
Unicode normalization form KC, compatibility composition.
@ kUnicodeNormD
Unicode normalization Form D, canonical decomposition.
@ kUnicodeNormC
Unicode normalization Form C, canonical composition.