LMMS
Loading...
Searching...
No Matches
fstring.cpp
Go to the documentation of this file.
1//------------------------------------------------------------------------
2// Project : SDK Base
3// Version : 1.0
4//
5// Category : Helpers
6// Filename : base/source/fstring.cpp
7// Created by : Steinberg, 2008
8// Description : String class
9//
10//-----------------------------------------------------------------------------
11// LICENSE
12// (c) 2021, Steinberg Media Technologies GmbH, All Rights Reserved
13//-----------------------------------------------------------------------------
14// Redistribution and use in source and binary forms, with or without modification,
15// are permitted provided that the following conditions are met:
16//
17// * Redistributions of source code must retain the above copyright notice,
18// this list of conditions and the following disclaimer.
19// * Redistributions in binary form must reproduce the above copyright notice,
20// this list of conditions and the following disclaimer in the documentation
21// and/or other materials provided with the distribution.
22// * Neither the name of the Steinberg Media Technologies nor the names of its
23// contributors may be used to endorse or promote products derived from this
24// software without specific prior written permission.
25//
26// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
27// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
28// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
29// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
30// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
31// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
34// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
35// OF THE POSSIBILITY OF SUCH DAMAGE.
36//-----------------------------------------------------------------------------
37
38#include "base/source/fstring.h"
39#include "base/source/fdebug.h"
42
43#include <cstdlib>
44#include <cctype>
45#include <cstdio>
46#include <cstdarg>
47#include <utility>
48
49#if SMTG_OS_WINDOWS
50#include <windows.h>
51#ifdef _MSC_VER
52#pragma warning (disable : 4244)
53#pragma warning (disable : 4267)
54#pragma warning (disable : 4996)
55
56#if DEVELOPMENT
57#include <crtdbg.h>
58
59#define malloc(s) _malloc_dbg(s, _NORMAL_BLOCK, __FILE__, __LINE__)
60#define realloc(p,s) _realloc_dbg(p,s, _NORMAL_BLOCK, __FILE__, __LINE__)
61#define free(p) _free_dbg(p, _NORMAL_BLOCK)
62
63#endif // DEVELOPMENT
64#endif // _MSC_VER
65#endif // SMTG_OS_WINDOWS
66
67#ifndef kPrintfBufferSize
68#define kPrintfBufferSize 4096
69#endif
70
71#if SMTG_OS_MACOS
72#include <CoreFoundation/CoreFoundation.h>
73#include <CoreFoundation/CFString.h>
74#include <CoreFoundation/CFStringEncodingExt.h>
75#include <wchar.h>
76
77#if defined (__GNUC__) && (__GNUC__ >= 4) && !__LP64__
78// on 32 bit Mac OS X we can safely ignore the format warnings as sizeof(int) == sizeof(long)
79#pragma GCC diagnostic ignored "-Wformat"
80#endif
81
82#define SMTG_ENABLE_DEBUG_CFALLOCATOR 0
83#define SMTG_DEBUG_CFALLOCATOR (DEVELOPMENT && SMTG_ENABLE_DEBUG_CFALLOCATOR)
84
85#if SMTG_DEBUG_CFALLOCATOR
86#include <libkern/OSAtomic.h>
87#include <dlfcn.h>
88#endif
89
90namespace Steinberg {
91#if SMTG_DEBUG_CFALLOCATOR
92static CFAllocatorRef kCFAllocator = NULL;
93
94struct CFStringDebugAllocator : CFAllocatorContext
95{
96 CFStringDebugAllocator ()
97 {
98 version = 0;
99 info = this;
100 retain = nullptr;
101 release = nullptr;
102 copyDescription = nullptr;
103 allocate = allocateCallBack;
104 reallocate = reallocateCallBack;
105 deallocate = deallocateCallBack;
106 preferredSize = preferredSizeCallBack;
107
108 numAllocations = allocationSize = numDeallocations = 0;
109 cfAllocator = CFAllocatorCreate (kCFAllocatorUseContext, this);
110
111 Dl_info info;
112 if (dladdr ((const void*)CFStringDebugAllocator::allocateCallBack, &info))
113 {
114 moduleName = info.dli_fname;
115 }
116 kCFAllocator = cfAllocator;
117 }
118
119 ~CFStringDebugAllocator ()
120 {
121 kCFAllocator = kCFAllocatorDefault;
122 CFRelease (cfAllocator);
123 FDebugPrint ("CFStringDebugAllocator (%s):\n", moduleName.text8 ());
124 FDebugPrint ("\tNumber of allocations : %u\n", numAllocations);
125 FDebugPrint ("\tNumber of deallocations: %u\n", numDeallocations);
126 FDebugPrint ("\tAllocated Bytes : %u\n", allocationSize);
127 }
128
129 String moduleName;
130 CFAllocatorRef cfAllocator;
131 volatile int64_t numAllocations;
132 volatile int64_t numDeallocations;
133 volatile int64_t allocationSize;
134
135 void* doAllocate (CFIndex allocSize, CFOptionFlags hint)
136 {
137 void* ptr = CFAllocatorAllocate (kCFAllocatorDefault, allocSize, hint);
138 OSAtomicIncrement64 (&numAllocations);
139 OSAtomicAdd64 (allocSize, &allocationSize);
140 return ptr;
141 }
142 void* doReallocate (void* ptr, CFIndex newsize, CFOptionFlags hint)
143 {
144 void* newPtr = CFAllocatorReallocate (kCFAllocatorDefault, ptr, newsize, hint);
145 return newPtr;
146 }
147 void doDeallocate (void* ptr)
148 {
149 CFAllocatorDeallocate (kCFAllocatorDefault, ptr);
150 OSAtomicIncrement64 (&numDeallocations);
151 }
152 CFIndex getPreferredSize (CFIndex size, CFOptionFlags hint)
153 {
154 return CFAllocatorGetPreferredSizeForSize (kCFAllocatorDefault, size, hint);
155 }
156
157 static void* allocateCallBack (CFIndex allocSize, CFOptionFlags hint, void* info)
158 {
159 return static_cast<CFStringDebugAllocator*> (info)->doAllocate (allocSize, hint);
160 }
161 static void* reallocateCallBack (void* ptr, CFIndex newsize, CFOptionFlags hint, void* info)
162 {
163 return static_cast<CFStringDebugAllocator*> (info)->doReallocate (ptr, newsize, hint);
164 }
165
166 static void deallocateCallBack (void* ptr, void* info)
167 {
168 static_cast<CFStringDebugAllocator*> (info)->doDeallocate (ptr);
169 }
170 static CFIndex preferredSizeCallBack (CFIndex size, CFOptionFlags hint, void* info)
171 {
172 return static_cast<CFStringDebugAllocator*> (info)->getPreferredSize (size, hint);
173 }
174};
175static CFStringDebugAllocator gDebugAllocator;
176#else
177
178static const CFAllocatorRef kCFAllocator = ::kCFAllocatorDefault;
179#endif // SMTG_DEBUG_CFALLOCATOR
180}
181
182//-----------------------------------------------------------------------------
183static void* toCFStringRef (const Steinberg::char8* source, Steinberg::uint32 encoding)
184{
185 if (encoding == 0xFFFF)
186 encoding = kCFStringEncodingASCII;
187 if (source)
188 return (void*)CFStringCreateWithCString (Steinberg::kCFAllocator, source, encoding);
189 else
190 return (void*)CFStringCreateWithCString (Steinberg::kCFAllocator, "", encoding);
191}
192
193//-----------------------------------------------------------------------------
194static bool fromCFStringRef (Steinberg::char8* dest, Steinberg::int32 destSize, const void* cfStr, Steinberg::uint32 encoding)
195{
196 CFIndex usedBytes;
197 CFRange range = {0, CFStringGetLength ((CFStringRef)cfStr)};
198 bool result = CFStringGetBytes ((CFStringRef)cfStr, range, encoding, '?', false, (UInt8*)dest, destSize, &usedBytes);
199 dest[usedBytes] = 0;
200 return result;
201}
202#endif // SMTG_OS_MACOS
203
204#if SMTG_OS_WINDOWS
205#define stricmp16 wcsicmp
206#define strnicmp16 wcsnicmp
207#define strrchr16 wcsrchr
208#define sprintf16 swprintf
209#define snprintf16 snwprintf
210#define vsnprintf16 vsnwprintf
211#define vsprintf16 wvsprintf
212#define vfprintf16 vfwprintf
213#define sscanf16 swscanf
214#define toupper16 towupper
215#define tolower16 towlower
216#define isupper16 iswupper
217#define islower16 iswlower
218#define isspace16 iswspace
219#define isalpha16 iswalpha
220#define isdigit16 iswdigit
221#define isalnum16 iswalnum
222
223#define stricmp _stricmp
224#define strnicmp _strnicmp
225#define snprintf _snprintf
226#define vsnprintf _vsnprintf
227#define snwprintf _snwprintf
228#define vsnwprintf _vsnwprintf
229
230#define wtoi _wtoi
231#define wtol _wtol
232#define wtof _wtof
233
234#elif SMTG_OS_LINUX
235#include <codecvt>
236#include <locale>
237#include <cstring>
238#include <string>
239#include <limits>
240#include <cassert>
241#include <wchar.h>
242
243using ConverterFacet = std::codecvt_utf8_utf16<char16_t>;
244using Converter = std::wstring_convert<ConverterFacet, char16_t>;
245
246//------------------------------------------------------------------------
247static ConverterFacet& converterFacet ()
248{
249 static ConverterFacet gFacet;
250 return gFacet;
251}
252
253//------------------------------------------------------------------------
254static Converter& converter ()
255{
256 static Converter gConverter;
257 return gConverter;
258}
259
260//-----------------------------------------------------------------------------
261static inline int stricasecmp (const Steinberg::char8* s1, const Steinberg::char8* s2)
262{
263 return ::strcasecmp (s1, s2);
264}
265
266//-----------------------------------------------------------------------------
267static inline int strnicasecmp (const Steinberg::char8* s1, const Steinberg::char8* s2, size_t n)
268{
269 return ::strncasecmp (s1, s2, n);
270}
271
272//-----------------------------------------------------------------------------
273static inline int stricmp16 (const Steinberg::char16* s1, const Steinberg::char16* s2)
274{
275 auto str1 = converter ().to_bytes (s1);
276 auto str2 = converter ().to_bytes (s2);
277 return stricasecmp (str1.data (), str2.data ());
278}
279
280//-----------------------------------------------------------------------------
281static inline int strnicmp16 (const Steinberg::char16* s1, const Steinberg::char16* s2, int n)
282{
283 auto str1 = converter ().to_bytes (s1);
284 auto str2 = converter ().to_bytes (s2);
285 return strnicasecmp (str1.data (), str2.data (), n);
286}
287
288//-----------------------------------------------------------------------------
289static inline int sprintf16 (Steinberg::char16* wcs, const Steinberg::char16* format, ...)
290{
291 assert(false && "DEPRECATED No Linux implementation");
292 return 0;
293}
294
295//-----------------------------------------------------------------------------
296static inline int vsnwprintf (Steinberg::char16* wcs, size_t maxlen,
297 const Steinberg::char16* format, va_list args)
298{
300 auto format_utf8 = converter ().to_bytes(format);
301 auto len = vsnprintf (str8, kPrintfBufferSize, format_utf8.data (), args);
302
303 auto tmp_str = converter ().from_bytes (str8, str8 + len);
304 auto target_len = std::min (tmp_str.size (), maxlen - 1);
305 tmp_str.copy (wcs, target_len);
306 wcs[target_len] = '\0';
307
308 return tmp_str.size ();
309}
310
311//-----------------------------------------------------------------------------
312static inline Steinberg::char16* strrchr16 (const Steinberg::char16* str, Steinberg::char16 c)
313{
314 assert(false && "DEPRECATED No Linux implementation");
315 return nullptr;
316}
317
318#elif SMTG_OS_MACOS
319#define tstrtoi64 strtoll
320#define stricmp strcasecmp
321#define strnicmp strncasecmp
322
323//-----------------------------------------------------------------------------
324static inline Steinberg::int32 strnicmp16 (const Steinberg::char16* str1, const Steinberg::char16* str2, size_t size)
325{
326 if (size == 0)
327 return 0;
328
329 CFIndex str1Len = Steinberg::strlen16 (str1);
330 CFIndex str2Len = Steinberg::strlen16 (str2);
331 if (static_cast<CFIndex> (size) < str2Len) // range is not applied to second string
332 str2Len = size;
333 CFStringRef cfStr1 = CFStringCreateWithCharactersNoCopy (Steinberg::kCFAllocator, (UniChar*)str1, str1Len, kCFAllocatorNull);
334 CFStringRef cfStr2 = CFStringCreateWithCharactersNoCopy (Steinberg::kCFAllocator, (UniChar*)str2, str2Len, kCFAllocatorNull);
335 CFComparisonResult result = CFStringCompareWithOptions (cfStr1, cfStr2, CFRangeMake (0, size), kCFCompareCaseInsensitive);
336 CFRelease (cfStr1);
337 CFRelease (cfStr2);
338 switch (result)
339 {
340 case kCFCompareEqualTo: return 0;
341 case kCFCompareLessThan: return -1;
342 case kCFCompareGreaterThan:
343 default: return 1;
344 };
345}
346
347//-----------------------------------------------------------------------------
348static inline Steinberg::int32 stricmp16 (const Steinberg::char16* str1, CFIndex str1Len, const Steinberg::char16* str2, CFIndex str2Len)
349{
350 CFStringRef cfStr1 = CFStringCreateWithCharactersNoCopy (Steinberg::kCFAllocator, (UniChar*)str1, str1Len, kCFAllocatorNull);
351 CFStringRef cfStr2 = CFStringCreateWithCharactersNoCopy (Steinberg::kCFAllocator, (UniChar*)str2, str2Len, kCFAllocatorNull);
352 CFComparisonResult result = CFStringCompare (cfStr1, cfStr2, kCFCompareCaseInsensitive);
353 CFRelease (cfStr1);
354 CFRelease (cfStr2);
355 switch (result)
356 {
357 case kCFCompareEqualTo: return 0;
358 case kCFCompareLessThan: return -1;
359 case kCFCompareGreaterThan:
360 default: return 1;
361 };
362}
363
364//-----------------------------------------------------------------------------
365static inline Steinberg::int32 stricmp16 (const Steinberg::ConstString& str1, const Steinberg::ConstString& str2)
366{
367 return stricmp16 (str1.text16 (), str1.length (), str2.text16 (), str2.length ());
368}
369
370//-----------------------------------------------------------------------------
371static inline Steinberg::int32 stricmp16 (const Steinberg::char16* str1, const Steinberg::char16* str2)
372{
373 CFIndex str1Len = Steinberg::strlen16 (str1);
374 CFIndex str2Len = Steinberg::strlen16 (str2);
375 return stricmp16 (str1, str1Len, str2, str2Len);
376}
377
378//-----------------------------------------------------------------------------
379static inline Steinberg::char16* strrchr16 (const Steinberg::char16* str, Steinberg::char16 c)
380{
382 while (len > 0)
383 {
384 if (str[len] == c)
385 return const_cast<Steinberg::char16*>(str + len);
386 len--;
387 }
388 return 0;
389}
390
391//-----------------------------------------------------------------------------
392static inline Steinberg::int32 vsnwprintf (Steinberg::char16* str, Steinberg::int32 size, const Steinberg::char16* format, va_list ap)
393{
394 // wrapped using CoreFoundation's CFString
395 CFMutableStringRef formatString = (CFMutableStringRef)Steinberg::ConstString (format).toCFStringRef (0xFFFF, true);
396 CFStringFindAndReplace (formatString, CFSTR("%s"), CFSTR("%S"), CFRangeMake (0, CFStringGetLength (formatString)), 0);
397 CFStringRef resultString = CFStringCreateWithFormatAndArguments (Steinberg::kCFAllocator, 0, formatString, ap);
398 CFRelease (formatString);
399 if (resultString)
400 {
402 res.fromCFStringRef (resultString);
403 res.copyTo16 (str, 0, size);
404 CFRelease (resultString);
405 return 0;
406 }
407 return 1;
408}
409
410//-----------------------------------------------------------------------------
411static inline Steinberg::int32 sprintf16 (Steinberg::char16* str, const Steinberg::char16* format, ...)
412{
413 va_list marker;
414 va_start (marker, format);
415 return vsnwprintf (str, -1, format, marker);
416}
417
418#endif // SMTG_OS_LINUX
419
420/*
421UTF-8 EF BB BF
422UTF-16 Big Endian FE FF
423UTF-16 Little Endian FF FE
424UTF-32 Big Endian 00 00 FE FF
425UTF-32 Little Endian FF FE 00 00
426*/
427
428namespace Steinberg {
429
430//-----------------------------------------------------------------------------
435
436//-----------------------------------------------------------------------------
437// ConstString
438//-----------------------------------------------------------------------------
440: buffer8 ((char8*)str)
441, len (length < 0 ? (str ? static_cast<uint32> (strlen (str)) : 0) : length)
442, isWide (0)
443{
444}
445
446//-----------------------------------------------------------------------------
448: buffer16 ((char16*)str)
449, len (length < 0 ? (str ? strlen16 (str) : 0) : length)
450, isWide (1)
451{
452}
453
454//-----------------------------------------------------------------------------
456: buffer (str.buffer)
457, len (length < 0 ? (str.len - (offset > 0 ? offset : 0)) : length)
458, isWide (str.isWide)
459{
460 if (offset > 0)
461 {
462 if (isWide)
463 buffer16 += offset;
464 else
465 buffer8 += offset;
466 }
467}
468
469//-----------------------------------------------------------------------------
471: buffer (nullptr)
472, len (0)
473, isWide (0)
474{
475 switch (var.getType ())
476 {
477 case FVariant::kString8:
478 buffer8 = (char8*)var.getString8 ();
479 len = buffer8 ? strlen8 (buffer8) : 0;
480 isWide = false;
481 break;
482
483 case FVariant::kString16:
484 buffer16 = (char16*)var.getString16 ();
485 len = buffer16 ? strlen16 (buffer16) : 0;
486 isWide = true;
487 break;
488 }
489}
490
491//-----------------------------------------------------------------------------
493: buffer (nullptr)
494, len (0)
495, isWide (0)
496{
497}
498
499//-----------------------------------------------------------------------------
501{
502 if (index >= len)
503 return c == 0;
504 if (isWide)
505 {
506 // make c wide
507 char8 src[] = {c, 0};
508 char16 dest[2] = {0};
509 if (multiByteToWideString (dest, src, 2) > 0)
510 return buffer16[index] == dest[0];
511 return false;
512 }
513 return buffer8[index] == c;
514}
515
516//-----------------------------------------------------------------------------
518{
519 if (index >= len)
520 return c == 0;
521 if (!isWide)
522 {
523 // make c ansi
524 char16 src[] = {c, 0};
525 char8 dest[8] = {0};
526 if (wideStringToMultiByte (dest, src, 2) > 0 && dest[1] == 0)
527 return buffer8[index] == dest[0];
528 return false;
529 }
530 return buffer16[index] == c;
531}
532
533//-----------------------------------------------------------------------------
535{
536 if (len == 0|| idx >= len)
537 return false;
538
539 if ((idx + n > len) || n < 0)
540 n = len - idx;
541
542 if (isWide)
543 result.assign (buffer16 + idx, n);
544 else
545 result.assign (buffer8 + idx, n);
546
547 return true;
548}
549
550//-----------------------------------------------------------------------------
552{
553 if (!str)
554 return 0;
555
556 if (isWide)
557 {
558 String tmp (text16 ());
559 if (tmp.toMultiByte () == false)
560 return 0;
561 return tmp.copyTo8 (str, idx, n);
562 }
563
564 if (isEmpty () || idx >= len || !buffer8)
565 {
566 str[0] = 0;
567 return 0;
568 }
569
570 if ((idx + n > len) || n < 0)
571 n = len - idx;
572
573 memcpy (str, &(buffer8[idx]), n * sizeof (char8));
574 str[n] = 0;
575 return n;
576}
577
578//-----------------------------------------------------------------------------
580{
581 if (!str)
582 return 0;
583
584 if (!isWide)
585 {
586 String tmp (text8 ());
587 if (tmp.toWideString () == false)
588 return 0;
589 return tmp.copyTo16 (str, idx, n);
590 }
591
592 if (isEmpty () || idx >= len || !buffer16)
593 {
594 str[0] = 0;
595 return 0;
596 }
597
598 if ((idx + n > len) || n < 0)
599 n = len - idx;
600
601 memcpy (str, &(buffer16[idx]), n * sizeof (char16));
602 str[n] = 0;
603 return n;
604}
605
606//-----------------------------------------------------------------------------
608{
609#ifdef UNICODE
610 return copyTo16 (str, idx, n);
611#else
612 return copyTo8 (str, idx, n);
613#endif
614}
615
616//-----------------------------------------------------------------------------
618{
619 if (isWideString () == false)
620 {
621 result->setText (text8 ());
622 }
623 else
624 {
626 if (iStr)
627 {
628 iStr->setText16 (text16 ());
629 }
630 else
631 {
632 String tmp (*this);
633 tmp.toMultiByte ();
634 result->setText (tmp.text8 ());
635 }
636 }
637}
638
639//-----------------------------------------------------------------------------
640void ConstString::copyTo (IString& string) const
641{
642 if (isWideString ())
643 string.setText16 (text16 ());
644 else
645 string.setText8 (text8 ());
646}
647
648
649
650//-----------------------------------------------------------------------------
652{
653 if (n == 0)
654 return 0;
655
656 if (str.isEmpty ())
657 {
658 if (isEmpty ())
659 return 0;
660 return 1;
661 }
662 else if (isEmpty ())
663 return -1;
664
665 if (!isWide && !str.isWide)
666 {
667 if (n < 0)
668 {
669 if (isCaseSensitive (mode))
670 return strcmp (*this, str);
671 else
672 return stricmp (*this, str);
673 }
674 else
675 {
676 if (isCaseSensitive (mode))
677 return strncmp (*this, str, n);
678 else
679 return strnicmp (*this, str, n);
680 }
681 }
682 else if (isWide && str.isWide)
683 {
684 if (n < 0)
685 {
686 if (isCaseSensitive (mode))
687 return strcmp16 (*this, str);
688 else
689 return stricmp16 (*this, str);
690 }
691 else
692 {
693 if (isCaseSensitive (mode))
694 return strncmp16 (*this, str, n);
695 else
696 return strnicmp16 (*this, str, n);
697 }
698 }
699 return compareAt (0, str, n, mode);
700}
701
702//-----------------------------------------------------------------------------
704{
705 return compare (str, -1, mode);
706}
707
708//-----------------------------------------------------------------------------
710{
711 if (n == 0)
712 return 0;
713
714 if (str.isEmpty ())
715 {
716 if (isEmpty ())
717 return 0;
718 return 1;
719 }
720 else if (isEmpty ())
721 return -1;
722
723 if (!isWide && !str.isWide)
724 {
725 char8* toCompare = buffer8;
726 if (index > 0)
727 {
728 if (index >= len)
729 {
730 if (str.isEmpty ())
731 return 0;
732 return -1;
733 }
734 toCompare += index;
735 }
736
737 if (n < 0)
738 {
739 if (isCaseSensitive (mode))
740 return strcmp (toCompare, str);
741 else
742 return stricmp (toCompare, str);
743 }
744 else
745 {
746 if (isCaseSensitive (mode))
747 return strncmp (toCompare, str, n);
748 else
749 return strnicmp (toCompare, str, n);
750 }
751 }
752 else if (isWide && str.isWide)
753 {
754 char16* toCompare = buffer16;
755 if (index > 0)
756 {
757 if (index >= len)
758 {
759 if (str.isEmpty ())
760 return 0;
761 return -1;
762 }
763 toCompare += index;
764 }
765
766 if (n < 0)
767 {
768 if (isCaseSensitive (mode))
769 return strcmp16 (toCompare, str.text16 ());
770 else
771 return stricmp16 (toCompare, str.text16 ());
772 }
773 else
774 {
775 if (isCaseSensitive (mode))
776 return strncmp16 (toCompare, str.text16 (), n);
777 else
778 return strnicmp16 (toCompare, str.text16 (), n);
779 }
780 }
781 else
782 {
783 if (isWide)
784 {
785 String tmp (str.text8 ());
786 if (tmp.toWideString () == false)
787 return -1;
788 return compareAt (index, tmp, n, mode);
789 }
790 else
791 {
792 String tmp (text8 ());
793 if (tmp.toWideString () == false)
794 return 1;
795 return tmp.compareAt (index, str, n, mode);
796 }
797 }
798}
799
800//------------------------------------------------------------------------
802{
803 if (str.isEmpty ())
804 {
805 if (isEmpty ())
806 return 0;
807 return 1;
808 }
809 else if (isEmpty ())
810 return -1;
811
812 if (!isWide && !str.isWide)
813 return strnatcmp8 (buffer8, str.text8 (), isCaseSensitive (mode));
814 else if (isWide && str.isWide)
815 return strnatcmp16 (buffer16, str.text16 (), isCaseSensitive (mode));
816 else
817 {
818 if (isWide)
819 {
820 String tmp (str.text8 ());
821 tmp.toWideString ();
822 return strnatcmp16 (buffer16, tmp.text16 (), isCaseSensitive (mode));
823 }
824 else
825 {
826 String tmp (text8 ());
827 tmp.toWideString ();
828 return strnatcmp16 (tmp.text16 (), str.text16 (), isCaseSensitive (mode));
829 }
830 }
831}
832
833//-----------------------------------------------------------------------------
834bool ConstString::startsWith (const ConstString& str, CompareMode mode /*= kCaseSensitive*/) const
835{
836 if (str.isEmpty ())
837 {
838 return isEmpty ();
839 }
840 else if (isEmpty ())
841 {
842 return false;
843 }
844 if (length () < str.length ())
845 {
846 return false;
847 }
848 if (!isWide && !str.isWide)
849 {
850 if (isCaseSensitive (mode))
851 return strncmp (buffer8, str.buffer8, str.length ()) == 0;
852 return strnicmp (buffer8, str.buffer8, str.length ()) == 0;
853 }
854 else if (isWide && str.isWide)
855 {
856 if (isCaseSensitive (mode))
857 return strncmp16 (buffer16, str.buffer16, str.length ()) == 0;
858 return strnicmp16 (buffer16, str.buffer16, str.length ()) == 0;
859 }
860 else if (isWide)
861 {
862 String tmp (str.text8 ());
863 tmp.toWideString ();
864 if (tmp.length () > length ())
865 return false;
866 if (isCaseSensitive (mode))
867 return strncmp16 (buffer16, tmp.buffer16, tmp.length ()) == 0;
868 return strnicmp16 (buffer16, tmp.buffer16, tmp.length ()) == 0;
869 }
870 else
871 {
872 String tmp (text8 ());
873 tmp.toWideString ();
874 if (str.length () > tmp.length ())
875 return false;
876 if (isCaseSensitive (mode))
877 return strncmp16 (tmp.buffer16, str.buffer16, str.length ()) == 0;
878 return strnicmp16 (tmp.buffer16, str.buffer16, str.length ()) == 0;
879 }
880}
881
882//-----------------------------------------------------------------------------
883bool ConstString::endsWith (const ConstString& str, CompareMode mode /*= kCaseSensitive*/) const
884{
885 if (str.isEmpty ())
886 {
887 return isEmpty ();
888 }
889 else if (isEmpty ())
890 {
891 return false;
892 }
893 if (length () < str.length ())
894 {
895 return false;
896 }
897 if (!isWide && !str.isWide)
898 {
899 if (isCaseSensitive (mode))
900 return strncmp (buffer8 + (length () - str.length ()), str.buffer8, str.length ()) == 0;
901 return strnicmp (buffer8 + (length () - str.length ()), str.buffer8, str.length ()) == 0;
902 }
903 else if (isWide && str.isWide)
904 {
905 if (isCaseSensitive (mode))
906 return strncmp16 (buffer16 + (length () - str.length ()), str.buffer16, str.length ()) == 0;
907 return strnicmp16 (buffer16 + (length () - str.length ()), str.buffer16, str.length ()) == 0;
908 }
909 else if (isWide)
910 {
911 String tmp (str.text8 ());
912 tmp.toWideString ();
913 if (tmp.length () > length ())
914 return false;
915 if (isCaseSensitive (mode))
916 return strncmp16 (buffer16 + (length () - tmp.length ()), tmp.buffer16, tmp.length ()) == 0;
917 return strnicmp16 (buffer16 + (length () - tmp.length ()), tmp.buffer16, tmp.length ()) == 0;
918 }
919 else
920 {
921 String tmp (text8 ());
922 tmp.toWideString ();
923 if (str.length () > tmp.length ())
924 return false;
925 if (isCaseSensitive (mode))
926 return strncmp16 (tmp.buffer16 + (tmp.length () - str.length ()), str.buffer16, str.length ()) == 0;
927 return strnicmp16 (tmp.buffer16 + (tmp.length () - str.length ()), str.buffer16, str.length ()) == 0;
928 }
929}
930
931//-----------------------------------------------------------------------------
933{
934 return findFirst (str, -1, m) != -1;
935}
936
937//-----------------------------------------------------------------------------
938int32 ConstString::findNext (int32 startIndex, const ConstString& str, int32 n, CompareMode mode, int32 endIndex) const
939{
940 uint32 endLength = len;
941 if (endIndex > -1 && (uint32)endIndex < len)
942 endLength = endIndex + 1;
943
944 if (isWide && str.isWide)
945 {
946 if (startIndex < 0)
947 startIndex = 0;
948
949 uint32 stringLength = str.length ();
950 n = n < 0 ? stringLength : Min<uint32> (n, stringLength);
951
952 if (n > 0)
953 {
954 uint32 i = 0;
955
956 if (isCaseSensitive (mode))
957 {
958 for (i = startIndex; i < endLength; i++)
959 if (strncmp16 (buffer16 + i, str, n) == 0)
960 return i;
961 }
962 else
963 {
964 for (i = startIndex; i < endLength; i++)
965 if (strnicmp16 (buffer16 + i, str, n) == 0)
966 return i;
967 }
968 }
969 return -1;
970 }
971 else if (!isWide && !str.isWide)
972 {
973 uint32 stringLength = str.length ();
974 n = n < 0 ? stringLength : Min<uint32> (n, stringLength);
975
976 if (startIndex < 0)
977 startIndex = 0;
978
979 if (n > 0)
980 {
981 uint32 i = 0;
982
983 if (isCaseSensitive (mode))
984 {
985 for (i = startIndex; i < endLength; i++)
986 if (strncmp (buffer8 + i, str, n) == 0)
987 return i;
988 }
989 else
990 {
991 for (i = startIndex; i < endLength; i++)
992 if (strnicmp (buffer8 + i, str, n) == 0)
993 return i;
994 }
995 }
996 return -1;
997 }
998 String tmp;
999 if (isWide)
1000 {
1001 tmp = str.text8 ();
1002 tmp.toWideString ();
1003 return findNext (startIndex, tmp, n , mode, endIndex);
1004 }
1005 tmp = text8 ();
1006 tmp.toWideString ();
1007 return tmp.findNext (startIndex, str, n, mode, endIndex);
1008}
1009
1010//------------------------------------------------------------------------------------------------
1012{
1013 uint32 endLength = len;
1014 if (endIndex > -1 && (uint32)endIndex < len)
1015 endLength = endIndex + 1;
1016
1017 if (isWide)
1018 {
1019 char8 src[] = {c, 0};
1020 char16 dest[8] = {0};
1021 if (multiByteToWideString (dest, src, 2) > 0)
1022 return findNext (startIndex, dest[0], mode, endIndex);
1023 return -1;
1024 }
1025
1026 if (startIndex < 0)
1027 startIndex = 0;
1028 uint32 i;
1029
1030 if (isCaseSensitive (mode))
1031 {
1032 for (i = startIndex; i < endLength; i++)
1033 {
1034 if (buffer8[i] == c)
1035 return i;
1036 }
1037 }
1038 else
1039 {
1040 c = toLower (c);
1041 for (i = startIndex; i < endLength; i++)
1042 {
1043 if (toLower (buffer8[i]) == c)
1044 return i;
1045 }
1046 }
1047 return -1;
1048}
1049
1050//-----------------------------------------------------------------------------
1052{
1053 uint32 endLength = len;
1054 if (endIndex > -1 && (uint32)endIndex < len)
1055 endLength = endIndex + 1;
1056
1057 if (!isWide)
1058 {
1059 char16 src[] = {c, 0};
1060 char8 dest[8] = {0};
1061 if (wideStringToMultiByte (dest, src, 2) > 0 && dest[1] == 0)
1062 return findNext (startIndex, dest[0], mode, endIndex);
1063
1064 return -1;
1065 }
1066
1067 uint32 i;
1068 if (startIndex < 0)
1069 startIndex = 0;
1070
1071 if (isCaseSensitive (mode))
1072 {
1073 for (i = startIndex; i < endLength; i++)
1074 {
1075 if (buffer16[i] == c)
1076 return i;
1077 }
1078 }
1079 else
1080 {
1081 c = toLower (c);
1082 for (i = startIndex; i < endLength; i++)
1083 {
1084 if (toLower (buffer16[i]) == c)
1085 return i;
1086 }
1087 }
1088 return -1;
1089}
1090
1091//-----------------------------------------------------------------------------
1093{
1094 if (len == 0)
1095 return -1;
1096
1097 if (isWide)
1098 {
1099 char8 src[] = {c, 0};
1100 char16 dest[8] = {0};
1101 if (multiByteToWideString (dest, src, 2) > 0)
1102 return findPrev (startIndex, dest[0], mode);
1103 return -1;
1104 }
1105
1106 if (startIndex < 0 || startIndex > (int32)len)
1107 startIndex = len;
1108
1109 int32 i;
1110
1111 if (isCaseSensitive (mode))
1112 {
1113 for (i = startIndex; i >= 0; i--)
1114 {
1115 if (buffer8[i] == c)
1116 return i;
1117 }
1118 }
1119 else
1120 {
1121 c = toLower (c);
1122 for (i = startIndex; i >= 0; i--)
1123 {
1124 if (toLower (buffer8[i]) == c)
1125 return i;
1126 }
1127 }
1128 return -1;
1129}
1130
1131//-----------------------------------------------------------------------------
1133{
1134 if (len == 0)
1135 return -1;
1136
1137 if (!isWide)
1138 {
1139 char16 src[] = {c, 0};
1140 char8 dest[8] = {0};
1141 if (wideStringToMultiByte (dest, src, 2) > 0 && dest[1] == 0)
1142 return findPrev (startIndex, dest[0], mode);
1143
1144 return -1;
1145 }
1146
1147 if (startIndex < 0 || startIndex > (int32)len)
1148 startIndex = len;
1149
1150 int32 i;
1151
1152 if (isCaseSensitive (mode))
1153 {
1154 for (i = startIndex; i >= 0; i--)
1155 {
1156 if (buffer16[i] == c)
1157 return i;
1158 }
1159 }
1160 else
1161 {
1162 c = toLower (c);
1163 for (i = startIndex; i >= 0; i--)
1164 {
1165 if (toLower (buffer16[i]) == c)
1166 return i;
1167 }
1168 }
1169 return -1;
1170}
1171
1172//-----------------------------------------------------------------------------
1174{
1175 if (isWide && str.isWide)
1176 {
1177 uint32 stringLength = str.length ();
1178 n = n < 0 ? stringLength : Min<uint32> (n, stringLength);
1179
1180 if (startIndex < 0 || startIndex >= (int32)len)
1181 startIndex = len - 1;
1182
1183 if (n > 0)
1184 {
1185 int32 i = 0;
1186
1187 if (isCaseSensitive (mode))
1188 {
1189 for (i = startIndex; i >= 0; i--)
1190 if (strncmp16 (buffer16 + i, str, n) == 0)
1191 return i;
1192 }
1193 else
1194 {
1195 for (i = startIndex; i >= 0; i--)
1196 if (strnicmp16 (buffer16 + i, str, n) == 0)
1197 return i;
1198 }
1199 }
1200 return -1;
1201 }
1202 else if (!isWide && !str.isWide)
1203 {
1204 uint32 stringLength = str.length ();
1205 n = n < 0 ? stringLength : Min<uint32> (n, stringLength);
1206
1207 if (startIndex < 0 || startIndex >= (int32)len)
1208 startIndex = len - 1;
1209
1210 if (n > 0)
1211 {
1212 int32 i = 0;
1213
1214 if (isCaseSensitive (mode))
1215 {
1216 for (i = startIndex; i >= 0; i--)
1217 if (strncmp (buffer8 + i, str, n) == 0)
1218 return i;
1219 }
1220 else
1221 {
1222 for (i = startIndex; i >= 0; i--)
1223 if (strnicmp (buffer8 + i, str, n) == 0)
1224 return i;
1225 }
1226 }
1227 return -1;
1228 }
1229 if (isWide)
1230 {
1231 String tmp (str.text8 ());
1232 tmp.toWideString ();
1233 return findPrev (startIndex, tmp, n, mode);
1234 }
1235 String tmp (text8 ());
1236 tmp.toWideString ();
1237 return tmp.findPrev (startIndex, str, n, mode);
1238}
1239
1240//-----------------------------------------------------------------------------
1242{
1243 if (isWide)
1244 {
1245 char8 src[] = {c, 0};
1246 char16 dest[8] = {0};
1247 if (multiByteToWideString (dest, src, 2) > 0)
1248 return countOccurences (dest[0], startIndex, mode);
1249 return -1;
1250 }
1251
1252 int32 result = 0;
1253 int32 next = startIndex;
1254 while (true)
1255 {
1256 next = findNext (next, c, mode);
1257 if (next >= 0)
1258 {
1259 next++;
1260 result++;
1261 }
1262 else
1263 break;
1264 }
1265 return result;
1266}
1267
1268//-----------------------------------------------------------------------------
1270{
1271 if (!isWide)
1272 {
1273 char16 src[] = {c, 0};
1274 char8 dest[8] = {0};
1275 if (wideStringToMultiByte (dest, src, 2) > 0 && dest[1] == 0)
1276 return countOccurences (dest[0], startIndex, mode);
1277
1278 return -1;
1279 }
1280 int32 result = 0;
1281 int32 next = startIndex;
1282 while (true)
1283 {
1284 next = findNext (next, c, mode);
1285 if (next >= 0)
1286 {
1287 next++;
1288 result++;
1289 }
1290 else
1291 break;
1292 }
1293 return result;
1294}
1295
1296//-----------------------------------------------------------------------------
1298{
1299 if (str.isWide != isWide)
1300 {
1301 if (isWide)
1302 {
1303 String tmp (str.text8 ());
1304 if (tmp.toWideString () == false)
1305 return -1;
1306 return getFirstDifferent (tmp, mode);
1307 }
1308 else
1309 {
1310 String tmp (text8 ());
1311 if (tmp.toWideString () == false)
1312 return -1;
1313 return tmp.getFirstDifferent (str, mode);
1314 }
1315 }
1316
1317 uint32 len1 = len;
1318 uint32 len2 = str.len;
1319 uint32 i;
1320
1321 if (isWide)
1322 {
1323 if (isCaseSensitive (mode))
1324 {
1325 for (i = 0; i <= len1 && i <= len2; i++)
1326 {
1327 if (buffer16[i] != str.buffer16[i])
1328 return i;
1329 }
1330 }
1331 else
1332 {
1333 for (i = 0; i <= len1 && i <= len2; i++)
1334 {
1335 if (toLower (buffer16[i]) != toLower (str.buffer16[i]))
1336 return i;
1337 }
1338 }
1339 }
1340 else
1341 {
1342 if (isCaseSensitive (mode))
1343 {
1344 for (i = 0; i <= len1 && i <= len2; i++)
1345 {
1346 if (buffer8[i] != str.buffer8[i])
1347 return i;
1348 }
1349 }
1350 else
1351 {
1352 for (i = 0; i <= len1 && i <= len2; i++)
1353 {
1354 if (toLower (buffer8[i]) != toLower (str.buffer8[i]))
1355 return i;
1356 }
1357 }
1358 }
1359 return -1;
1360}
1361
1362//-----------------------------------------------------------------------------
1363bool ConstString::scanInt64 (int64& value, uint32 offset, bool scanToEnd) const
1364{
1365 if (isEmpty () || offset >= len)
1366 return false;
1367
1368 if (isWide)
1369 return scanInt64_16 (buffer16 + offset, value, scanToEnd);
1370 else
1371 return scanInt64_8 (buffer8 + offset, value, scanToEnd);
1372}
1373
1374//-----------------------------------------------------------------------------
1375bool ConstString::scanUInt64 (uint64& value, uint32 offset, bool scanToEnd) const
1376{
1377 if (isEmpty () || offset >= len)
1378 return false;
1379
1380 if (isWide)
1381 return scanUInt64_16 (buffer16 + offset, value, scanToEnd);
1382 else
1383 return scanUInt64_8 (buffer8 + offset, value, scanToEnd);
1384}
1385
1386//-----------------------------------------------------------------------------
1387bool ConstString::scanHex (uint8& value, uint32 offset, bool scanToEnd) const
1388{
1389 if (isEmpty () || offset >= len)
1390 return false;
1391
1392 if (isWide)
1393 return scanHex_16 (buffer16 + offset, value, scanToEnd);
1394 else
1395 return scanHex_8 (buffer8 + offset, value, scanToEnd);
1396}
1397
1398//-----------------------------------------------------------------------------
1399bool ConstString::scanInt32 (int32& value, uint32 offset, bool scanToEnd) const
1400{
1401 if (isEmpty () || offset >= len)
1402 return false;
1403
1404 if (isWide)
1405 return scanInt32_16 (buffer16 + offset, value, scanToEnd);
1406 else
1407 return scanInt32_8 (buffer8 + offset, value, scanToEnd);
1408}
1409
1410//-----------------------------------------------------------------------------
1411bool ConstString::scanUInt32 (uint32& value, uint32 offset, bool scanToEnd) const
1412{
1413 if (isEmpty () || offset >= len)
1414 return false;
1415
1416 if (isWide)
1417 return scanUInt32_16 (buffer16 + offset, value, scanToEnd);
1418 else
1419 return scanUInt32_8 (buffer8 + offset, value, scanToEnd);
1420}
1421
1422//-----------------------------------------------------------------------------
1423bool ConstString::scanInt64_8 (const char8* text, int64& value, bool scanToEnd)
1424{
1425 while (text && text[0])
1426 {
1427 if (sscanf (text, "%" FORMAT_INT64A, &value) == 1)
1428 return true;
1429 else if (scanToEnd == false)
1430 return false;
1431 text++;
1432 }
1433 return false;
1434}
1435
1436//-----------------------------------------------------------------------------
1437bool ConstString::scanInt64_16 (const char16* text, int64& value, bool scanToEnd)
1438{
1439 if (text && text[0])
1440 {
1441 String str (text);
1443 return scanInt64_8 (str, value, scanToEnd);
1444 }
1445 return false;
1446}
1447
1448//-----------------------------------------------------------------------------
1449bool ConstString::scanUInt64_8 (const char8* text, uint64& value, bool scanToEnd)
1450{
1451 while (text && text[0])
1452 {
1453 if (sscanf (text, "%" FORMAT_UINT64A, &value) == 1)
1454 return true;
1455 else if (scanToEnd == false)
1456 return false;
1457 text++;
1458 }
1459 return false;
1460}
1461
1462//-----------------------------------------------------------------------------
1463bool ConstString::scanUInt64_16 (const char16* text, uint64& value, bool scanToEnd)
1464{
1465 if (text && text[0])
1466 {
1467 String str (text);
1469 return scanUInt64_8 (str, value, scanToEnd);
1470 }
1471 return false;
1472}
1473
1474//-----------------------------------------------------------------------------
1475bool ConstString::scanInt64 (const tchar* text, int64& value, bool scanToEnd)
1476{
1477#ifdef UNICODE
1478 return scanInt64_16 (text, value,scanToEnd);
1479#else
1480 return scanInt64_8 (text, value, scanToEnd);
1481#endif
1482}
1483
1484//-----------------------------------------------------------------------------
1485bool ConstString::scanUInt64 (const tchar* text, uint64& value, bool scanToEnd)
1486{
1487#ifdef UNICODE
1488 return scanUInt64_16 (text, value, scanToEnd);
1489#else
1490 return scanUInt64_8 (text, value, scanToEnd);
1491#endif
1492}
1493
1494//-----------------------------------------------------------------------------
1495bool ConstString::scanHex_8 (const char8* text, uint8& value, bool scanToEnd)
1496{
1497 while (text && text[0])
1498 {
1499 unsigned int v; // scanf expects an unsigned int for %x
1500 if (sscanf (text, "%x", &v) == 1)
1501 {
1502 value = (uint8)v;
1503 return true;
1504 }
1505 else if (scanToEnd == false)
1506 return false;
1507 text++;
1508 }
1509 return false;
1510}
1511
1512//-----------------------------------------------------------------------------
1513bool ConstString::scanHex_16 (const char16* text, uint8& value, bool scanToEnd)
1514{
1515 if (text && text[0])
1516 {
1517 String str (text);
1518 str.toMultiByte (kCP_Default); // scanf uses default codepage
1519 return scanHex_8 (str, value, scanToEnd);
1520 }
1521 return false;
1522}
1523
1524//-----------------------------------------------------------------------------
1525bool ConstString::scanHex (const tchar* text, uint8& value, bool scanToEnd)
1526{
1527#ifdef UNICODE
1528 return scanHex_16 (text, value, scanToEnd);
1529#else
1530 return scanHex_8 (text, value, scanToEnd);
1531#endif
1532}
1533
1534//-----------------------------------------------------------------------------
1535bool ConstString::scanFloat (double& value, uint32 offset, bool scanToEnd) const
1536{
1537 if (isEmpty () || offset >= len)
1538 return false;
1539
1540 String str (*this);
1541 int32 pos = -1;
1542 if (isWide)
1543 {
1544 if ((pos = str.findNext (offset, STR(','))) >= 0 && ((uint32)pos) >= offset)
1545 str.setChar (pos, STR('.'));
1546
1547 str.toMultiByte (kCP_Default); // scanf uses default codepage
1548 }
1549 else
1550 {
1551 if ((pos = str.findNext (offset, ',')) >= 0 && ((uint32)pos) >= offset)
1552 str.setChar (pos, '.');
1553 }
1554
1555 const char8* txt = str.text8 () + offset;
1556 while (txt && txt[0])
1557 {
1558 if (sscanf (txt, "%lf", &value) == 1)
1559 return true;
1560 else if (scanToEnd == false)
1561 return false;
1562 txt++;
1563 }
1564 return false;
1565}
1566
1567//-----------------------------------------------------------------------------
1569{
1570 #if SMTG_OS_WINDOWS
1571 WCHAR temp[2] = {c, 0};
1572 ::CharLowerW (temp);
1573 return temp[0];
1574 #elif SMTG_OS_MACOS
1575 // only convert characters which in lowercase are also single characters
1576 UniChar characters [2] = {0};
1577 characters[0] = c;
1578 CFMutableStringRef str = CFStringCreateMutableWithExternalCharactersNoCopy (kCFAllocator, characters, 1, 2, kCFAllocatorNull);
1579 if (str)
1580 {
1581 CFStringLowercase (str, NULL);
1582 CFRelease (str);
1583 if (characters[1] == 0)
1584 return characters[0];
1585 }
1586 return c;
1587 #elif SMTG_OS_LINUX
1588 assert(false && "DEPRECATED No Linux implementation");
1589 return c;
1590 #else
1591 return towlower (c);
1592 #endif
1593}
1594
1595//-----------------------------------------------------------------------------
1597{
1598 #if SMTG_OS_WINDOWS
1599 WCHAR temp[2] = {c, 0};
1600 ::CharUpperW (temp);
1601 return temp[0];
1602 #elif SMTG_OS_MACOS
1603 // only convert characters which in uppercase are also single characters (don't translate a sharp-s which would result in SS)
1604 UniChar characters [2] = {0};
1605 characters[0] = c;
1606 CFMutableStringRef str = CFStringCreateMutableWithExternalCharactersNoCopy (kCFAllocator, characters, 1, 2, kCFAllocatorNull);
1607 if (str)
1608 {
1609 CFStringUppercase (str, NULL);
1610 CFRelease (str);
1611 if (characters[1] == 0)
1612 return characters[0];
1613 }
1614 return c;
1615 #elif SMTG_OS_LINUX
1616 assert(false && "DEPRECATED No Linux implementation");
1617 return c;
1618 #else
1619 return towupper (c);
1620 #endif
1621}
1622
1623//-----------------------------------------------------------------------------
1625{
1626 if ((c >= 'A') && (c <= 'Z'))
1627 return c + ('a' - 'A');
1628 #if SMTG_OS_WINDOWS
1629 CHAR temp[2] = {c, 0};
1630 ::CharLowerA (temp);
1631 return temp[0];
1632 #else
1633 return static_cast<char8> (tolower (c));
1634 #endif
1635}
1636
1637//-----------------------------------------------------------------------------
1639{
1640 if ((c >= 'a') && (c <= 'z'))
1641 return c - ('a' - 'A');
1642 #if SMTG_OS_WINDOWS
1643 CHAR temp[2] = {c, 0};
1644 ::CharUpperA (temp);
1645 return temp[0];
1646 #else
1647 return static_cast<char8> (toupper (c));
1648 #endif
1649}
1650
1651//-----------------------------------------------------------------------------
1652bool ConstString::isCharSpace (const char8 character)
1653{
1654 return isspace (character) != 0;
1655}
1656
1657//-----------------------------------------------------------------------------
1658bool ConstString::isCharSpace (const char16 character)
1659{
1660 switch (character)
1661 {
1662 case 0x0020:
1663 case 0x00A0:
1664 case 0x2002:
1665 case 0x2003:
1666 case 0x2004:
1667 case 0x2005:
1668 case 0x2006:
1669 case 0x2007:
1670 case 0x2008:
1671 case 0x2009:
1672 case 0x200A:
1673 case 0x200B:
1674 case 0x202F:
1675 case 0x205F:
1676 case 0x3000:
1677 return true;
1678 }
1679 return false;
1680}
1681
1682//-----------------------------------------------------------------------------
1683bool ConstString::isCharAlpha (const char8 character)
1684{
1685 return isalpha (character) != 0;
1686}
1687
1688//-----------------------------------------------------------------------------
1689bool ConstString::isCharAlpha (const char16 character)
1690{
1691 return iswalpha (character) != 0;
1692}
1693
1694//-----------------------------------------------------------------------------
1696{
1697 return isalnum (character) != 0;
1698}
1699
1700//-----------------------------------------------------------------------------
1702{
1703 return iswalnum (character) != 0; // this may not work on macOSX when another locale is set inside the c-lib
1704}
1705
1706//-----------------------------------------------------------------------------
1707bool ConstString::isCharDigit (const char8 character)
1708{
1709 return isdigit (character) != 0;
1710}
1711
1712//-----------------------------------------------------------------------------
1713bool ConstString::isCharDigit (const char16 character)
1714{
1715 return iswdigit (character) != 0; // this may not work on macOSX when another locale is set inside the c-lib
1716}
1717
1718//-----------------------------------------------------------------------------
1720{
1721 return character >= 0;
1722}
1723
1724//-----------------------------------------------------------------------------
1726{
1727 return character < 128;
1728}
1729
1730//-----------------------------------------------------------------------------
1732{
1733 return toUpper (character) == character;
1734}
1735
1736//-----------------------------------------------------------------------------
1738{
1739 return toUpper (character) == character;
1740}
1741
1742//-----------------------------------------------------------------------------
1744{
1745 return toLower (character) == character;
1746}
1747
1748//-----------------------------------------------------------------------------
1750{
1751 return toLower (character) == character;
1752}
1753
1754//-----------------------------------------------------------------------------
1756{
1757 if (isEmpty () || index >= len)
1758 return false;
1759
1760 if (isWide)
1761 return ConstString::isCharDigit (buffer16[index]);
1762 else
1763 return ConstString::isCharDigit (buffer8[index]);
1764}
1765
1766//-----------------------------------------------------------------------------
1768{
1769 if (isEmpty ())
1770 return -1;
1771
1772 int32 endIndex = len - 1;
1773 int32 i = endIndex;
1774 while (isDigit ((uint32) i) && i >= 0)
1775 i--;
1776
1777 // now either all are digits or i is on the first non digit
1778 if (i < endIndex)
1779 {
1780 if (width > 0 && (endIndex - i != static_cast<int32> (width)))
1781 return -1;
1782
1783 return i + 1;
1784 }
1785
1786 return -1;
1787}
1788
1789//-----------------------------------------------------------------------------
1791{
1792 int32 index = getTrailingNumberIndex ();
1793
1794 int64 number = 0;
1795
1796 if (index >= 0)
1797 if (scanInt64 (number, index))
1798 return number;
1799
1800 return fallback;
1801}
1802
1803
1804
1805//-----------------------------------------------------------------------------
1807{
1808 if (isWide)
1809 {
1810 var.setString16 (buffer16);
1811 }
1812 else
1813 {
1814 var.setString8 (buffer8);
1815 }
1816}
1817
1818//-----------------------------------------------------------------------------
1820{
1821 uint32 i;
1822 if (isWide)
1823 {
1824 for (i = 0; i < len; i++)
1825 if (ConstString::isCharAscii (buffer16 [i]) == false)
1826 return false;
1827 }
1828 else
1829 {
1830 for (i = 0; i < len; i++)
1831 if (ConstString::isCharAscii (buffer8 [i]) == false)
1832 return false;
1833 }
1834 return true;
1835}
1836
1837
1838#if SMTG_OS_MACOS
1839uint32 kDefaultSystemEncoding = kCFStringEncodingMacRoman;
1840//-----------------------------------------------------------------------------
1841static CFStringEncoding MBCodePageToCFStringEncoding (uint32 codePage)
1842{
1843 switch (codePage)
1844 {
1845 case kCP_ANSI: return kDefaultSystemEncoding; // MacRoman or JIS
1846 case kCP_MAC_ROMAN: return kCFStringEncodingMacRoman;
1847 case kCP_ANSI_WEL: return kCFStringEncodingWindowsLatin1;
1848 case kCP_MAC_CEE: return kCFStringEncodingMacCentralEurRoman;
1849 case kCP_Utf8: return kCFStringEncodingUTF8;
1850 case kCP_ShiftJIS: return kCFStringEncodingShiftJIS_X0213_00;
1851 case kCP_US_ASCII: return kCFStringEncodingASCII;
1852 }
1853 return kCFStringEncodingASCII;
1854}
1855#endif
1856
1857//-----------------------------------------------------------------------------
1858int32 ConstString::multiByteToWideString (char16* dest, const char8* source, int32 charCount, uint32 sourceCodePage)
1859{
1860 if (source == nullptr || source[0] == 0)
1861 {
1862 if (dest && charCount > 0)
1863 {
1864 dest[0] = 0;
1865 }
1866 return 0;
1867 }
1868 int32 result = 0;
1869#if SMTG_OS_WINDOWS
1870 result = MultiByteToWideChar (sourceCodePage, MB_ERR_INVALID_CHARS, source, -1, dest, charCount);
1871#endif
1872
1873#if SMTG_OS_MACOS
1874 CFStringRef cfStr =
1875 (CFStringRef)::toCFStringRef (source, MBCodePageToCFStringEncoding (sourceCodePage));
1876 if (cfStr)
1877 {
1878 CFRange range = {0, CFStringGetLength (cfStr)};
1879 CFIndex usedBytes;
1880 if (CFStringGetBytes (cfStr, range, kCFStringEncodingUnicode, ' ', false, (UInt8*)dest,
1881 charCount * 2, &usedBytes) > 0)
1882 {
1883 result = static_cast<int32> (usedBytes / 2 + 1);
1884 if (dest)
1885 dest[usedBytes / 2] = 0;
1886 }
1887
1888 CFRelease (cfStr);
1889 }
1890#endif
1891
1892#if SMTG_OS_LINUX
1893 if (sourceCodePage == kCP_ANSI || sourceCodePage == kCP_US_ASCII || sourceCodePage == kCP_Utf8)
1894 {
1895 if (dest == nullptr)
1896 {
1897 auto state = std::mbstate_t ();
1898 auto maxChars = charCount ? charCount : std::numeric_limits<int32>::max () - 1;
1899 result = converterFacet ().length (state, source, source + strlen (source), maxChars);
1900 }
1901 else
1902 {
1903 auto utf16Str = converter ().from_bytes (source);
1904 if (!utf16Str.empty ())
1905 {
1906 result = std::min<int32> (charCount, utf16Str.size ());
1907 memcpy (dest, utf16Str.data (), result * sizeof (char16));
1908 dest[result] = 0;
1909 }
1910 }
1911 }
1912 else
1913 {
1914 assert(false && "DEPRECATED No Linux implementation");
1915 }
1916
1917#endif
1918
1919 SMTG_ASSERT (result > 0)
1920 return result;
1921}
1922
1923//-----------------------------------------------------------------------------
1924int32 ConstString::wideStringToMultiByte (char8* dest, const char16* wideString, int32 charCount, uint32 destCodePage)
1925{
1926#if SMTG_OS_WINDOWS
1927 return WideCharToMultiByte (destCodePage, 0, wideString, -1, dest, charCount, nullptr, nullptr);
1928
1929#elif SMTG_OS_MACOS
1930 int32 result = 0;
1931 if (wideString != 0)
1932 {
1933 if (dest)
1934 {
1935 CFStringRef cfStr = CFStringCreateWithCharactersNoCopy (kCFAllocator, (const UniChar*)wideString, strlen16 (wideString), kCFAllocatorNull);
1936 if (cfStr)
1937 {
1938 if (fromCFStringRef (dest, charCount, cfStr, MBCodePageToCFStringEncoding (destCodePage)))
1939 result = static_cast<int32> (strlen (dest) + 1);
1940 CFRelease (cfStr);
1941 }
1942 }
1943 else
1944 {
1945 return static_cast<int32> (CFStringGetMaximumSizeForEncoding (strlen16 (wideString), MBCodePageToCFStringEncoding (destCodePage)));
1946 }
1947 }
1948 return result;
1949
1950#elif SMTG_OS_LINUX
1951 int32 result = 0;
1952 if (destCodePage == kCP_Utf8)
1953 {
1954 if (dest == nullptr)
1955 {
1956 auto maxChars = charCount ? charCount : tstrlen (wideString);
1957 result = converterFacet ().max_length () * maxChars;
1958 }
1959 else
1960 {
1961 auto utf8Str = converter ().to_bytes (wideString);
1962 if (!utf8Str.empty ())
1963 {
1964 result = std::min<int32> (charCount, utf8Str.size ());
1965 memcpy (dest, utf8Str.data (), result * sizeof (char8));
1966 dest[result] = 0;
1967 }
1968 }
1969 }
1970 else if (destCodePage == kCP_ANSI || destCodePage == kCP_US_ASCII)
1971 {
1972 if (dest == nullptr)
1973 {
1974 result = strlen16 (wideString) + 1;
1975 }
1976 else
1977 {
1978 int32 i = 0;
1979 for (; i < charCount; ++i)
1980 {
1981 if (wideString[i] == 0)
1982 break;
1983 if (wideString[i] <= 0x007F)
1984 dest[i] = wideString[i];
1985 else
1986 dest[i] = '_';
1987 }
1988 dest[i] = 0;
1989 result = i;
1990 }
1991 }
1992 else
1993 {
1994 assert(false && "DEPRECATED No Linux implementation");
1995 }
1996 return result;
1997
1998#else
1999#warning DEPRECATED No Linux implementation
2000 assert(false && "DEPRECATED No Linux implementation");
2001 return 0;
2002#endif
2003
2004}
2005
2006//-----------------------------------------------------------------------------
2008{
2009 if (isWide == false)
2010 return false;
2011
2012#if SMTG_OS_WINDOWS
2013#ifdef UNICODE
2014 if (n != kUnicodeNormC)
2015 return false;
2016 uint32 normCharCount = static_cast<uint32> (FoldString (MAP_PRECOMPOSED, buffer16, len, nullptr, 0));
2017 return (normCharCount == len);
2018#else
2019 return false;
2020#endif
2021
2022#elif SMTG_OS_MACOS
2023 if (n != kUnicodeNormC)
2024 return false;
2025
2026 CFStringRef cfStr = (CFStringRef)toCFStringRef ();
2027 CFIndex charCount = CFStringGetLength (cfStr);
2028 CFRelease (cfStr);
2029 return (charCount == len);
2030#else
2031 return false;
2032#endif
2033}
2034
2035//-----------------------------------------------------------------------------
2036// String
2037//-----------------------------------------------------------------------------
2039{
2040 isWide = kWideStringDefault ? 1 : 0;
2041}
2042
2043//-----------------------------------------------------------------------------
2044String::String (const char8* str, MBCodePage codePage, int32 n, bool isTerminated)
2045{
2046 isWide = 0;
2047 if (str)
2048 {
2049 assign (str, n, isTerminated);
2050 toWideString (codePage);
2051 }
2052}
2053
2054//-----------------------------------------------------------------------------
2055String::String (const char8* str, int32 n, bool isTerminated)
2056{
2057 if (str)
2058 assign (str, n, isTerminated);
2059}
2060
2061//-----------------------------------------------------------------------------
2062String::String (const char16* str, int32 n, bool isTerminated)
2063{
2064 isWide = 1;
2065 if (str)
2066 assign (str, n, isTerminated);
2067}
2068
2069//-----------------------------------------------------------------------------
2071{
2072 isWide = str.isWideString ();
2073 if (!str.isEmpty ())
2074 assign (str, n);
2075}
2076
2077//-----------------------------------------------------------------------------
2079{
2080 isWide = str.isWideString ();
2081 if (!str.isEmpty ())
2082 assign (str, n);
2083}
2084
2085//-----------------------------------------------------------------------------
2087{
2088 isWide = kWideStringDefault ? 1 : 0;
2089 fromVariant (var);
2090}
2091
2092//-----------------------------------------------------------------------------
2094{
2095 isWide = str->isWideString ();
2096 if (isWide)
2097 assign (str->getText16 ());
2098 else
2099 assign (str->getText8 ());
2100}
2101
2102//-----------------------------------------------------------------------------
2104{
2105 if (buffer)
2106 resize (0, false);
2107}
2108
2109#if SMTG_CPP11_STDLIBSUPPORT
2110//-----------------------------------------------------------------------------
2111String::String (String&& str)
2112{
2113 *this = std::move (str);
2114}
2115
2116//-----------------------------------------------------------------------------
2118{
2119 SMTG_ASSERT (buffer == nullptr || buffer != str.buffer);
2120 tryFreeBuffer ();
2121
2122 isWide = str.isWide;
2123 buffer = str.buffer;
2124 len = str.len;
2125 str.buffer = nullptr;
2126 str.len = 0;
2127 return *this;
2128}
2129#endif
2130
2131//-----------------------------------------------------------------------------
2133{
2134 if (isWide)
2135 len = strlen16 (text16 ());
2136 else
2137 len = strlen8 (text8 ());
2138}
2139
2140//-----------------------------------------------------------------------------
2141bool String::toWideString (uint32 sourceCodePage)
2142{
2143 if (!isWide)
2144 {
2145 if (buffer8 && len > 0)
2146 {
2147 int32 bytesNeeded = multiByteToWideString (nullptr, buffer8, 0, sourceCodePage) * sizeof (char16);
2148 if (bytesNeeded)
2149 {
2150 bytesNeeded += sizeof (char16);
2151 char16* newStr = (char16*) malloc (bytesNeeded);
2152 if (multiByteToWideString (newStr, buffer8, len + 1, sourceCodePage) <= 0)
2153 {
2154 free (newStr);
2155 return false;
2156 }
2157 free (buffer8);
2158 buffer16 = newStr;
2159 isWide = true;
2160 updateLength ();
2161 }
2162 else
2163 {
2164 return false;
2165 }
2166 }
2167 isWide = true;
2168 }
2169 return true;
2170}
2171
2172#define SMTG_STRING_CHECK_CONVERSION 1
2173#define SMTG_STRING_CHECK_CONVERSION_NO_BREAK 1
2174
2175#if SMTG_STRING_CHECK_CONVERSION_NO_BREAK
2176 #define SMTG_STRING_CHECK_MSG FDebugPrint
2177#else
2178 #define SMTG_STRING_CHECK_MSG FDebugBreak
2179#endif
2180//-----------------------------------------------------------------------------
2181bool String::checkToMultiByte (uint32 destCodePage) const
2182{
2183 if (!isWide || isEmpty ())
2184 return true;
2185
2186#if DEVELOPMENT && SMTG_STRING_CHECK_CONVERSION
2187 int debugLen = length ();
2188 int debugNonASCII = 0;
2189 for (int32 i = 0; i < length (); i++)
2190 {
2191 if (buffer16[i] > 127)
2192 ++debugNonASCII;
2193 }
2194
2195 String* backUp = nullptr;
2196 if (debugNonASCII > 0)
2197 backUp = NEW String (*this);
2198#endif
2199
2200 // this should be avoided, since it can lead to information loss
2201 bool result = const_cast <String&> (*this).toMultiByte (destCodePage);
2202
2203#if DEVELOPMENT && SMTG_STRING_CHECK_CONVERSION
2204 if (backUp)
2205 {
2206 String temp (*this);
2207 temp.toWideString (destCodePage);
2208
2209 if (temp != *backUp)
2210 {
2211 backUp->toMultiByte (kCP_Utf8);
2212 SMTG_STRING_CHECK_MSG ("Indirect string conversion information loss ! %d/%d non ASCII chars: \"%s\" -> \"%s\"\n", debugNonASCII, debugLen, backUp->buffer8, buffer8);
2213 }
2214 else
2215 SMTG_STRING_CHECK_MSG ("Indirect string potential conversion information loss ! %d/%d non ASCII chars result: \"%s\"\n", debugNonASCII, debugLen, buffer8);
2216
2217 delete backUp;
2218 }
2219#endif
2220
2221 return result;
2222}
2223
2224//-----------------------------------------------------------------------------
2225bool String::toMultiByte (uint32 destCodePage)
2226{
2227 if (isWide)
2228 {
2229 if (buffer16 && len > 0)
2230 {
2231 int32 numChars = wideStringToMultiByte (nullptr, buffer16, 0, destCodePage) + sizeof (char8);
2232 char8* newStr = (char8*) malloc (numChars * sizeof (char8));
2233 if (wideStringToMultiByte (newStr, buffer16, numChars, destCodePage) <= 0)
2234 {
2235 free (newStr);
2236 return false;
2237 }
2238 free (buffer16);
2239 buffer8 = newStr;
2240 isWide = false;
2241 updateLength ();
2242 }
2243 isWide = false;
2244 }
2245 else if (destCodePage != kCP_Default)
2246 {
2247 if (toWideString () == false)
2248 return false;
2249 return toMultiByte (destCodePage);
2250 }
2251 return true;
2252}
2253
2254//-----------------------------------------------------------------------------
2255void String::fromUTF8 (const char8* utf8String)
2256{
2257 assign (utf8String);
2259}
2260
2261//-----------------------------------------------------------------------------
2263{
2264 if (isWide == false)
2265 return false;
2266
2267 if (buffer16 == nullptr)
2268 return true;
2269
2270#if SMTG_OS_WINDOWS
2271#ifdef UNICODE
2272 if (n != kUnicodeNormC)
2273 return false;
2274
2275 uint32 normCharCount = static_cast<uint32> (FoldString (MAP_PRECOMPOSED, buffer16, len, nullptr, 0));
2276 if (normCharCount == len)
2277 return true;
2278
2279 char16* newString = (char16*)malloc ((normCharCount + 1) * sizeof (char16));
2280 uint32 converterCount = static_cast<uint32> (FoldString (MAP_PRECOMPOSED, buffer16, len, newString, normCharCount + 1));
2281 if (converterCount != normCharCount)
2282 {
2283 free (newString);
2284 return false;
2285 }
2286 newString [converterCount] = 0;
2287 free (buffer16);
2288 buffer16 = newString;
2289 updateLength ();
2290 return true;
2291#else
2292 return false;
2293#endif
2294
2295#elif SMTG_OS_MACOS
2296 CFMutableStringRef origStr = (CFMutableStringRef)toCFStringRef (0xFFFF, true);
2297 if (origStr)
2298 {
2299 CFStringNormalizationForm normForm = kCFStringNormalizationFormD;
2300 switch (n)
2301 {
2302 case kUnicodeNormC: normForm = kCFStringNormalizationFormC; break;
2303 case kUnicodeNormD: normForm = kCFStringNormalizationFormD; break;
2304 case kUnicodeNormKC: normForm = kCFStringNormalizationFormKC; break;
2305 case kUnicodeNormKD: normForm = kCFStringNormalizationFormKD; break;
2306 }
2307 CFStringNormalize (origStr, normForm);
2308 bool result = fromCFStringRef (origStr);
2309 CFRelease (origStr);
2310 return result;
2311 }
2312 return false;
2313#else
2314 return false;
2315#endif
2316}
2317
2318//-----------------------------------------------------------------------------
2320{
2321 if (buffer)
2322 {
2323 free (buffer);
2324 buffer = nullptr;
2325 }
2326}
2327
2328//-----------------------------------------------------------------------------
2329bool String::resize (uint32 newLength, bool wide, bool fill)
2330{
2331 if (newLength == 0)
2332 {
2333 tryFreeBuffer ();
2334 len = 0;
2335 isWide = wide ? 1 : 0;
2336 }
2337 else
2338 {
2339 size_t newCharSize = wide ? sizeof (char16) : sizeof (char8);
2340 size_t oldCharSize = (isWide != 0) ? sizeof (char16) : sizeof (char8);
2341
2342 size_t newBufferSize = (newLength + 1) * newCharSize;
2343 size_t oldBufferSize = (len + 1) * oldCharSize;
2344
2345 isWide = wide ? 1 : 0;
2346
2347 if (buffer)
2348 {
2349 if (newBufferSize != oldBufferSize)
2350 {
2351 void* newstr = realloc (buffer, newBufferSize);
2352 if (newstr == nullptr)
2353 return false;
2354 buffer = newstr;
2355 if (isWide)
2356 buffer16[newLength] = 0;
2357 else
2358 buffer8[newLength] = 0;
2359 }
2360 else if (wide && newCharSize != oldCharSize)
2361 buffer16[newLength] = 0;
2362 }
2363 else
2364 {
2365 void* newstr = malloc (newBufferSize);
2366 if (newstr == nullptr)
2367 return false;
2368 buffer = newstr;
2369 if (isWide)
2370 {
2371 buffer16[0] = 0;
2372 buffer16[newLength] = 0;
2373 }
2374 else
2375 {
2376 buffer8[0] = 0;
2377 buffer8[newLength] = 0;
2378 }
2379 }
2380
2381 if (fill && len < newLength && buffer)
2382 {
2383 if (isWide)
2384 {
2385 char16 c = ' ';
2386 for (uint32 i = len; i < newLength; i++)
2387 buffer16 [i] = c;
2388 }
2389 else
2390 {
2391 memset (buffer8 + len, ' ', newLength - len);
2392 }
2393 }
2394 }
2395 return true;
2396}
2397
2398//-----------------------------------------------------------------------------
2400{
2401 if (index == len && c == 0)
2402 return true;
2403
2404 if (index >= len)
2405 {
2406 if (c == 0)
2407 {
2408 if (resize (index, isWide, true) == false)
2409 return false;
2410 len = index;
2411 return true;
2412 }
2413 else
2414 {
2415 if (resize (index + 1, isWide, true) == false)
2416 return false;
2417 len = index + 1;
2418 }
2419 }
2420
2421 if (index < len && buffer)
2422 {
2423 if (isWide)
2424 {
2425 if (c == 0)
2426 buffer16[index] = 0;
2427 else
2428 {
2429 char8 src[] = {c, 0};
2430 char16 dest[8] = {0};
2431 if (multiByteToWideString (dest, src, 2) > 0)
2432 buffer16[index] = dest[0];
2433 }
2434 SMTG_ASSERT (buffer16[len] == 0)
2435 }
2436 else
2437 {
2438 buffer8[index] = c;
2439 SMTG_ASSERT (buffer8[len] == 0)
2440 }
2441
2442 if (c == 0)
2443 updateLength ();
2444
2445 return true;
2446 }
2447 return false;
2448}
2449
2450//-----------------------------------------------------------------------------
2452{
2453 if (index == len && c == 0)
2454 return true;
2455
2456 if (index >= len)
2457 {
2458 if (c == 0)
2459 {
2460 if (resize (index, isWide, true) == false)
2461 return false;
2462 len = index;
2463 return true;
2464 }
2465 else
2466 {
2467 if (resize (index + 1, isWide, true) == false)
2468 return false;
2469 len = index + 1;
2470 }
2471 }
2472
2473 if (index < len && buffer)
2474 {
2475 if (isWide)
2476 {
2477 buffer16[index] = c;
2478 SMTG_ASSERT (buffer16[len] == 0)
2479 }
2480 else
2481 {
2482 SMTG_ASSERT (buffer8[len] == 0)
2483 char16 src[] = {c, 0};
2484 char8 dest[8] = {0};
2485 if (wideStringToMultiByte (dest, src, 2) > 0 && dest[1] == 0)
2486 buffer8[index] = dest[0];
2487 else
2488 return false;
2489 }
2490
2491 if (c == 0)
2492 updateLength ();
2493
2494 return true;
2495 }
2496 return false;
2497}
2498
2499//-----------------------------------------------------------------------------
2501{
2502 if (str.isWideString ())
2503 return assign (str.text16 (), n < 0 ? str.length () : n);
2504 else
2505 return assign (str.text8 (), n < 0 ? str.length () : n);
2506}
2507
2508//-----------------------------------------------------------------------------
2509String& String::assign (const char8* str, int32 n, bool isTerminated)
2510{
2511 if (str == buffer8)
2512 return *this;
2513
2514 if (isTerminated)
2515 {
2516 uint32 stringLength = (uint32)((str) ? strlen (str) : 0);
2517 n = n < 0 ? stringLength : Min<uint32> (n, stringLength);
2518 }
2519 else if (n < 0)
2520 return *this;
2521
2522 if (resize (n, false))
2523 {
2524 if (buffer8 && n > 0 && str)
2525 {
2526 memcpy (buffer8, str, n * sizeof (char8));
2527 SMTG_ASSERT (buffer8[n] == 0)
2528 }
2529 isWide = 0;
2530 len = n;
2531 }
2532 return *this;
2533}
2534
2535//-----------------------------------------------------------------------------
2536String& String::assign (const char16* str, int32 n, bool isTerminated)
2537{
2538 if (str == buffer16)
2539 return *this;
2540
2541 if (isTerminated)
2542 {
2543 uint32 stringLength = (uint32)((str) ? strlen16 (str) : 0);
2544 n = n < 0 ? stringLength : Min<uint32> (n, stringLength);
2545 }
2546 else if (n < 0)
2547 return *this;
2548
2549 if (resize (n, true))
2550 {
2551 if (buffer16 && n > 0 && str)
2552 {
2553 memcpy (buffer16, str, n * sizeof (char16));
2554 SMTG_ASSERT (buffer16[n] == 0)
2555 }
2556 isWide = 1;
2557 len = n;
2558 }
2559 return *this;
2560}
2561
2562//-----------------------------------------------------------------------------
2564{
2565 if (resize (n, false))
2566 {
2567 if (buffer8 && n > 0)
2568 {
2569 memset (buffer8, c, n * sizeof (char8));
2570 SMTG_ASSERT (buffer8[n] == 0)
2571 }
2572 isWide = 0;
2573 len = n;
2574 }
2575 return *this;
2576
2577}
2578
2579//-----------------------------------------------------------------------------
2581{
2582 if (resize (n, true))
2583 {
2584 if (buffer && n > 0)
2585 {
2586 for (int32 i = 0; i < n; i++)
2587 buffer16[i] = c;
2588 SMTG_ASSERT (buffer16[n] == 0)
2589 }
2590 isWide = 1;
2591 len = n;
2592 }
2593 return *this;
2594}
2595
2596//-----------------------------------------------------------------------------
2598{
2599 if (str.isWideString ())
2600 return append (str.text16 (), n);
2601 else
2602 return append (str.text8 (), n);
2603}
2604
2605//-----------------------------------------------------------------------------
2607{
2608 if (str == buffer8)
2609 return *this;
2610
2611 if (len == 0)
2612 return assign (str, n);
2613
2614 if (isWide)
2615 {
2616 String tmp (str);
2617 if (tmp.toWideString () == false)
2618 return *this;
2619
2620 return append (tmp.buffer16, n);
2621 }
2622
2623 uint32 stringLength = (uint32)((str) ? strlen (str) : 0);
2624 n = n < 0 ? stringLength : Min<uint32> (n, stringLength);
2625
2626 if (n > 0)
2627 {
2628 int32 newlen = n + len;
2629 if (!resize (newlen, false))
2630 return *this;
2631
2632 if (buffer && str)
2633 {
2634 memcpy (buffer8 + len, str, n * sizeof (char8));
2635 SMTG_ASSERT (buffer8[newlen] == 0)
2636 }
2637
2638 len += n;
2639 }
2640 return *this;
2641}
2642
2643//-----------------------------------------------------------------------------
2645{
2646 if (str == buffer16)
2647 return *this;
2648
2649 if (len == 0)
2650 return assign (str, n);
2651
2652 if (!isWide)
2653 {
2654 if (toWideString () == false)
2655 return *this;
2656 }
2657
2658 uint32 stringLength = (uint32)((str) ? strlen16 (str) : 0);
2659 n = n < 0 ? stringLength : Min<uint32> (n, stringLength);
2660
2661 if (n > 0)
2662 {
2663 int32 newlen = n + len;
2664 if (!resize (newlen, true))
2665 return *this;
2666
2667 if (buffer16 && str)
2668 {
2669 memcpy (buffer16 + len, str, n * sizeof (char16));
2670 SMTG_ASSERT (buffer16[newlen] == 0)
2671 }
2672
2673 len += n;
2674 }
2675 return *this;
2676}
2677
2678//-----------------------------------------------------------------------------
2680{
2681 char8 str[] = {c, 0};
2682 if (n == 1)
2683 {
2684 return append (str, 1);
2685 }
2686 else if (n > 1)
2687 {
2688 if (isWide)
2689 {
2690 String tmp (str);
2691 if (tmp.toWideString () == false)
2692 return *this;
2693
2694 return append (tmp.buffer16[0], n);
2695 }
2696
2697 int32 newlen = n + len;
2698 if (!resize (newlen, false))
2699 return *this;
2700
2701 if (buffer)
2702 {
2703 memset (buffer8 + len, c, n * sizeof (char8));
2704 SMTG_ASSERT (buffer8[newlen] == 0)
2705 }
2706
2707 len += n;
2708 }
2709 return *this;
2710}
2711
2712//-----------------------------------------------------------------------------
2714{
2715 if (n == 1)
2716 {
2717 char16 str[] = {c, 0};
2718 return append (str, 1);
2719 }
2720 else if (n > 1)
2721 {
2722 if (!isWide)
2723 {
2724 if (toWideString () == false)
2725 return *this;
2726 }
2727
2728 int32 newlen = n + len;
2729 if (!resize (newlen, true))
2730 return *this;
2731
2732 if (buffer16)
2733 {
2734 for (int32 i = len; i < newlen; i++)
2735 buffer16[i] = c;
2736 SMTG_ASSERT (buffer16[newlen] == 0)
2737 }
2738
2739 len += n;
2740 }
2741 return *this;
2742}
2743
2744//-----------------------------------------------------------------------------
2746{
2747 if (str.isWideString ())
2748 return insertAt (idx, str.text16 (), n);
2749 else
2750 return insertAt (idx, str.text8 (), n);
2751}
2752
2753//-----------------------------------------------------------------------------
2755{
2756 if (idx > len)
2757 return *this;
2758
2759 if (isWide)
2760 {
2761 String tmp (str);
2762 if (tmp.toWideString () == false)
2763 return *this;
2764 return insertAt (idx, tmp.buffer16, n);
2765 }
2766
2767 uint32 stringLength = (uint32)((str) ? strlen (str) : 0);
2768 n = n < 0 ? stringLength : Min<uint32> (n, stringLength);
2769
2770 if (n > 0)
2771 {
2772 int32 newlen = len + n;
2773 if (!resize (newlen, false))
2774 return *this;
2775
2776 if (buffer && str)
2777 {
2778 if (idx < len)
2779 memmove (buffer8 + idx + n, buffer8 + idx, (len - idx) * sizeof (char8));
2780 memcpy (buffer8 + idx, str, n * sizeof (char8));
2781 SMTG_ASSERT (buffer8[newlen] == 0)
2782 }
2783
2784 len += n;
2785 }
2786 return *this;
2787}
2788
2789//-----------------------------------------------------------------------------
2791{
2792 if (idx > len)
2793 return *this;
2794
2795 if (!isWide)
2796 {
2797 if (toWideString () == false)
2798 return *this;
2799 }
2800
2801 uint32 stringLength = (uint32)((str) ? strlen16 (str) : 0);
2802 n = n < 0 ? stringLength : Min<uint32> (n, stringLength);
2803
2804 if (n > 0)
2805 {
2806 int32 newlen = len + n;
2807 if (!resize (newlen, true))
2808 return *this;
2809
2810 if (buffer && str)
2811 {
2812 if (idx < len)
2813 memmove (buffer16 + idx + n, buffer16 + idx, (len - idx) * sizeof (char16));
2814 memcpy (buffer16 + idx, str, n * sizeof (char16));
2815 SMTG_ASSERT (buffer16[newlen] == 0)
2816 }
2817
2818 len += n;
2819 }
2820 return *this;
2821}
2822
2823//-----------------------------------------------------------------------------
2825{
2826 if (str.isWideString ())
2827 return replace (idx, n1, str.text16 (), n2);
2828 else
2829 return replace (idx, n1, str.text8 (), n2);
2830}
2831
2832// "replace" replaces n1 number of characters at the specified index with
2833// n2 characters from the specified string.
2834//-----------------------------------------------------------------------------
2835String& String::replace (uint32 idx, int32 n1, const char8* str, int32 n2)
2836{
2837 if (idx > len || str == nullptr)
2838 return *this;
2839
2840 if (isWide)
2841 {
2842 String tmp (str);
2843 if (tmp.toWideString () == false)
2844 return *this;
2845 if (tmp.length () == 0 || n2 == 0)
2846 return remove (idx, n1);
2847 return replace (idx, n1, tmp.buffer16, n2);
2848 }
2849
2850 if (n1 < 0 || idx + n1 > len)
2851 n1 = len - idx;
2852 if (n1 == 0)
2853 return *this;
2854
2855 uint32 stringLength = (uint32)((str) ? strlen (str) : 0);
2856 n2 = n2 < 0 ? stringLength : Min<uint32> (n2, stringLength);
2857
2858 uint32 newlen = len - n1 + n2;
2859 if (newlen > len)
2860 if (!resize (newlen, false))
2861 return *this;
2862
2863 if (buffer)
2864 {
2865 memmove (buffer8 + idx + n2, buffer8 + idx + n1, (len - (idx + n1)) * sizeof (char8));
2866 memcpy (buffer8 + idx, str, n2 * sizeof (char8));
2867 buffer8[newlen] = 0; // cannot be removed because resize is not called called in all cases (newlen > len)
2868 }
2869
2870 len = newlen;
2871
2872 return *this;
2873}
2874
2875//-----------------------------------------------------------------------------
2876String& String::replace (uint32 idx, int32 n1, const char16* str, int32 n2)
2877{
2878 if (idx > len || str == nullptr)
2879 return *this;
2880
2881 if (!isWide)
2882 {
2883 if (toWideString () == false)
2884 return *this;
2885 }
2886
2887 if (n1 < 0 || idx + n1 > len)
2888 n1 = len - idx;
2889 if (n1 == 0)
2890 return *this;
2891
2892 uint32 stringLength = (uint32)((str) ? strlen16 (str) : 0);
2893 n2 = n2 < 0 ? stringLength : Min<uint32> (n2, stringLength);
2894
2895 uint32 newlen = len - n1 + n2;
2896 if (newlen > len)
2897 if (!resize (newlen, true))
2898 return *this;
2899
2900 if (buffer)
2901 {
2902 memmove (buffer16 + idx + n2, buffer16 + idx + n1, (len - (idx + n1)) * sizeof (char16));
2903 memcpy (buffer16 + idx, str, n2 * sizeof (char16));
2904 buffer16[newlen] = 0; // cannot be removed because resize is not called called in all cases (newlen > len)
2905 }
2906
2907 len = newlen;
2908
2909 return *this;
2910}
2911
2912//-----------------------------------------------------------------------------
2913int32 String::replace (const char8* toReplace, const char8* toReplaceWith, bool all, CompareMode m)
2914{
2915 if (toReplace == nullptr || toReplaceWith == nullptr)
2916 return 0;
2917
2918 int32 result = 0;
2919
2920 int32 idx = findFirst (toReplace, -1, m);
2921 if (idx > -1)
2922 {
2923 int32 toReplaceLen = static_cast<int32> (strlen (toReplace));
2924 int32 toReplaceWithLen = static_cast<int32> (strlen (toReplaceWith));
2925 while (idx > -1)
2926 {
2927 replace (idx, toReplaceLen, toReplaceWith, toReplaceWithLen);
2928 result++;
2929
2930 if (all)
2931 idx = findNext (idx + toReplaceWithLen , toReplace, -1, m);
2932 else
2933 break;
2934 }
2935 }
2936
2937 return result;
2938}
2939
2940//-----------------------------------------------------------------------------
2941int32 String::replace (const char16* toReplace, const char16* toReplaceWith, bool all, CompareMode m)
2942{
2943 if (toReplace == nullptr || toReplaceWith == nullptr)
2944 return 0;
2945
2946 int32 result = 0;
2947
2948 int32 idx = findFirst (toReplace, -1, m);
2949 if (idx > -1)
2950 {
2951 int32 toReplaceLen = strlen16 (toReplace);
2952 int32 toReplaceWithLen = strlen16 (toReplaceWith);
2953 while (idx > -1)
2954 {
2955 replace (idx, toReplaceLen, toReplaceWith, toReplaceWithLen);
2956 result++;
2957
2958 if (all)
2959 idx = findNext (idx + toReplaceWithLen, toReplace, -1, m);
2960 else
2961 break;
2962 }
2963 }
2964 return result;
2965}
2966
2967//-----------------------------------------------------------------------------
2968template <class T>
2969static bool performReplace (T* str, const T* toReplace, T toReplaceBy)
2970{
2971 bool anyReplace = false;
2972 T* p = str;
2973 while (*p)
2974 {
2975 const T* rep = toReplace;
2976 while (*rep)
2977 {
2978 if (*p == *rep)
2979 {
2980 *p = toReplaceBy;
2981 anyReplace = true;
2982 break;
2983 }
2984 rep++;
2985 }
2986 p++;
2987 }
2988 return anyReplace;
2989}
2990
2991//-----------------------------------------------------------------------------
2992bool String::replaceChars8 (const char8* toReplace, char8 toReplaceBy)
2993{
2994 if (isEmpty ())
2995 return false;
2996
2997 if (isWide)
2998 {
2999 String toReplaceW (toReplace);
3000 if (toReplaceW.toWideString () == false)
3001 return false;
3002
3003 char8 src[] = {toReplaceBy, 0};
3004 char16 dest[2] = {0};
3005 if (multiByteToWideString (dest, src, 2) > 0)
3006 {
3007 return replaceChars16 (toReplaceW.text16 (), dest[0]);
3008 }
3009 return false;
3010 }
3011
3012 if (toReplaceBy == 0)
3013 toReplaceBy = ' ';
3014
3015 return performReplace<char8> (buffer8, toReplace, toReplaceBy);
3016}
3017
3018//-----------------------------------------------------------------------------
3019bool String::replaceChars16 (const char16* toReplace, char16 toReplaceBy)
3020{
3021 if (isEmpty ())
3022 return false;
3023
3024 if (!isWide)
3025 {
3026 String toReplaceA (toReplace);
3027 if (toReplaceA.toMultiByte () == false)
3028 return false;
3029
3030 if (toReplaceA.length () > 1)
3031 {
3032 SMTG_WARNING("cannot replace non ASCII chars on non Wide String")
3033 return false;
3034 }
3035
3036 char16 src[] = {toReplaceBy, 0};
3037 char8 dest[8] = {0};
3038 if (wideStringToMultiByte (dest, src, 2) > 0 && dest[1] == 0)
3039 return replaceChars8 (toReplaceA.text8 (), dest[0]);
3040
3041 return false;
3042 }
3043
3044 if (toReplaceBy == 0)
3045 toReplaceBy = STR16 (' ');
3046
3047 return performReplace<char16> (buffer16, toReplace, toReplaceBy);
3048}
3049
3050// "remove" removes the specified number of characters from the string
3051// starting at the specified index.
3052//-----------------------------------------------------------------------------
3054{
3055 if (isEmpty () || idx >= len || n == 0)
3056 return *this;
3057
3058 if ((idx + n > len) || n < 0)
3059 n = len - idx;
3060 else
3061 {
3062 int32 toMove = len - idx - n;
3063 if (buffer)
3064 {
3065 if (isWide)
3066 memmove (buffer16 + idx, buffer16 + idx + n, toMove * sizeof (char16));
3067 else
3068 memmove (buffer8 + idx, buffer8 + idx + n, toMove * sizeof (char8));
3069 }
3070 }
3071
3072 resize (len - n, isWide);
3073 updateLength ();
3074
3075 return *this;
3076}
3077
3078//-----------------------------------------------------------------------------
3079bool String::removeSubString (const ConstString& subString, bool allOccurences)
3080{
3081 bool removed = false;
3082 while (!removed || allOccurences)
3083 {
3084 int32 idx = findFirst (subString);
3085 if (idx < 0)
3086 break;
3087 remove (idx, subString.length ());
3088 removed = true;
3089 }
3090 return removed;
3091}
3092
3093//-----------------------------------------------------------------------------
3094template <class T, class F>
3095static uint32 performTrim (T* str, uint32 length, F func, bool funcResult)
3096{
3097 uint32 toRemoveAtHead = 0;
3098 uint32 toRemoveAtTail = 0;
3099
3100 T* p = str;
3101
3102 while ((*p) && ((func (*p) != 0) == funcResult))
3103 p++;
3104
3105 toRemoveAtHead = static_cast<uint32> (p - str);
3106
3107 if (toRemoveAtHead < length)
3108 {
3109 p = str + length - 1;
3110
3111 while (((func (*p) != 0) == funcResult) && (p > str))
3112 {
3113 p--;
3114 toRemoveAtTail++;
3115 }
3116 }
3117
3118 uint32 newLength = length - (toRemoveAtHead + toRemoveAtTail);
3119 if (newLength != length)
3120 {
3121 if (toRemoveAtHead)
3122 memmove (str, str + toRemoveAtHead, newLength * sizeof (T));
3123 }
3124 return newLength;
3125}
3126
3127// "trim" trims the leading and trailing unwanted characters from the string.
3128//-----------------------------------------------------------------------------
3130{
3131 if (isEmpty ())
3132 return false;
3133
3134 uint32 newLength;
3135
3136 switch (group)
3137 {
3138 case kSpace:
3139 if (isWide)
3140 newLength = performTrim<char16> (buffer16, len, iswspace, true);
3141 else
3142 newLength = performTrim<char8> (buffer8, len, isspace, true);
3143 break;
3144
3145 case kNotAlphaNum:
3146 if (isWide)
3147 newLength = performTrim<char16> (buffer16, len, iswalnum, false);
3148 else
3149 newLength = performTrim<char8> (buffer8, len, isalnum, false);
3150 break;
3151
3152 case kNotAlpha:
3153 if (isWide)
3154 newLength = performTrim<char16> (buffer16, len, iswalpha, false);
3155 else
3156 newLength = performTrim<char8> (buffer8, len, isalpha, false);
3157 break;
3158
3159 default: // Undefined enum value
3160 return false;
3161 }
3162
3163 if (newLength != len)
3164 {
3165 resize (newLength, isWide);
3166 len = newLength;
3167 return true;
3168 }
3169 return false;
3170}
3171
3172//-----------------------------------------------------------------------------
3173template <class T, class F>
3174static uint32 performRemove (T* str, uint32 length, F func, bool funcResult)
3175{
3176 T* p = str;
3177
3178 while (*p)
3179 {
3180 if ((func (*p) != 0) == funcResult)
3181 {
3182 size_t toMove = length - (p - str);
3183 memmove (p, p + 1, toMove * sizeof (T));
3184 length--;
3185 }
3186 else
3187 p++;
3188 }
3189 return length;
3190}
3191//-----------------------------------------------------------------------------
3193{
3194 if (isEmpty ())
3195 return;
3196
3197 uint32 newLength;
3198
3199 switch (group)
3200 {
3201 case kSpace:
3202 if (isWide)
3203 newLength = performRemove<char16> (buffer16, len, iswspace, true);
3204 else
3205 newLength = performRemove<char8> (buffer8, len, isspace, true);
3206 break;
3207
3208 case kNotAlphaNum:
3209 if (isWide)
3210 newLength = performRemove<char16> (buffer16, len, iswalnum, false);
3211 else
3212 newLength = performRemove<char8> (buffer8, len, isalnum, false);
3213 break;
3214
3215 case kNotAlpha:
3216 if (isWide)
3217 newLength = performRemove<char16> (buffer16, len, iswalpha, false);
3218 else
3219 newLength = performRemove<char8> (buffer8, len, isalpha, false);
3220 break;
3221
3222 default: // Undefined enum value
3223 return;
3224 }
3225
3226 if (newLength != len)
3227 {
3228 resize (newLength, isWide);
3229 len = newLength;
3230 }
3231}
3232
3233//-----------------------------------------------------------------------------
3234template <class T>
3235static uint32 performRemoveChars (T* str, uint32 length, const T* toRemove)
3236{
3237 T* p = str;
3238
3239 while (*p)
3240 {
3241 bool found = false;
3242 const T* rem = toRemove;
3243 while (*rem)
3244 {
3245 if (*p == *rem)
3246 {
3247 found = true;
3248 break;
3249 }
3250 rem++;
3251 }
3252
3253 if (found)
3254 {
3255 size_t toMove = length - (p - str);
3256 memmove (p, p + 1, toMove * sizeof (T));
3257 length--;
3258 }
3259 else
3260 p++;
3261 }
3262 return length;
3263}
3264
3265//-----------------------------------------------------------------------------
3266bool String::removeChars8 (const char8* toRemove)
3267{
3268 if (isEmpty () || toRemove == nullptr)
3269 return true;
3270
3271 if (isWide)
3272 {
3273 String wStr (toRemove);
3274 if (wStr.toWideString () == false)
3275 return false;
3276 return removeChars16 (wStr.text16 ());
3277 }
3278
3279 uint32 newLength = performRemoveChars<char8> (buffer8, len, toRemove);
3280
3281 if (newLength != len)
3282 {
3283 resize (newLength, false);
3284 len = newLength;
3285 }
3286 return true;
3287}
3288
3289//-----------------------------------------------------------------------------
3290bool String::removeChars16 (const char16* toRemove)
3291{
3292 if (isEmpty () || toRemove == nullptr)
3293 return true;
3294
3295 if (!isWide)
3296 {
3297 String str8 (toRemove);
3298 if (str8.toMultiByte () == false)
3299 return false;
3300 return removeChars8 (str8.text8 ());
3301 }
3302
3303 uint32 newLength = performRemoveChars<char16> (buffer16, len, toRemove);
3304
3305 if (newLength != len)
3306 {
3307 resize (newLength, true);
3308 len = newLength;
3309 }
3310 return true;
3311}
3312
3313//-----------------------------------------------------------------------------
3315{
3316 char8 string[kPrintfBufferSize];
3317
3318 va_list marker;
3319 va_start (marker, format);
3320
3321 vsnprintf (string, kPrintfBufferSize-1, format, marker);
3322 return assign (string);
3323}
3324
3325
3326//-----------------------------------------------------------------------------
3328{
3329 char16 string[kPrintfBufferSize];
3330
3331 va_list marker;
3332 va_start (marker, format);
3333
3334 vsnwprintf (string, kPrintfBufferSize-1, format, marker);
3335 return assign (string);
3336}
3337
3338//-----------------------------------------------------------------------------
3339String& String::vprintf (const char8* format, va_list args)
3340{
3341 char8 string[kPrintfBufferSize];
3342
3343 vsnprintf (string, kPrintfBufferSize-1, format, args);
3344 return assign (string);
3345}
3346
3347//-----------------------------------------------------------------------------
3348String& String::vprintf (const char16* format, va_list args)
3349{
3350 char16 string[kPrintfBufferSize];
3351
3352 vsnwprintf (string, kPrintfBufferSize-1, format, args);
3353 return assign (string);
3354}
3355
3356//-----------------------------------------------------------------------------
3358{
3359 if (isWide)
3360 {
3361 #if SMTG_CPP11
3362 return String::printf (STR("%") STR(FORMAT_INT64A), value);
3363 #else
3364 return String::printf (STR("%" FORMAT_INT64A), value);
3365 #endif
3366 }
3367 else
3368 return String::printf ("%" FORMAT_INT64A, value);
3369}
3370
3371//-----------------------------------------------------------------------------
3373{
3374 if (isWide)
3375 {
3376 char16 string[kPrintfBufferSize];
3377 sprintf16 (string, STR16 ("%lf"), value);
3378
3379 char16* pointPtr = strrchr16 (string, STR ('.'));
3380 if (pointPtr)
3381 {
3382 pointPtr++; // keep 1st digit after point
3383 int32 index = strlen16 (string) - 1;
3384 char16 zero = STR16 ('0');
3385 while (pointPtr < (string + index))
3386 {
3387 if (string[index] == zero)
3388 {
3389 string[index] = 0;
3390 index--;
3391 }
3392 else
3393 break;
3394 }
3395 }
3396 return assign (string);
3397 }
3398 else
3399 {
3400 char8 string[kPrintfBufferSize];
3401 sprintf (string, "%lf", value);
3402
3403 char8* pointPtr = strrchr (string, '.');
3404 if (pointPtr)
3405 {
3406 pointPtr++; // keep 1st digit after point
3407 int32 index = (int32) (strlen (string) - 1);
3408 while (pointPtr < (string + index))
3409 {
3410 if (string[index] == '0')
3411 {
3412 string[index] = 0;
3413 index--;
3414 }
3415 else
3416 break;
3417 }
3418 }
3419 return assign (string);
3420 }
3421}
3422
3423//-----------------------------------------------------------------------------
3424bool String::incrementTrailingNumber (uint32 width, tchar separator, uint32 minNumber, bool applyOnlyFormat)
3425{
3426 if (width > 32)
3427 return false;
3428
3429 int64 number = 1;
3430 int32 index = getTrailingNumberIndex ();
3431 if (index >= 0)
3432 {
3433 if (scanInt64 (number, index))
3434 if (!applyOnlyFormat)
3435 number++;
3436
3437 if (separator != 0 && index > 0 && testChar (index - 1, separator) == true)
3438 index--;
3439
3440 remove (index);
3441 }
3442
3443 if (number < minNumber)
3444 number = minNumber;
3445
3446 if (isWide)
3447 {
3448 char16 format[64];
3449 char16 trail[128];
3450 if (separator && isEmpty () == false)
3451 {
3452 sprintf16 (format, STR16 ("%%c%%0%uu"), width);
3453 sprintf16 (trail, format, separator, (uint32) number);
3454 }
3455 else
3456 {
3457 sprintf16 (format, STR16 ("%%0%uu"), width);
3458 sprintf16 (trail, format, (uint32) number);
3459 }
3460 append (trail);
3461 }
3462 else
3463 {
3464 char format[64];
3465 char trail[128];
3466 if (separator && isEmpty () == false)
3467 {
3468 sprintf (format, "%%c%%0%uu", width);
3469 sprintf (trail, format, separator, (uint32) number);
3470 }
3471 else
3472 {
3473 sprintf (format, "%%0%uu", width);
3474 sprintf (trail, format, (uint32) number);
3475 }
3476 append (trail);
3477 }
3478
3479 return true;
3480}
3481
3482//-----------------------------------------------------------------------------
3484{
3485 if (buffer && index < len)
3486 {
3487 if (isWide)
3488 buffer16[index] = ConstString::toLower (buffer16[index]);
3489 else
3490 buffer8[index] = ConstString::toLower (buffer8[index]);
3491 }
3492}
3493
3494//-----------------------------------------------------------------------------
3496{
3497 int32 i = len;
3498 if (buffer && i > 0)
3499 {
3500 if (isWide)
3501 {
3502#if SMTG_OS_MACOS
3503 CFMutableStringRef cfStr = CFStringCreateMutableWithExternalCharactersNoCopy (kCFAllocator, (UniChar*)buffer16, len, len+1, kCFAllocatorNull);
3504 CFStringLowercase (cfStr, NULL);
3505 CFRelease (cfStr);
3506#else
3507 char16* c = buffer16;
3508 while (i--)
3509 {
3510 *c = ConstString::toLower (*c);
3511 c++;
3512 }
3513#endif
3514 }
3515 else
3516 {
3517 char8* c = buffer8;
3518 while (i--)
3519 {
3520 *c = ConstString::toLower (*c);
3521 c++;
3522 }
3523 }
3524 }
3525}
3526
3527//-----------------------------------------------------------------------------
3529{
3530 if (buffer && index < len)
3531 {
3532 if (isWide)
3533 buffer16[index] = ConstString::toUpper (buffer16[index]);
3534 else
3535 buffer8[index] = ConstString::toUpper (buffer8[index]);
3536 }
3537}
3538
3539//-----------------------------------------------------------------------------
3541{
3542 int32 i = len;
3543 if (buffer && i > 0)
3544 {
3545 if (isWide)
3546 {
3547#if SMTG_OS_MACOS
3548 CFMutableStringRef cfStr = CFStringCreateMutableWithExternalCharactersNoCopy (kCFAllocator, (UniChar*)buffer16, len, len+1, kCFAllocatorNull);
3549 CFStringUppercase (cfStr, NULL);
3550 CFRelease (cfStr);
3551#else
3552 char16* c = buffer16;
3553 while (i--)
3554 {
3555 *c = ConstString::toUpper (*c);
3556 c++;
3557 }
3558#endif
3559 }
3560 else
3561 {
3562 char8* c = buffer8;
3563 while (i--)
3564 {
3565 *c = ConstString::toUpper (*c);
3566 c++;
3567 }
3568 }
3569 }
3570}
3571
3572//-----------------------------------------------------------------------------
3574{
3575 switch (var.getType ())
3576 {
3577 case FVariant::kString8:
3578 assign (var.getString8 ());
3579 return true;
3580
3582 assign (var.getString16 ());
3583 return true;
3584
3585 case FVariant::kFloat:
3586 printFloat (var.getFloat ());
3587 return true;
3588
3589 case FVariant::kInteger:
3590 printInt64 (var.getInt ());
3591 return true;
3592
3593 default:
3594 remove ();
3595 }
3596 return false;
3597}
3598
3599//-----------------------------------------------------------------------------
3601{
3602 if (isWide)
3603 {
3604 var.setString16 (text16 ());
3605 }
3606 else
3607 {
3608 var.setString8 (text8 ());
3609 }
3610}
3611
3612//-----------------------------------------------------------------------------
3614{
3615 FVariant variant;
3616 if (a->get (attrID, variant) == kResultTrue)
3617 return fromVariant (variant);
3618 return false;
3619}
3620
3621//-----------------------------------------------------------------------------
3623{
3624 FVariant variant;
3625 toVariant (variant);
3626 if (a->set (attrID, variant) == kResultTrue)
3627 return true;
3628 return false;
3629}
3630
3631// "swapContent" swaps ownership of the strings pointed to
3632//-----------------------------------------------------------------------------
3634{
3635 void* tmp = s.buffer;
3636 uint32 tmpLen = s.len;
3637 bool tmpWide = s.isWide;
3638 s.buffer = buffer;
3639 s.len = len;
3640 s.isWide = isWide;
3641 buffer = tmp;
3642 len = tmpLen;
3643 isWide = tmpWide;
3644}
3645
3646//-----------------------------------------------------------------------------
3648{
3649 resize (0, other.isWide);
3650 buffer = other.buffer;
3651 len = other.len;
3652
3653 other.buffer = nullptr;
3654 other.len = 0;
3655}
3656
3657//-----------------------------------------------------------------------------
3658void String::take (void* b, bool wide)
3659{
3660 resize (0, wide);
3661 buffer = b;
3662 isWide = wide;
3663 updateLength ();
3664}
3665
3666//-----------------------------------------------------------------------------
3668{
3669 void* res = buffer;
3670 len = 0;
3671 buffer = nullptr;
3672 return res;
3673}
3674
3675//-----------------------------------------------------------------------------
3677{
3678 void* passed = pass ();
3679
3680 if (isWide)
3681 {
3682 if (passed)
3683 {
3684 var.setString16 ((const char16*)passed);
3685 var.setOwner (true);
3686 }
3687 else
3689 }
3690 else
3691 {
3692 if (passed)
3693 {
3694 var.setString8 ((const char8*)passed);
3695 var.setOwner (true);
3696 }
3697 else
3699 }
3700}
3701
3702
3703//-----------------------------------------------------------------------------
3704unsigned char* String::toPascalString (unsigned char* buf)
3705{
3706 if (buffer)
3707 {
3708 if (isWide)
3709 {
3710 String tmp (*this);
3711 tmp.toMultiByte ();
3712 return tmp.toPascalString (buf);
3713 }
3714
3715 int32 length = len;
3716 if (length > 255)
3717 length = 255;
3718 buf[0] = (uint8)length;
3719 while (length >= 0)
3720 {
3721 buf[length + 1] = buffer8[length];
3722 length--;
3723 }
3724 return buf;
3725 }
3726 else
3727 {
3728 *buf = 0;
3729 return buf;
3730 }
3731}
3732
3733//-----------------------------------------------------------------------------
3734const String& String::fromPascalString (const unsigned char* buf)
3735{
3736 resize (0, false);
3737 isWide = 0;
3738 int32 length = buf[0];
3739 resize (length + 1, false);
3740 buffer8[length] = 0; // cannot be removed, because we only do the 0-termination for multibyte buffer8
3741 while (--length >= 0)
3742 buffer8[length] = buf[length + 1];
3743 len = buf[0];
3744 return *this;
3745}
3746
3747#if SMTG_OS_MACOS
3748
3749//-----------------------------------------------------------------------------
3750bool String::fromCFStringRef (const void* cfStr, uint32 encoding)
3751{
3752 if (cfStr == 0)
3753 return false;
3754
3755 CFStringRef strRef = (CFStringRef)cfStr;
3756 if (isWide)
3757 {
3758 CFRange range = { 0, CFStringGetLength (strRef)};
3759 CFIndex usedBytes;
3760 if (resize (static_cast<int32> (range.length + 1), true))
3761 {
3762 if (encoding == 0xFFFF)
3763 encoding = kCFStringEncodingUnicode;
3764 if (CFStringGetBytes (strRef, range, encoding, ' ', false, (UInt8*)buffer16, range.length * 2, &usedBytes) > 0)
3765 {
3766 buffer16[usedBytes/2] = 0;
3767 this->len = strlen16 (buffer16);
3768 return true;
3769 }
3770 }
3771 }
3772 else
3773 {
3774 if (cfStr == 0)
3775 return false;
3776 if (encoding == 0xFFFF)
3777 encoding = kCFStringEncodingASCII;
3778 int32 len = static_cast<int32> (CFStringGetLength (strRef) * 2);
3779 if (resize (++len, false))
3780 {
3781 if (CFStringGetCString (strRef, buffer8, len, encoding))
3782 {
3783 this->len = static_cast<int32> (strlen (buffer8));
3784 return true;
3785 }
3786 }
3787 }
3788
3789 return false;
3790}
3791
3792//-----------------------------------------------------------------------------
3793void* ConstString::toCFStringRef (uint32 encoding, bool mutableCFString) const
3794{
3795 if (mutableCFString)
3796 {
3797 CFMutableStringRef str = CFStringCreateMutable (kCFAllocator, 0);
3798 if (isWide)
3799 {
3800 CFStringAppendCharacters (str, (const UniChar *)buffer16, len);
3801 return str;
3802 }
3803 else
3804 {
3805 if (encoding == 0xFFFF)
3806 encoding = kCFStringEncodingASCII;
3807 CFStringAppendCString (str, buffer8, encoding);
3808 return str;
3809 }
3810 }
3811 else
3812 {
3813 if (isWide)
3814 {
3815 if (encoding == 0xFFFF)
3816 encoding = kCFStringEncodingUnicode;
3817 return (void*)CFStringCreateWithBytes (kCFAllocator, (const unsigned char*)buffer16, len * 2, encoding, false);
3818 }
3819 else
3820 {
3821 if (encoding == 0xFFFF)
3822 encoding = kCFStringEncodingASCII;
3823 if (buffer8)
3824 return (void*)CFStringCreateWithCString (kCFAllocator, buffer8, encoding);
3825 else
3826 return (void*)CFStringCreateWithCString (kCFAllocator, "", encoding);
3827 }
3828 }
3829 return 0;
3830}
3831
3832#endif
3833
3834//-----------------------------------------------------------------------------
3836{
3837 uint32 h = 0;
3838 if (s)
3839 {
3840 for (h = 0; *s != '\0'; s++)
3841 h = (64 * h + *s) % m;
3842 }
3843 return h;
3844}
3845
3846//-----------------------------------------------------------------------------
3848{
3849 uint32 h = 0;
3850 if (s)
3851 {
3852 for (h = 0; *s != 0; s++)
3853 h = (64 * h + *s) % m;
3854 }
3855 return h;
3856}
3857
3858//------------------------------------------------------------------------
3859template <class T> int32 tstrnatcmp (const T* s1, const T* s2, bool caseSensitive = true)
3860{
3861 if (s1 == nullptr && s2 == nullptr)
3862 return 0;
3863 else if (s1 == nullptr)
3864 return -1;
3865 else if (s2 == nullptr)
3866 return 1;
3867
3868 while (*s1 && *s2)
3869 {
3871 {
3872 int32 s1LeadingZeros = 0;
3873 while (*s1 == '0')
3874 {
3875 s1++; // skip leading zeros
3876 s1LeadingZeros++;
3877 }
3878 int32 s2LeadingZeros = 0;
3879 while (*s2 == '0')
3880 {
3881 s2++; // skip leading zeros
3882 s2LeadingZeros++;
3883 }
3884
3885 int32 countS1Digits = 0;
3886 while (*(s1 + countS1Digits) && ConstString::isCharDigit (*(s1 + countS1Digits)))
3887 countS1Digits++;
3888 int32 countS2Digits = 0;
3889 while (*(s2 + countS2Digits) && ConstString::isCharDigit (*(s2 + countS2Digits)))
3890 countS2Digits++;
3891
3892 if (countS1Digits != countS2Digits)
3893 return countS1Digits - countS2Digits; // one number is longer than the other
3894
3895 for (int32 i = 0; i < countS1Digits; i++)
3896 {
3897 // countS1Digits == countS2Digits
3898 if (*s1 != *s2)
3899 return (int32)(*s1 - *s2); // the digits differ
3900 s1++;
3901 s2++;
3902 }
3903
3904 if (s1LeadingZeros != s2LeadingZeros)
3905 return s1LeadingZeros - s2LeadingZeros; // differentiate by the number of leading zeros
3906 }
3907 else
3908 {
3909 if (caseSensitive == false)
3910 {
3911 T srcToUpper = static_cast<T> (toupper (*s1));
3912 T dstToUpper = static_cast<T> (toupper (*s2));
3913 if (srcToUpper != dstToUpper)
3914 return (int32)(srcToUpper - dstToUpper);
3915 }
3916 else if (*s1 != *s2)
3917 return (int32)(*s1 - *s2);
3918
3919 s1++;
3920 s2++;
3921 }
3922 }
3923
3924 if (*s1 == 0 && *s2 == 0)
3925 return 0;
3926 else if (*s1 == 0)
3927 return -1;
3928 else if (*s2 == 0)
3929 return 1;
3930 else
3931 return (int32)(*s1 - *s2);
3932}
3933
3934//------------------------------------------------------------------------
3935int32 strnatcmp8 (const char8* s1, const char8* s2, bool caseSensitive /*= true*/)
3936{
3937 return tstrnatcmp (s1, s2, caseSensitive);
3938}
3939
3940//------------------------------------------------------------------------
3941int32 strnatcmp16 (const char16* s1, const char16* s2, bool caseSensitive /*= true*/)
3942{
3943 return tstrnatcmp (s1, s2, caseSensitive);
3944}
3945
3946//-----------------------------------------------------------------------------
3947// StringObject Implementation
3948//-----------------------------------------------------------------------------
3949void PLUGIN_API StringObject::setText (const char8* text)
3950{
3951 assign (text);
3952}
3953
3954//-----------------------------------------------------------------------------
3955void PLUGIN_API StringObject::setText8 (const char8* text)
3956{
3957 assign (text);
3958}
3959
3960//-----------------------------------------------------------------------------
3961void PLUGIN_API StringObject::setText16 (const char16* text)
3962{
3963 assign (text);
3964}
3965
3966//-----------------------------------------------------------------------------
3967const char8* PLUGIN_API StringObject::getText8 ()
3968{
3969 return text8 ();
3970}
3971
3972//-----------------------------------------------------------------------------
3974{
3975 return text16 ();
3976}
3977
3978//-----------------------------------------------------------------------------
3979void PLUGIN_API StringObject::take (void* s, bool _isWide)
3980{
3981 String::take (s, _isWide);
3982}
3983
3984//-----------------------------------------------------------------------------
3985bool PLUGIN_API StringObject::isWideString () const
3986{
3987 return String::isWideString ();
3988}
3989
3990//------------------------------------------------------------------------
3991} // namespace Steinberg
#define NULL
Definition CarlaBridgeFormat.cpp:30
#define nullptr
Definition DistrhoDefines.h:75
assert(0)
uint8_t a
Definition Spc_Cpu.h:141
int32_t int32
Definition basics.h:89
Definition fstring.h:117
static bool isCharLower(char8 character)
Definition fstring.cpp:1743
virtual const char8 * text8() const
Returns pointer to string of type char8.
Definition fstring.h:492
int32 getFirstDifferent(const ConstString &str, CompareMode=kCaseSensitive) const
Returns position of first different character.
Definition fstring.cpp:1297
int64 getTrailingNumber(int64 fallback=0) const
Returns result of scanInt64 or the fallback.
Definition fstring.cpp:1790
bool testChar16(uint32 index, char16 c) const
Definition fstring.cpp:517
bool isAsciiString() const
Checks if all characters in string are in ascii range.
Definition fstring.cpp:1819
virtual const tchar * text() const
Returns pointer to string of type tchar.
Definition fstring.h:482
static bool scanUInt32_16(const char16 *text, uint32 &value, bool scanToEnd=true)
Converts string of type char16 to int32 value.
Definition fstring.h:597
static bool scanInt32_8(const char8 *text, int32 &value, bool scanToEnd=true)
Converts string of type char8 to int32 value.
Definition fstring.h:549
static bool isCharSpace(char8 character)
Returns true if character is a space.
Definition fstring.cpp:1652
static bool scanUInt64_16(const char16 *text, uint64 &value, bool scanToEnd=true)
Converts string of type char16 to uint64 value.
Definition fstring.cpp:1463
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.
Definition fstring.cpp:1924
CompareMode
Definition fstring.h:170
@ kCaseSensitive
Comparison is done with regard to character's case.
Definition fstring.h:171
bool endsWith(const ConstString &str, CompareMode m=kCaseSensitive) const
Check if this ends with str.
Definition fstring.cpp:883
int32 naturalCompare(const ConstString &str, CompareMode mode=kCaseSensitive) const
Definition fstring.cpp:801
bool isDigit(uint32 index) const
Returns true if character at position is a digit.
Definition fstring.cpp:1755
uint32 len
Definition fstring.h:295
static bool scanHex_16(const char16 *text, uint8 &value, bool scanToEnd=true)
Converts string of type char16 to hex/unit8 value.
Definition fstring.cpp:1513
bool testChar8(uint32 index, char8 c) const
Returns true if character is equal at position 'index'.
Definition fstring.cpp:500
bool scanInt32(int32 &value, uint32 offset=0, bool scanToEnd=true) const
Converts string to int32 value starting at offset.
Definition fstring.cpp:1399
static bool scanHex_8(const char8 *text, uint8 &value, bool scanToEnd=true)
Converts string of type char8 to hex/unit8 value.
Definition fstring.cpp:1495
bool scanHex(uint8 &value, uint32 offset=0, bool scanToEnd=true) const
Converts string to hex/uint8 value starting at offset.
Definition fstring.cpp:1387
static bool isCharUpper(char8 character)
Definition fstring.cpp:1731
bool scanUInt32(uint32 &value, uint32 offset=0, bool scanToEnd=true) const
Converts string to uint32 value starting at offset.
Definition fstring.cpp:1411
bool extract(String &result, uint32 idx, int32 n=-1) const
Get n characters long substring starting at index (n=-1: until end).
Definition fstring.cpp:534
static char8 toLower(char8 c)
Converts to lower case.
Definition fstring.cpp:1624
static bool isCharAlphaNum(char8 character)
Returns true if character is an alphanumeric character.
Definition fstring.cpp:1695
int32 copyTo8(char8 *str, uint32 idx=0, int32 n=-1) const
Definition fstring.cpp:551
int32 countOccurences(char8 c, uint32 startIndex, CompareMode=kCaseSensitive) const
Counts occurences of c within this starting at index.
Definition fstring.cpp:1241
bool isWideString() const
Returns true if string is wide.
Definition fstring.h:276
bool startsWith(const ConstString &str, CompareMode m=kCaseSensitive) const
Check if this starts with str.
Definition fstring.cpp:834
char8 * buffer8
Definition fstring.h:292
int32 getTrailingNumberIndex(uint32 width=0) const
Returns start index of trailing number.
Definition fstring.cpp:1767
int32 copyTo(tchar *str, uint32 idx=0, int32 n=-1) const
Definition fstring.cpp:607
bool scanUInt64(uint64 &value, uint32 offset=0, bool scanToEnd=true) const
Converts string to uint64 value starting at offset.
Definition fstring.cpp:1375
ConstString(const char8 *str, int32 length=-1)
Assign from string of type char8 (length=-1: all).
Definition fstring.cpp:439
ConstString()
Definition fstring.cpp:492
bool isEmpty() const
Return true if string is empty.
Definition fstring.h:129
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.
Definition fstring.cpp:1858
bool contains(const ConstString &str, CompareMode m=kCaseSensitive) const
Check if this contains str.
Definition fstring.cpp:932
bool testChar(uint32 index, char8 c) const
Definition fstring.h:152
void toVariant(FVariant &var) const
Definition fstring.cpp:1806
static bool scanInt64_8(const char8 *text, int64 &value, bool scanToEnd=true)
Converts string of type char8 to int64 value.
Definition fstring.cpp:1423
static bool isCharAscii(char8 character)
Returns true if character is in ASCII range.
Definition fstring.cpp:1719
int32 findNext(int32 startIndex, const ConstString &str, int32 n=-1, CompareMode=kCaseSensitive, int32 endIndex=-1) const
Definition fstring.cpp:938
int32 findFirst(const ConstString &str, int32 n=-1, CompareMode m=kCaseSensitive, int32 endIndex=-1) const
Definition fstring.h:204
static bool scanInt64_16(const char16 *text, int64 &value, bool scanToEnd=true)
Converts string of type char16 to int64 value.
Definition fstring.cpp:1437
static bool isCharDigit(char8 character)
Returns true if character is a number.
Definition fstring.cpp:1707
static bool isCharAlpha(char8 character)
Returns true if character is an alphabetic character.
Definition fstring.cpp:1683
bool isNormalized(UnicodeNormalization=kUnicodeNormC)
On PC only kUnicodeNormC is working.
Definition fstring.cpp:2007
int32 findPrev(int32 startIndex, const ConstString &str, int32 n=-1, CompareMode=kCaseSensitive) const
Definition fstring.cpp:1173
bool scanFloat(double &value, uint32 offset=0, bool scanToEnd=true) const
Converts string to double value starting at offset.
Definition fstring.cpp:1535
bool scanInt64(int64 &value, uint32 offset=0, bool scanToEnd=true) const
Converts string to int64 value starting at offset.
Definition fstring.cpp:1363
int32 copyTo16(char16 *str, uint32 idx=0, int32 n=-1) const
Definition fstring.cpp:579
static bool scanUInt64_8(const char8 *text, uint64 &value, bool scanToEnd=true)
Converts string of type char8 to uint64 value.
Definition fstring.cpp:1449
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).
Definition fstring.cpp:709
int32 compare(const ConstString &str, int32 n, CompareMode m=kCaseSensitive) const
Compare n characters of str with n characters of this (return: see above).
Definition fstring.cpp:651
static bool scanUInt32_8(const char8 *text, uint32 &value, bool scanToEnd=true)
Converts string of type char8 to int32 value.
Definition fstring.h:585
virtual const char16 * text16() const
Returns pointer to string of type char16.
Definition fstring.h:498
virtual int32 length() const
Return length of string.
Definition fstring.h:128
char16 * buffer16
Definition fstring.h:293
static char8 toUpper(char8 c)
Converts to upper case.
Definition fstring.cpp:1638
void * buffer
Definition fstring.h:291
uint32 isWide
Definition fstring.h:296
static bool scanInt32_16(const char16 *text, int32 &value, bool scanToEnd=true)
Converts string of type char16 to int32 value.
Definition fstring.h:561
Definition funknown.h:403
Definition fvariant.h:34
@ kString8
Definition fvariant.h:42
@ kFloat
Definition fvariant.h:41
@ kInteger
Definition fvariant.h:40
@ kString16
Definition fvariant.h:45
const char8 * getString8() const
Definition fvariant.h:141
double getFloat() const
Definition fvariant.h:135
int64 getInt() const
Definition fvariant.h:134
const char16 * getString16() const
Definition fvariant.h:142
void setString8(const char8 *v)
Definition fvariant.h:111
uint16 getType() const
Definition fvariant.h:146
void setString16(const char16 *v)
Definition fvariant.h:117
void setOwner(bool state)
Definition fvariant.h:150
Definition ipersistent.h:80
Definition istringresult.h:50
virtual bool PLUGIN_API isWideString() const =0
virtual const char8 *PLUGIN_API getText8()=0
virtual const char16 *PLUGIN_API getText16()=0
Definition istringresult.h:32
Definition fstring.h:308
String & printf(const char8 *format,...)
Print formatted data into string.
Definition fstring.cpp:3314
String & assign(const ConstString &str, int32 n=-1)
Assign n characters of str (-1: all).
Definition fstring.cpp:2500
CharGroup
Definition fstring.h:396
@ kNotAlphaNum
Definition fstring.h:396
@ kNotAlpha
Definition fstring.h:396
@ kSpace
Definition fstring.h:396
bool checkToMultiByte(uint32 destCodePage=kCP_Default) const
Definition fstring.cpp:2181
bool replaceChars8(const char8 *toReplace, char8 toReplaceBy)
Returns true when any replacement was done.
Definition fstring.cpp:2992
const char8 * text8() const SMTG_OVERRIDE
Returns pointer to string of type char8.
Definition fstring.h:621
void swapContent(String &s)
Swaps ownership of the strings pointed to.
Definition fstring.cpp:3633
void toUpper()
Upper case the string.
Definition fstring.cpp:3540
bool normalize(UnicodeNormalization=kUnicodeNormC)
On PC only kUnicodeNormC is working.
Definition fstring.cpp:2262
bool fromAttributes(IAttributes *a, IAttrID attrID)
Assigns string from FAttributes.
Definition fstring.cpp:3613
bool fromVariant(const FVariant &var)
Assigns string from FVariant.
Definition fstring.cpp:3573
~String()
Definition fstring.cpp:2103
String & vprintf(const char8 *format, va_list args)
Definition fstring.cpp:3339
bool removeChars8(const char8 *which)
Remove all occurrences of each char in 'which'.
Definition fstring.cpp:3266
bool toAttributes(IAttributes *a, IAttrID attrID)
Definition fstring.cpp:3622
String()
Definition fstring.cpp:2038
String & insertAt(uint32 idx, const ConstString &str, int32 n=-1)
Insert n characters of str at position idx (n=-1: all).
Definition fstring.cpp:2745
bool removeChars16(const char16 *which)
Remove all occurrences of each char in 'which'.
Definition fstring.cpp:3290
const String & fromPascalString(const unsigned char *buf)
Pascal string conversion.
Definition fstring.cpp:3734
void * pass()
Definition fstring.cpp:3667
bool setChar16(uint32 index, char16 c)
Definition fstring.cpp:2451
bool toWideString(uint32 sourceCodePage=kCP_Default)
Converts to wide string according to sourceCodePage.
Definition fstring.cpp:2141
bool toMultiByte(uint32 destCodePage=kCP_Default)
Definition fstring.cpp:2225
void take(String &str)
Take ownership of the string of 'str'.
Definition fstring.cpp:3647
String & printFloat(double value)
Definition fstring.cpp:3372
unsigned char * toPascalString(unsigned char *buf)
Pascal string conversion.
Definition fstring.cpp:3704
String & printInt64(int64 value)
Definition fstring.cpp:3357
String & append(const ConstString &str, int32 n=-1)
Append n characters of str to this (n=-1: all).
Definition fstring.cpp:2597
String & operator=(const char8 *str)
Assign from a string of type char8.
Definition fstring.h:341
const char16 * text16() const SMTG_OVERRIDE
Returns pointer to string of type char16.
Definition fstring.h:630
bool incrementTrailingNumber(uint32 width=2, tchar separator=STR(' '), uint32 minNumber=1, bool applyOnlyFormat=false)
Definition fstring.cpp:3424
bool resize(uint32 newSize, bool wide, bool fill=false)
Definition fstring.cpp:2329
void toVariant(FVariant &var) const
Definition fstring.cpp:3600
String & remove(uint32 index=0, int32 n=-1)
Remove n characters from string starting at index (n=-1: until end).
Definition fstring.cpp:3053
bool setChar8(uint32 index, char8 c)
Definition fstring.cpp:2399
void fromUTF8(const char8 *utf8String)
Assigns from UTF8 string.
Definition fstring.cpp:2255
void passToVariant(FVariant &var)
Pass ownership of buffer to Variant - sets Variant ownership.
Definition fstring.cpp:3676
void tryFreeBuffer()
Definition fstring.cpp:2319
bool removeSubString(const ConstString &subString, bool allOccurences=true)
Definition fstring.cpp:3079
bool replaceChars16(const char16 *toReplace, char16 toReplaceBy)
Definition fstring.cpp:3019
void updateLength()
Call this when the string is truncated outside (not recommended though).
Definition fstring.cpp:2132
void toLower()
Lower case the string.
Definition fstring.cpp:3495
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).
Definition fstring.cpp:2824
bool setChar(uint32 index, char8 c)
Definition fstring.h:336
void removeChars(CharGroup mode=kSpace)
Removes all of group.
Definition fstring.cpp:3192
const char8 *PLUGIN_API getText8() SMTG_OVERRIDE
Definition fstring.cpp:3967
void PLUGIN_API take(void *s, bool _isWide) SMTG_OVERRIDE
Definition fstring.cpp:3979
void PLUGIN_API setText8(const char8 *text) SMTG_OVERRIDE
Definition fstring.cpp:3955
const char16 *PLUGIN_API getText16() SMTG_OVERRIDE
Definition fstring.cpp:3973
void PLUGIN_API setText(const char8 *text) SMTG_OVERRIDE
Definition fstring.cpp:3949
void PLUGIN_API setText16(const char16 *text) SMTG_OVERRIDE
Definition fstring.cpp:3961
bool PLUGIN_API isWideString() const SMTG_OVERRIDE
Definition fstring.cpp:3985
Definition String.h:48
String trim() const
Definition String.cpp:1540
unsigned * m
Definition inflate.c:1559
unsigned v[N_MAX]
Definition inflate.c:1584
register unsigned i
Definition inflate.c:1575
unsigned s
Definition inflate.c:1555
#define SMTG_WARNING(s)
Definition fdebug.h:197
#define NEW
Definition fdebug.h:212
#define SMTG_ASSERT(f)
Definition fdebug.h:196
#define STR(x)
Definition fstrdefs.h:39
#define STR16(x)
Definition fstrdefs.h:35
#define SMTG_STRING_CHECK_MSG
Definition fstring.cpp:2176
#define kPrintfBufferSize
Definition fstring.cpp:68
static PuglViewHint int value
Definition pugl.h:1708
static PuglViewHint hint
Definition pugl.h:1707
static int width
Definition pugl.h:1593
struct backing_store_struct * info
Definition jmemsys.h:183
int marker
Definition jpeglib.h:950
int version
Definition jpeglib.h:901
Definition baseiids.cpp:43
static uint32 performTrim(T *str, uint32 length, F func, bool funcResult)
Definition fstring.cpp:3095
unsigned long long uint64
Definition ftypes.h:67
int16 char16
Definition ftypes.h:101
static bool performReplace(T *str, const T *toReplace, T toReplaceBy)
Definition fstring.cpp:2969
int int32
Definition ftypes.h:50
static const uint32 kPrintfBufferSize
Definition fstrdefs.h:286
int32 strlen8(const char8 *str)
Definition fstrdefs.h:125
static uint32 performRemoveChars(T *str, uint32 length, const T *toRemove)
Definition fstring.cpp:3235
FIDString IAttrID
Definition ipersistent.h:62
static const char16 kEmptyString16[]
Definition fstrdefs.h:104
char char8
Definition ftypes.h:93
int32 strncmp16(const char16 *first, const char16 *last, uint32 count)
Definition fstrdefs.h:186
static const bool kWideStringDefault
Definition fstring.h:57
@ kResultTrue
Definition funknown.h:194
static const char8 kEmptyString8[]
Definition fstrdefs.h:103
long long int64
Definition ftypes.h:66
int32 strcmp16(const char16 *src, const char16 *dst)
Definition fstrdefs.h:150
int32 strnatcmp16(const char16 *s1, const char16 *s2, bool caseSensitive)
Definition fstring.cpp:3941
char16 tchar
Definition ftypes.h:105
int32 strlen16(const char16 *str)
Definition fstrdefs.h:126
uint32 hashString8(const char8 *s, uint32 m)
Definition fstring.cpp:3835
MBCodePage
Definition fstring.h:66
@ kCP_MAC_ROMAN
Default Mac codepage.
Definition fstring.h:68
@ kCP_ShiftJIS
Shifted Japan Industrial Standard Encoding.
Definition fstring.h:73
@ kCP_US_ASCII
US-ASCII (7-bit).
Definition fstring.h:74
@ kCP_Default
Default ANSI codepage.
Definition fstring.h:76
@ kCP_MAC_CEE
Mac Central European Encoding.
Definition fstring.h:71
@ kCP_ANSI_WEL
West European Latin Encoding.
Definition fstring.h:70
@ kCP_ANSI
Default ANSI codepage.
Definition fstring.h:67
@ kCP_Utf8
UTF8 Encoding.
Definition fstring.h:72
static bool isCaseSensitive(ConstString::CompareMode mode)
Definition fstring.cpp:431
unsigned char uint8
Definition ftypes.h:40
int32 tstrlen(const tchar *str)
Definition fstrdefs.h:124
UnicodeNormalization
Definition fstring.h:80
@ kUnicodeNormKD
Unicode normalization form KD, compatibility decomposition.
Definition fstring.h:84
@ kUnicodeNormKC
Unicode normalization form KC, compatibility composition.
Definition fstring.h:83
@ kUnicodeNormD
Unicode normalization Form D, canonical decomposition.
Definition fstring.h:82
@ kUnicodeNormC
Unicode normalization Form C, canonical composition.
Definition fstring.h:81
static uint32 performRemove(T *str, uint32 length, F func, bool funcResult)
Definition fstring.cpp:3174
uint32 hashString16(const char16 *s, uint32 m)
Definition fstring.cpp:3847
int32 tstrnatcmp(const T *s1, const T *s2, bool caseSensitive=true)
Definition fstring.cpp:3859
int32 strnatcmp8(const char8 *s1, const char8 *s2, bool caseSensitive)
Definition fstring.cpp:3935
unsigned int uint32
Definition ftypes.h:51
png_uint_32 length
Definition png.c:2247
png_structrp int mode
Definition png.h:1139
#define stricmp(x, y)
Definition swell-types.h:68
#define strnicmp(x, y, z)
Definition swell-types.h:71
char CHAR
Definition swell-types.h:188
int n
Definition crypt.c:458
uch * p
Definition crypt.c:594
return c
Definition crypt.c:175
memcpy(hh, h, RAND_HEAD_LEN)
uch h[RAND_HEAD_LEN]
Definition crypt.c:459
b
Definition crypt.c:628
ulg size
Definition extract.c:2350
int result
Definition process.c:1455
char * malloc()
else sprintf(d_t_str, LoadFarString(shtYMDHMTime), yr%100, monthstr, dy, hh, mm)
_WDL_CSTRING_PREFIX void INT_PTR const char * format
Definition wdlcstring.h:263