Ark Server API 3.54
Serverside plugin support for Ark Survival Evolved.
Loading...
Searching...
No Matches
FString.h
Go to the documentation of this file.
1// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
5#include <string>
6#include <locale>
7#include <Logger/Logger.h>
8
9#include "TArray.h"
10#include "../Windows/MicrosoftPlatformString.h"
11#include "../Templates/MemoryOps.h"
12#include "../Templates/UnrealTemplate.h"
13#include "../Math/UnrealMathUtility.h"
14#include "../Misc/CString.h"
15#include "../Crc.h"
16
17#pragma warning(push)
18#pragma warning(disable : 4244)
19
20struct FStringFormatArg;
21
23namespace ESearchCase
24{
25 enum Type
26 {
29
32 };
33};
34
36namespace ESearchDir
37{
38 enum Type
39 {
42
45 };
46}
47
53{
54private:
55 friend struct TContainerTraits<FString>;
56
60
61public:
63
64 FString() = default;
65 FString(FString&&) = default;
66 FString(const FString&) = default;
67 FString& operator=(FString&&) = default;
68 FString& operator=(const FString&) = default;
69
76 FORCEINLINE FString(const FString& Other, int32 ExtraSlack)
77 : Data(Other.Data, ExtraSlack + ((Other.Data.Num() || !ExtraSlack) ? 0 : 1)) // Add 1 if the source string array is empty and we want some slack, because we'll need to include a null terminator which is currently missing
78 {
79 }
80
87 FORCEINLINE FString(FString&& Other, int32 ExtraSlack)
88 : Data(MoveTemp(Other.Data), ExtraSlack + ((Other.Data.Num() || !ExtraSlack) ? 0 : 1)) // Add 1 if the source string array is empty and we want some slack, because we'll need to include a null terminator which is currently missing
89 {
90 }
91
97 template <typename CharType>
98 FORCEINLINE FString(const CharType* Src, typename TEnableIf<TIsCharType<CharType>::Value>::Type* Dummy = nullptr) // This TEnableIf is to ensure we don't instantiate this constructor for non-char types, like id* in Obj-C
99 {
100 if (Src && *Src)
101 {
102 int32 SrcLen = TCString<CharType>::Strlen(Src) + 1;
103 int32 DestLen = FPlatformString::ConvertedLength<TCHAR>(Src, SrcLen);
104 Data.AddUninitialized(DestLen);
105
106 FPlatformString::Convert(Data.GetData(), DestLen, Src, SrcLen);
107 }
108 }
109
116 FORCEINLINE explicit FString(int32 InCount, const TCHAR* InSrc)
117 {
118 Data.AddUninitialized(InCount ? InCount + 1 : 0);
119
120 if (Data.Num() > 0)
121 {
122 FCString::Strncpy(Data.GetData(), InSrc, InCount + 1);
123 }
124 }
125
129 FORCEINLINE explicit FString(const std::string& str)
130 : FString(str.c_str())
131 {
132 }
133
137 FORCEINLINE explicit FString(const std::wstring& str)
138 : FString(str.c_str())
139 {
140 }
141
147 FORCEINLINE FString& operator=(const TCHAR* Other)
148 {
149 if (Data.GetData() != Other)
150 {
151 int32 Len = (Other && *Other) ? FCString::Strlen(Other) + 1 : 0;
152 Data.Empty(Len);
154
155 if (Len)
156 {
157 FMemory::Memcpy(Data.GetData(), Other, Len * sizeof(TCHAR));
158 }
159 }
160 return *this;
161 }
162
169 FORCEINLINE TCHAR& operator[](int32 Index)
170 {
171 return Data.GetData()[Index];
172 }
173
180 FORCEINLINE const TCHAR& operator[](int32 Index) const
181 {
182 return Data.GetData()[Index];
183 }
184
190
193 {
194 return Data.CreateIterator();
195 }
196
199 {
200 return Data.CreateConstIterator();
201 }
202
203private:
208 FORCEINLINE friend DataType::RangedForIteratorType begin(FString& Str) { auto Result = begin(Str.Data); return Result; }
209 FORCEINLINE friend DataType::RangedForConstIteratorType begin(const FString& Str) { auto Result = begin(Str.Data); return Result; }
210 FORCEINLINE friend DataType::RangedForIteratorType end(FString& Str) { auto Result = end(Str.Data); if (Str.Data.Num()) { --Result; } return Result; }
211 FORCEINLINE friend DataType::RangedForConstIteratorType end(const FString& Str) { auto Result = end(Str.Data); if (Str.Data.Num()) { --Result; } return Result; }
212
213public:
214 FORCEINLINE uint32 GetAllocatedSize() const
215 {
216 return Data.GetAllocatedSize();
217 }
218
222 FORCEINLINE void CheckInvariants() const
223 {
224 }
225
231 FORCEINLINE void Empty(int32 Slack = 0)
232 {
233 Data.Empty(Slack);
234 }
235
241 FORCEINLINE bool IsEmpty() const
242 {
243 return Data.Num() <= 1;
244 }
245
251 FORCEINLINE void Reset(int32 NewReservedSize = 0)
252 {
253 const int32 NewSizeIncludingTerminator = (NewReservedSize > 0) ? (NewReservedSize + 1) : 0;
254 Data.Reset(NewSizeIncludingTerminator);
255 }
256
260 FORCEINLINE void Shrink()
261 {
262 Data.Shrink();
263 }
264
272 FORCEINLINE bool IsValidIndex(int32 Index) const
273 {
274 return Index >= 0 && Index < Len();
275 }
276
282 FORCEINLINE const TCHAR* operator*() const
283 {
284 return Data.Num() ? Data.GetData() : TEXT("");
285 }
286
293 FORCEINLINE DataType& GetCharArray()
294 {
295 return Data;
296 }
297
299 FORCEINLINE const DataType& GetCharArray() const
300 {
301 return Data;
302 }
303
304#ifdef __OBJC__
306 FORCEINLINE NSString* GetNSString() const
307 {
308#if PLATFORM_TCHAR_IS_4_BYTES
309 return[[[NSString alloc] initWithBytes:Data.GetData() length : Len() * sizeof(TCHAR) encoding : NSUTF32LittleEndianStringEncoding] autorelease];
310#else
311 return[[[NSString alloc] initWithBytes:Data.GetData() length : Len() * sizeof(TCHAR) encoding : NSUTF16LittleEndianStringEncoding] autorelease];
312#endif
313 }
314#endif
315
322 FORCEINLINE void AppendChars(const TCHAR* Array, int32 Count)
323 {
324 if (!Count)
325 return;
326
327 int32 Index = Data.Num();
328
329 // Reserve enough space - including an extra gap for a null terminator if we don't already have a string allocated
330 Data.AddUninitialized(Count + (Index ? 0 : 1));
331
332 TCHAR* EndPtr = Data.GetData() + Index - (Index ? 1 : 0);
333
334 // Copy characters to end of string, overwriting null terminator if we already have one
335 CopyAssignItems(EndPtr, Array, Count);
336
337 // (Re-)establish the null terminator
338 *(EndPtr + Count) = 0;
339 }
340
347 FORCEINLINE FString& operator+=(const TCHAR* Str)
348 {
350
351 AppendChars(Str, FCString::Strlen(Str));
352
353 return *this;
354 }
355
362 template <typename CharType>
363 FORCEINLINE typename TEnableIf<TIsCharType<CharType>::Value, FString&>::Type operator+=(CharType InChar)
364 {
366
367 if (InChar != 0)
368 {
369 // position to insert the character.
370 // At the end of the string if we have existing characters, otherwise at the 0 position
371 int32 InsertIndex = (Data.Num() > 0) ? Data.Num() - 1 : 0;
372
373 // number of characters to add. If we don't have any existing characters,
374 // we'll need to append the terminating zero as well.
375 int32 InsertCount = (Data.Num() > 0) ? 1 : 2;
376
377 Data.AddUninitialized(InsertCount);
378 Data[InsertIndex] = InChar;
379 Data[InsertIndex + 1] = 0;
380 }
381 return *this;
382 }
383
390 FORCEINLINE FString& AppendChar(const TCHAR InChar)
391 {
392 *this += InChar;
393 return *this;
394 }
395
396 FORCEINLINE FString& Append(const FString& Text)
397 {
398 *this += Text;
399 return *this;
400 }
401
402 FString& Append(const TCHAR* Text, int32 Count)
403 {
405
406 if (Count != 0)
407 {
408 // position to insert the character.
409 // At the end of the string if we have existing characters, otherwise at the 0 position
410 int32 InsertIndex = (Data.Num() > 0) ? Data.Num() - 1 : 0;
411
412 // number of characters to add. If we don't have any existing characters,
413 // we'll need to append the terminating zero as well.
414 int32 FinalCount = (Data.Num() > 0) ? Count : Count + 1;
415
416 Data.AddUninitialized(FinalCount);
417
418 for (int32 Index = 0; Index < Count; Index++)
419 {
420 Data[InsertIndex + Index] = Text[Index];
421 }
422
423 Data[Data.Num() - 1] = 0;
424 }
425 return *this;
426 }
427
435 FORCEINLINE void RemoveAt(int32 Index, int32 Count = 1, bool bAllowShrinking = true)
436 {
437 Data.RemoveAt(Index, Count, bAllowShrinking);
438 }
439
440 FORCEINLINE void InsertAt(int32 Index, TCHAR Character)
441 {
442 if (Character != 0)
443 {
444 if (Data.Num() == 0)
445 {
446 *this += Character;
447 }
448 else
449 {
450 Data.Insert(Character, Index);
451 }
452 }
453 }
454
455 FORCEINLINE void InsertAt(int32 Index, const FString& Characters)
456 {
457 if (Characters.Len())
458 {
459 if (Data.Num() == 0)
460 {
461 *this += Characters;
462 }
463 else
464 {
465 Data.Insert(Characters.Data.GetData(), Characters.Len(), Index);
466 }
467 }
468 }
469
476 bool RemoveFromStart(const FString& InPrefix, ESearchCase::Type SearchCase = ESearchCase::IgnoreCase);
477
484 bool RemoveFromEnd(const FString& InSuffix, ESearchCase::Type SearchCase = ESearchCase::IgnoreCase);
485
492 void PathAppend(const TCHAR* Str, int32 StrLength);
493
500 FORCEINLINE FString& operator+=(const FString& Str)
501 {
503 Str.CheckInvariants();
504
505 AppendChars(Str.Data.GetData(), Str.Len());
506
507 return *this;
508 }
509
518 template <typename CharType>
519 FORCEINLINE friend typename TEnableIf<TIsCharType<CharType>::Value, FString>::Type operator+(const FString& Lhs, CharType Rhs)
520 {
521 Lhs.CheckInvariants();
522
523 FString Result(Lhs, 1);
524 Result += Rhs;
525
526 return Result;
527 }
528
537 template <typename CharType>
538 FORCEINLINE friend typename TEnableIf<TIsCharType<CharType>::Value, FString>::Type operator+(FString&& Lhs, CharType Rhs)
539 {
540 Lhs.CheckInvariants();
541
542 FString Result(MoveTemp(Lhs), 1);
543 Result += Rhs;
544
545 return Result;
546 }
547
548private:
549 template <typename LhsType, typename RhsType>
550 FORCEINLINE static FString ConcatFStrings(typename TIdentity<LhsType>::Type Lhs, typename TIdentity<RhsType>::Type Rhs)
551 {
552 Lhs.CheckInvariants();
553 Rhs.CheckInvariants();
554
555 if (Lhs.IsEmpty())
556 {
557 return MoveTempIfPossible(Rhs);
558 }
559
560 int32 RhsLen = Rhs.Len();
561
562 FString Result(MoveTempIfPossible(Lhs), RhsLen);
563 Result.AppendChars(Rhs.Data.GetData(), RhsLen);
564
565 return Result;
566 }
567
568 template <typename RhsType>
569 FORCEINLINE static FString ConcatTCHARsToFString(const TCHAR* Lhs, typename TIdentity<RhsType>::Type Rhs)
570 {
571 Rhs.CheckInvariants();
572
573 if (!Lhs || !*Lhs)
574 {
575 return MoveTempIfPossible(Rhs);
576 }
577
578 int32 LhsLen = FCString::Strlen(Lhs);
579 int32 RhsLen = Rhs.Len();
580
581 // This is not entirely optimal, as if the Rhs is an rvalue and has enough slack space to hold Lhs, then
582 // the memory could be reused here without constructing a new object. However, until there is proof otherwise,
583 // I believe this will be relatively rare and isn't worth making the code a lot more complex right now.
584 FString Result;
585 Result.Data.AddUninitialized(LhsLen + RhsLen + 1);
586
587 TCHAR* ResultData = Result.Data.GetData();
588 CopyAssignItems(ResultData, Lhs, LhsLen);
589 CopyAssignItems(ResultData + LhsLen, Rhs.Data.GetData(), RhsLen);
590 *(ResultData + LhsLen + RhsLen) = 0;
591
592 return Result;
593 }
594
595 template <typename LhsType>
596 FORCEINLINE static FString ConcatFStringToTCHARs(typename TIdentity<LhsType>::Type Lhs, const TCHAR* Rhs)
597 {
598 Lhs.CheckInvariants();
599
600 if (!Rhs || !*Rhs)
601 {
602 return MoveTempIfPossible(Lhs);
603 }
604
605 int32 RhsLen = FCString::Strlen(Rhs);
606
607 FString Result(MoveTempIfPossible(Lhs), RhsLen);
608 Result.AppendChars(Rhs, RhsLen);
609
610 return Result;
611 }
612
613public:
622 FORCEINLINE friend FString operator+(const FString& Lhs, const FString& Rhs)
623 {
624 return ConcatFStrings<const FString&, const FString&>(Lhs, Rhs);
625 }
626
635 FORCEINLINE friend FString operator+(FString&& Lhs, const FString& Rhs)
636 {
637 return ConcatFStrings<FString&&, const FString&>(MoveTemp(Lhs), Rhs);
638 }
639
648 FORCEINLINE friend FString operator+(const FString& Lhs, FString&& Rhs)
649 {
650 return ConcatFStrings<const FString&, FString&&>(Lhs, MoveTemp(Rhs));
651 }
652
661 FORCEINLINE friend FString operator+(FString&& Lhs, FString&& Rhs)
662 {
663 return ConcatFStrings<FString&&, FString&&>(MoveTemp(Lhs), MoveTemp(Rhs));
664 }
665
674 FORCEINLINE friend FString operator+(const TCHAR* Lhs, const FString& Rhs)
675 {
676 return ConcatTCHARsToFString<const FString&>(Lhs, Rhs);
677 }
678
687 FORCEINLINE friend FString operator+(const TCHAR* Lhs, FString&& Rhs)
688 {
689 return ConcatTCHARsToFString<FString&&>(Lhs, MoveTemp(Rhs));
690 }
691
700 FORCEINLINE friend FString operator+(const FString& Lhs, const TCHAR* Rhs)
701 {
702 return ConcatFStringToTCHARs<const FString&>(Lhs, Rhs);
703 }
704
713 FORCEINLINE friend FString operator+(FString&& Lhs, const TCHAR* Rhs)
714 {
715 return ConcatFStringToTCHARs<FString&&>(MoveTemp(Lhs), Rhs);
716 }
717
724 FORCEINLINE FString& operator/=(const TCHAR* Str)
725 {
726 PathAppend(Str, FCString::Strlen(Str));
727 return *this;
728 }
729
736 FORCEINLINE FString& operator/=(const FString& Str)
737 {
738 PathAppend(Str.Data.GetData(), Str.Len());
739 return *this;
740 }
741
749 FORCEINLINE friend FString operator/(const FString& Lhs, const TCHAR* Rhs)
750 {
751 int32 StrLength = FCString::Strlen(Rhs);
752
753 FString Result(Lhs, StrLength + 1);
754 Result.PathAppend(Rhs, StrLength);
755 return Result;
756 }
757
765 FORCEINLINE friend FString operator/(FString&& Lhs, const TCHAR* Rhs)
766 {
767 int32 StrLength = FCString::Strlen(Rhs);
768
769 FString Result(MoveTemp(Lhs), StrLength + 1);
770 Result.PathAppend(Rhs, StrLength);
771 return Result;
772 }
773
781 FORCEINLINE friend FString operator/(const FString& Lhs, const FString& Rhs)
782 {
783 int32 StrLength = Rhs.Len();
784
785 FString Result(Lhs, StrLength + 1);
786 Result.PathAppend(Rhs.Data.GetData(), StrLength);
787 return Result;
788 }
789
797 FORCEINLINE friend FString operator/(FString&& Lhs, const FString& Rhs)
798 {
799 int32 StrLength = Rhs.Len();
800
801 FString Result(MoveTemp(Lhs), StrLength + 1);
802 Result.PathAppend(Rhs.Data.GetData(), StrLength);
803 return Result;
804 }
805
813 FORCEINLINE friend FString operator/(const TCHAR* Lhs, const FString& Rhs)
814 {
815 int32 StrLength = Rhs.Len();
816
817 FString Result(FString(Lhs), StrLength + 1);
818 Result.PathAppend(Rhs.Data.GetData(), Rhs.Len());
819 return Result;
820 }
821
830 FORCEINLINE friend bool operator<=(const FString& Lhs, const FString& Rhs)
831 {
832 return FPlatformString::Stricmp(*Lhs, *Rhs) <= 0;
833 }
834
843 template <typename CharType>
844 FORCEINLINE friend bool operator<=(const FString& Lhs, const CharType* Rhs)
845 {
846 return FPlatformString::Stricmp(*Lhs, Rhs) <= 0;
847 }
848
857 template <typename CharType>
858 FORCEINLINE friend bool operator<=(const CharType* Lhs, const FString& Rhs)
859 {
860 return FPlatformString::Stricmp(Lhs, *Rhs) <= 0;
861 }
862
871 FORCEINLINE friend bool operator<(const FString& Lhs, const FString& Rhs)
872 {
873 return FPlatformString::Stricmp(*Lhs, *Rhs) < 0;
874 }
875
884 template <typename CharType>
885 FORCEINLINE friend bool operator<(const FString& Lhs, const CharType* Rhs)
886 {
887 return FPlatformString::Stricmp(*Lhs, Rhs) < 0;
888 }
889
898 template <typename CharType>
899 FORCEINLINE friend bool operator<(const CharType* Lhs, const FString& Rhs)
900 {
901 return FPlatformString::Stricmp(Lhs, *Rhs) < 0;
902 }
903
912 FORCEINLINE friend bool operator>=(const FString& Lhs, const FString& Rhs)
913 {
914 return FPlatformString::Stricmp(*Lhs, *Rhs) >= 0;
915 }
916
925 template <typename CharType>
926 FORCEINLINE friend bool operator>=(const FString& Lhs, const CharType* Rhs)
927 {
928 return FPlatformString::Stricmp(*Lhs, Rhs) >= 0;
929 }
930
939 template <typename CharType>
940 FORCEINLINE friend bool operator>=(const CharType* Lhs, const FString& Rhs)
941 {
942 return FPlatformString::Stricmp(Lhs, *Rhs) >= 0;
943 }
944
953 FORCEINLINE friend bool operator>(const FString& Lhs, const FString& Rhs)
954 {
955 return FPlatformString::Stricmp(*Lhs, *Rhs) > 0;
956 }
957
966 template <typename CharType>
967 FORCEINLINE friend bool operator>(const FString& Lhs, const CharType* Rhs)
968 {
969 return FPlatformString::Stricmp(*Lhs, Rhs) > 0;
970 }
971
980 template <typename CharType>
981 FORCEINLINE friend bool operator>(const CharType* Lhs, const FString& Rhs)
982 {
983 return FPlatformString::Stricmp(Lhs, *Rhs) > 0;
984 }
985
994 FORCEINLINE friend bool operator==(const FString& Lhs, const FString& Rhs)
995 {
996 return FPlatformString::Stricmp(*Lhs, *Rhs) == 0;
997 }
998
1007 template <typename CharType>
1008 FORCEINLINE friend bool operator==(const FString& Lhs, const CharType* Rhs)
1009 {
1010 return FPlatformString::Stricmp(*Lhs, Rhs) == 0;
1011 }
1012
1021 template <typename CharType>
1022 FORCEINLINE friend bool operator==(const CharType* Lhs, const FString& Rhs)
1023 {
1024 return FPlatformString::Stricmp(Lhs, *Rhs) == 0;
1025 }
1026
1035 FORCEINLINE friend bool operator!=(const FString& Lhs, const FString& Rhs)
1036 {
1037 return FPlatformString::Stricmp(*Lhs, *Rhs) != 0;
1038 }
1039
1048 template <typename CharType>
1049 FORCEINLINE friend bool operator!=(const FString& Lhs, const CharType* Rhs)
1050 {
1051 return FPlatformString::Stricmp(*Lhs, Rhs) != 0;
1052 }
1053
1062 template <typename CharType>
1063 FORCEINLINE friend bool operator!=(const CharType* Lhs, const FString& Rhs)
1064 {
1065 return FPlatformString::Stricmp(Lhs, *Rhs) != 0;
1066 }
1067
1069 FORCEINLINE int32 Len() const
1070 {
1071 return Data.Num() ? Data.Num() - 1 : 0;
1072 }
1073
1075 FORCEINLINE FString Left(int32 Count) const
1076 {
1077 return FString(FMath::Clamp(Count, 0, Len()), **this);
1078 }
1079
1081 FORCEINLINE FString LeftChop(int32 Count) const
1082 {
1083 return FString(FMath::Clamp(Len() - Count, 0, Len()), **this);
1084 }
1085
1087 FORCEINLINE FString Right(int32 Count) const
1088 {
1089 return FString(**this + Len() - FMath::Clamp(Count, 0, Len()));
1090 }
1091
1093 FORCEINLINE FString RightChop(int32 Count) const
1094 {
1095 return FString(**this + Len() - FMath::Clamp(Len() - Count, 0, Len()));
1096 }
1097
1099 FORCEINLINE FString Mid(int32 Start, int32 Count = INT_MAX) const
1100 {
1101 uint32 End = Start + Count;
1102 Start = FMath::Clamp((uint32)Start, (uint32)0, (uint32)Len());
1103 End = FMath::Clamp((uint32)End, (uint32)Start, (uint32)Len());
1104 return FString(End - Start, **this + Start);
1105 }
1106
1116 int32 Find(const TCHAR* SubStr, ESearchCase::Type SearchCase = ESearchCase::IgnoreCase,
1117 ESearchDir::Type SearchDir = ESearchDir::FromStart, int32 StartPosition = INDEX_NONE) const;
1118
1128 FORCEINLINE int32 Find(const FString& SubStr, ESearchCase::Type SearchCase = ESearchCase::IgnoreCase,
1129 ESearchDir::Type SearchDir = ESearchDir::FromStart, int32 StartPosition = INDEX_NONE) const
1130 {
1131 return Find(*SubStr, SearchCase, SearchDir, StartPosition);
1132 }
1133
1142 FORCEINLINE bool Contains(const TCHAR* SubStr, ESearchCase::Type SearchCase = ESearchCase::IgnoreCase,
1143 ESearchDir::Type SearchDir = ESearchDir::FromStart) const
1144 {
1145 return Find(SubStr, SearchCase, SearchDir) != INDEX_NONE;
1146 }
1147
1156 FORCEINLINE bool Contains(const FString& SubStr, ESearchCase::Type SearchCase = ESearchCase::IgnoreCase,
1157 ESearchDir::Type SearchDir = ESearchDir::FromStart) const
1158 {
1159 return Find(*SubStr, SearchCase, SearchDir) != INDEX_NONE;
1160 }
1161
1169 FORCEINLINE bool FindChar(TCHAR InChar, int32& Index) const
1170 {
1171 return Data.Find(InChar, Index);
1172 }
1173
1181 FORCEINLINE bool FindLastChar(TCHAR InChar, int32& Index) const
1182 {
1183 return Data.FindLast(InChar, Index);
1184 }
1185
1194 template <typename Predicate>
1195 FORCEINLINE int32 FindLastCharByPredicate(Predicate Pred, int32 Count) const
1196 {
1197 return Data.FindLastByPredicate(Pred, Count);
1198 }
1199
1208 template <typename Predicate>
1209 FORCEINLINE int32 FindLastCharByPredicate(Predicate Pred) const
1210 {
1211 return Data.FindLastByPredicate(Pred, this->Len());
1212 }
1213
1221 FORCEINLINE bool Equals(const FString& Other, ESearchCase::Type SearchCase = ESearchCase::CaseSensitive) const
1222 {
1223 if (SearchCase == ESearchCase::CaseSensitive)
1224 {
1225 return FCString::Strcmp(**this, *Other) == 0;
1226 }
1227 else
1228 {
1229 return FCString::Stricmp(**this, *Other) == 0;
1230 }
1231 }
1232
1240 FORCEINLINE int32 Compare(const FString& Other, ESearchCase::Type SearchCase = ESearchCase::CaseSensitive) const
1241 {
1242 if (SearchCase == ESearchCase::CaseSensitive)
1243 {
1244 return FCString::Strcmp(**this, *Other);
1245 }
1246 else
1247 {
1248 return FCString::Stricmp(**this, *Other);
1249 }
1250 }
1251
1262 bool Split(const FString& InS, FString* LeftS, FString* RightS, ESearchCase::Type SearchCase = ESearchCase::IgnoreCase,
1263 ESearchDir::Type SearchDir = ESearchDir::FromStart) const
1264 {
1265 int32 InPos = Find(InS, SearchCase, SearchDir);
1266
1267 if (InPos < 0) { return false; }
1268
1269 if (LeftS) { *LeftS = Left(InPos); }
1270 if (RightS) { *RightS = Mid(InPos + InS.Len()); }
1271
1272 return true;
1273 }
1274
1276 FString ToUpper() const &;
1277
1282 FString ToUpper() && ;
1283
1285 void ToUpperInline();
1286
1288 FString ToLower() const &;
1289
1294 FString ToLower() && ;
1295
1297 void ToLowerInline();
1298
1300 FString LeftPad(int32 ChCount) const;
1301
1303 FString RightPad(int32 ChCount) const;
1304
1306 bool IsNumeric() const;
1307
1308 // @return string with Ch character
1309 static FString Chr(TCHAR Ch);
1310
1319 static FString ChrN(int32 NumCharacters, TCHAR Char);
1320
1327 bool StartsWith(const TCHAR* InSuffix, ESearchCase::Type SearchCase = ESearchCase::IgnoreCase) const;
1328
1335 bool StartsWith(const FString& InPrefix, ESearchCase::Type SearchCase = ESearchCase::IgnoreCase) const;
1336
1343 bool EndsWith(const TCHAR* InSuffix, ESearchCase::Type SearchCase = ESearchCase::IgnoreCase) const;
1344
1351 bool EndsWith(const FString& InSuffix, ESearchCase::Type SearchCase = ESearchCase::IgnoreCase) const;
1352
1361 bool MatchesWildcard(const FString& Wildcard, ESearchCase::Type SearchCase = ESearchCase::IgnoreCase) const;
1362
1366 void TrimStartAndEndInline();
1367
1372 FString TrimStartAndEnd() const &;
1373
1379
1383 void TrimStartInline();
1384
1389 FString TrimStart() const &;
1390
1395 FString TrimStart() && ;
1396
1400 void TrimEndInline();
1401
1406 FString TrimEnd() const &;
1407
1412 FString TrimEnd() && ;
1413
1417 void TrimToNullTerminator();
1418
1422 FString TrimQuotes(bool* bQuotesRemoved = nullptr) const;
1423
1433 int32 ParseIntoArray(TArray<FString>& OutArray, const TCHAR* pchDelim, bool InCullEmpty = true) const;
1434
1445 int32 ParseIntoArrayWS(TArray<FString>& OutArray, const TCHAR* pchExtraDelim = nullptr, bool InCullEmpty = true) const;
1446
1455 int32 ParseIntoArrayLines(TArray<FString>& OutArray, bool InCullEmpty = true) const;
1456
1467 int32 ParseIntoArray(TArray<FString>& OutArray, const TCHAR** DelimArray, int32 NumDelims, bool InCullEmpty = true) const;
1468
1476 static int32 CullArray(TArray<FString>* InArray);
1477
1481 FString Reverse() const;
1482
1486 void ReverseString();
1487
1496 FString Replace(const TCHAR* From, const TCHAR* To, ESearchCase::Type SearchCase = ESearchCase::IgnoreCase) const;
1497
1507 int32 ReplaceInline(const TCHAR* SearchText, const TCHAR* ReplacementText, ESearchCase::Type SearchCase = ESearchCase::IgnoreCase);
1508
1513
1522 FString ReplaceCharWithEscapedChar(const TArray<TCHAR>* Chars = nullptr) const;
1523
1529 FString ReplaceEscapedCharWithChar(const TArray<TCHAR>* Chars = nullptr) const;
1530
1536 FString ConvertTabsToSpaces(const int32 InSpacesPerTab);
1537
1538 // Takes the number passed in and formats the string in comma format ( 12345 becomes "12,345")
1539 static FString FormatAsNumber(int32 InNumber);
1540
1541 // To allow more efficient memory handling, automatically adds one for the string termination.
1542 FORCEINLINE void Reserve(const uint32 CharacterCount)
1543 {
1544 Data.Reserve(CharacterCount + 1);
1545 }
1546
1548 static FORCEINLINE FString FromInt(int32 Num)
1549 {
1550 FString Ret;
1551 Ret.AppendInt(Num);
1552 return Ret;
1553 }
1554
1556 void AppendInt(int32 InNum);
1557
1566 static bool ToBlob(const FString& Source, uint8* DestBuffer, const uint32 DestSize);
1567
1576 static bool ToHexBlob(const FString& Source, uint8* DestBuffer, const uint32 DestSize);
1577
1586 template <typename T, typename Allocator>
1587 static FString Join(const TArray<T, Allocator>& Array, const TCHAR* Separator)
1588 {
1589 FString Result;
1590 bool First = true;
1591 for (const T& Element : Array)
1592 {
1593 if (First)
1594 {
1595 First = false;
1596 }
1597 else
1598 {
1599 Result += Separator;
1600 }
1601
1602 Result += Element;
1603 }
1604
1605 return Result;
1606 }
1607
1611 std::string ToString() const
1612 {
1613 TCHAR* data = Data.GetData();
1614
1615 if (!data)
1616 return "";
1617
1618 int size_needed = WideCharToMultiByte(CP_UTF8, 0, &data[0], (int)Len(), NULL, 0, NULL, NULL);
1619 std::string str(size_needed, 0);
1620 WideCharToMultiByte(CP_UTF8, 0, &data[0], (int)Len(), &str[0], size_needed, NULL, NULL);
1621 return str;
1622 }
1623
1632 template <typename T, typename... Args>
1633 static FString Format(const T* format, Args&&... args)
1634 {
1635 if constexpr (!TIsCharType<T>::Value)
1636 static_assert(TIsCharType<T>::Value, "format must be a char or wchar_t");
1637
1638 auto formatted_msg = fmt::format(format, std::forward<Args>(args)...);
1639
1640 return FString(formatted_msg.c_str());
1641 }
1642
1643
1644};
1645
1646FORCEINLINE uint32 GetTypeHash(const FString& Thing)
1647{
1648 uint32 Hash = FCrc::MemCrc32(&Thing, sizeof(FString));
1649 return Hash;
1650}
1651
1652template<>
1654{
1656};
1657
1658template<> struct TIsZeroConstructType<FString> { enum { Value = true }; };
1660
1661template <>
1663{
1664 enum { Value = true };
1665};
1666
1667inline TCHAR* GetData(FString& String)
1668{
1669 return String.GetCharArray().GetData();
1670}
1671
1672inline const TCHAR* GetData(const FString& String)
1673{
1674 return String.GetCharArray().GetData();
1675}
1676
1677inline SIZE_T GetNum(const FString& String)
1678{
1679 return String.GetCharArray().Num();
1680}
1681
1688inline FString BytesToString(const uint8* In, int32 Count)
1689{
1690 FString Result;
1691 Result.Empty(Count);
1692
1693 while (Count)
1694 {
1695 // Put the byte into an int16 and add 1 to it, this keeps anything from being put into the string as a null terminator
1696 int16 Value = *In;
1697 Value += 1;
1698
1699 Result += TCHAR(Value);
1700
1701 ++In;
1702 Count--;
1703 }
1704 return Result;
1705}
1706
1714inline int32 StringToBytes(const FString& String, uint8* OutBytes, int32 MaxBufferSize)
1715{
1716 int32 NumBytes = 0;
1717 const TCHAR* CharPos = *String;
1718
1719 while (*CharPos && NumBytes < MaxBufferSize)
1720 {
1721 OutBytes[NumBytes] = (int8)(*CharPos - 1);
1722 CharPos++;
1723 ++NumBytes;
1724 }
1725 return NumBytes - 1;
1726}
1727
1730{
1731 if (Num > 9)
1732 {
1733 return TEXT('A') + TCHAR(Num - 10);
1734 }
1735 return TEXT('0') + TCHAR(Num);
1736}
1737
1743inline void ByteToHex(uint8 In, FString& Result)
1744{
1745 Result += NibbleToTChar(In >> 4);
1746 Result += NibbleToTChar(In & 15);
1747}
1748
1755inline FString BytesToHex(const uint8* In, int32 Count)
1756{
1757 FString Result;
1758 Result.Empty(Count * 2);
1759
1760 while (Count)
1761 {
1762 ByteToHex(*In++, Result);
1763 Count--;
1764 }
1765 return Result;
1766}
1767
1773inline const bool CheckTCharIsHex(const TCHAR Char)
1774{
1775 return (Char >= TEXT('0') && Char <= TEXT('9')) || (Char >= TEXT('A') && Char <= TEXT('F')) || (Char >= TEXT('a') && Char <= TEXT('f'));
1776}
1777
1783inline const uint8 TCharToNibble(const TCHAR Char)
1784{
1785 check(CheckTCharIsHex(Char));
1786 if (Char >= TEXT('0') && Char <= TEXT('9'))
1787 {
1788 return Char - TEXT('0');
1789 }
1790 else if (Char >= TEXT('A') && Char <= TEXT('F'))
1791 {
1792 return (Char - TEXT('A')) + 10;
1793 }
1794 return (Char - TEXT('a')) + 10;
1795}
1796
1803inline int32 HexToBytes(const FString& HexString, uint8* OutBytes)
1804{
1805 int32 NumBytes = 0;
1806 const bool bPadNibble = (HexString.Len() % 2) == 1;
1807 const TCHAR* CharPos = *HexString;
1808 if (bPadNibble)
1809 {
1810 OutBytes[NumBytes++] = TCharToNibble(*CharPos++);
1811 }
1812 while (*CharPos)
1813 {
1814 OutBytes[NumBytes] = TCharToNibble(*CharPos++) << 4;
1815 OutBytes[NumBytes] += TCharToNibble(*CharPos++);
1816 ++NumBytes;
1817 }
1818 return NumBytes;
1819}
1820
1822namespace Lex
1823{
1837 inline void FromString(int8& OutValue, const TCHAR* Buffer) { OutValue = FCString::Atoi(Buffer); }
1838 inline void FromString(int16& OutValue, const TCHAR* Buffer) { OutValue = FCString::Atoi(Buffer); }
1839 inline void FromString(int32& OutValue, const TCHAR* Buffer) { OutValue = FCString::Atoi(Buffer); }
1840 inline void FromString(int64& OutValue, const TCHAR* Buffer) { OutValue = FCString::Atoi64(Buffer); }
1841 inline void FromString(uint8& OutValue, const TCHAR* Buffer) { OutValue = FCString::Atoi(Buffer); }
1842 inline void FromString(uint16& OutValue, const TCHAR* Buffer) { OutValue = FCString::Atoi(Buffer); }
1843 inline void FromString(uint32& OutValue, const TCHAR* Buffer) { OutValue = FCString::Atoi64(Buffer); } //64 because this unsigned and so Atoi might overflow
1844 inline void FromString(uint64& OutValue, const TCHAR* Buffer) { OutValue = FCString::Strtoui64(Buffer, nullptr, 0); }
1845 inline void FromString(float& OutValue, const TCHAR* Buffer) { OutValue = FCString::Atof(Buffer); }
1846 inline void FromString(double& OutValue, const TCHAR* Buffer) { OutValue = FCString::Atod(Buffer); }
1847 inline void FromString(FString& OutValue, const TCHAR* Buffer) { OutValue = Buffer; }
1848
1849 template<typename CharType>
1851 ToString(const CharType* Ptr)
1852 {
1853 return FString(Ptr);
1854 }
1855
1857 {
1858 return Value ? TEXT("true") : TEXT("false");
1859 }
1860
1861 FORCEINLINE FString ToString(FString&& Str)
1862 {
1863 return MoveTemp(Str);
1864 }
1865
1866 FORCEINLINE FString ToString(const FString& Str)
1867 {
1868 return Str;
1869 }
1870
1872 template<typename T>
1874 {
1875 return ToString(Value);
1876 }
1877
1880 template<typename T>
1881 static typename TEnableIf<TIsArithmetic<T>::Value, bool>::Type
1882 TryParseString(T& OutValue, const TCHAR* Buffer)
1883 {
1884 if (FCString::IsNumeric(Buffer))
1885 {
1886 FromString(OutValue, Buffer);
1887 return true;
1888 }
1889 return false;
1890 }
1891}
1892
1893// Deprecated alias for old LexicalConversion namespace.
1894// Namespace alias deprecation doesn't work on our compilers, so we can't actually mark it with the DEPRECATED() macro.
1895namespace LexicalConversion = Lex;
1896
1898template<typename T>
1900{
1901 static FString ToString(const T& Value) { return Lex::ToString(Value); }
1903};
1904template<typename T>
1906{
1907 static void FromString(T& Value, const TCHAR* Buffer) { return Lex::FromString(Value, Buffer); }
1908};
1909
1910
1911/* FString implementation
1912*****************************************************************************/
1913
1915{
1917 {
1918 static FORCEINLINE bool Compare(TCHAR Lhs, TCHAR Rhs)
1919 {
1920 return Lhs == Rhs;
1921 }
1922 };
1923
1925 {
1926 static FORCEINLINE bool Compare(TCHAR Lhs, TCHAR Rhs)
1927 {
1928 return FChar::ToLower(Lhs) == FChar::ToLower(Rhs);
1929 }
1930 };
1931
1932 template <typename CompareType>
1933 bool MatchesWildcardRecursive(const TCHAR* Target, int32 TargetLength, const TCHAR* Wildcard, int32 WildcardLength)
1934 {
1935 // Skip over common initial non-wildcard-char sequence of Target and Wildcard
1936 for (;;)
1937 {
1938 TCHAR WCh = *Wildcard;
1939 if (WCh == TEXT('*') || WCh == TEXT('?'))
1940 {
1941 break;
1942 }
1943
1944 if (!CompareType::Compare(*Target, WCh))
1945 {
1946 return false;
1947 }
1948
1949 if (WCh == TEXT('\0'))
1950 {
1951 return true;
1952 }
1953
1954 ++Target;
1955 ++Wildcard;
1956 --TargetLength;
1957 --WildcardLength;
1958 }
1959
1960 // Test for common suffix
1961 const TCHAR* TPtr = Target + TargetLength;
1962 const TCHAR* WPtr = Wildcard + WildcardLength;
1963 for (;;)
1964 {
1965 --TPtr;
1966 --WPtr;
1967
1968 TCHAR WCh = *WPtr;
1969 if (WCh == TEXT('*') || WCh == TEXT('?'))
1970 {
1971 break;
1972 }
1973
1974 if (!CompareType::Compare(*TPtr, WCh))
1975 {
1976 return false;
1977 }
1978
1979 --TargetLength;
1980 if (TargetLength == 0)
1981 {
1982 return false;
1983 }
1984
1985 --WildcardLength;
1986 }
1987
1988 // Match * against anything and ? against single (and zero?) chars
1989 TCHAR FirstWild = *Wildcard;
1990 if (WildcardLength == 1 && (FirstWild == TEXT('*') || TargetLength < 2))
1991 {
1992 return true;
1993 }
1994 ++Wildcard;
1995 --WildcardLength;
1996
1997 // This routine is very slow, though it does ok with one wildcard
1998 int32 MaxNum = TargetLength;
1999 if (FirstWild == TEXT('?') && MaxNum > 1)
2000 {
2001 MaxNum = 1;
2002 }
2003
2004 for (int32 Index = 0; Index <= MaxNum; ++Index)
2005 {
2006 if (MatchesWildcardRecursive<CompareType>(Target, TargetLength - Index, Wildcard, WildcardLength))
2007 {
2008 return true;
2009 }
2010 }
2011 return false;
2012 }
2013}
2014
2016{
2017 if (Data.Num())
2018 {
2019 int32 DataLen = FCString::Strlen(Data.GetData());
2020 int32 Len = DataLen > 0 ? DataLen + 1 : 0;
2021
2022 Data.RemoveAt(Len, Data.Num() - Len);
2023 }
2024}
2025
2026
2027inline int32 FString::Find(const TCHAR* SubStr, ESearchCase::Type SearchCase, ESearchDir::Type SearchDir, int32 StartPosition) const
2028{
2029 if (SubStr == nullptr)
2030 {
2031 return INDEX_NONE;
2032 }
2033 if (SearchDir == ESearchDir::FromStart)
2034 {
2035 const TCHAR* Start = **this;
2036 if (StartPosition != INDEX_NONE)
2037 {
2038 Start += FMath::Clamp(StartPosition, 0, Len() - 1);
2039 }
2040 const TCHAR* Tmp = SearchCase == ESearchCase::IgnoreCase
2041 ? FCString::Stristr(Start, SubStr)
2042 : FCString::Strstr(Start, SubStr);
2043
2044 return Tmp ? (Tmp - **this) : INDEX_NONE;
2045 }
2046 else
2047 {
2048 // if ignoring, do a onetime ToUpper on both strings, to avoid ToUppering multiple
2049 // times in the loop below
2050 if (SearchCase == ESearchCase::IgnoreCase)
2051 {
2052 return ToUpper().Find(FString(SubStr).ToUpper(), ESearchCase::CaseSensitive, SearchDir, StartPosition);
2053 }
2054 else
2055 {
2056 const int32 SearchStringLength = FMath::Max(1, FCString::Strlen(SubStr));
2057
2058 if (StartPosition == INDEX_NONE || StartPosition >= Len())
2059 {
2060 StartPosition = Len();
2061 }
2062
2063 for (int32 i = StartPosition - SearchStringLength; i >= 0; i--)
2064 {
2065 int32 j;
2066 for (j = 0; SubStr[j]; j++)
2067 {
2068 if ((*this)[i + j] != SubStr[j])
2069 {
2070 break;
2071 }
2072 }
2073
2074 if (!SubStr[j])
2075 {
2076 return i;
2077 }
2078 }
2079 return INDEX_NONE;
2080 }
2081 }
2082}
2083
2085{
2086 FString New = *this;
2087 New.ToUpperInline();
2088 return New;
2089}
2090
2092{
2093 this->ToUpperInline();
2094 return MoveTemp(*this);
2095}
2096
2098{
2099 const int32 StringLength = Len();
2100 TCHAR* RawData = Data.GetData();
2101 for (int32 i = 0; i < StringLength; ++i)
2102 {
2103 RawData[i] = FChar::ToUpper(RawData[i]);
2104 }
2105}
2106
2107
2109{
2110 FString New = *this;
2111 New.ToLowerInline();
2112 return New;
2113}
2114
2116{
2117 this->ToLowerInline();
2118 return MoveTemp(*this);
2119}
2120
2122{
2123 const int32 StringLength = Len();
2124 TCHAR* RawData = Data.GetData();
2125 for (int32 i = 0; i < StringLength; ++i)
2126 {
2127 RawData[i] = FChar::ToLower(RawData[i]);
2128 }
2129}
2130
2131inline bool FString::StartsWith(const TCHAR* InPrefix, ESearchCase::Type SearchCase) const
2132{
2133 if (SearchCase == ESearchCase::IgnoreCase)
2134 {
2135 return InPrefix && *InPrefix && !FCString::Strnicmp(**this, InPrefix, FCString::Strlen(InPrefix));
2136 }
2137 else
2138 {
2139 return InPrefix && *InPrefix && !FCString::Strncmp(**this, InPrefix, FCString::Strlen(InPrefix));
2140 }
2141}
2142
2143inline bool FString::StartsWith(const FString& InPrefix, ESearchCase::Type SearchCase) const
2144{
2145 if (SearchCase == ESearchCase::IgnoreCase)
2146 {
2147 return InPrefix.Len() > 0 && !FCString::Strnicmp(**this, *InPrefix, InPrefix.Len());
2148 }
2149 else
2150 {
2151 return InPrefix.Len() > 0 && !FCString::Strncmp(**this, *InPrefix, InPrefix.Len());
2152 }
2153}
2154
2155inline bool FString::EndsWith(const TCHAR* InSuffix, ESearchCase::Type SearchCase) const
2156{
2157 if (!InSuffix || *InSuffix == TEXT('\0'))
2158 {
2159 return false;
2160 }
2161
2162 int32 ThisLen = this->Len();
2163 int32 SuffixLen = FCString::Strlen(InSuffix);
2164 if (SuffixLen > ThisLen)
2165 {
2166 return false;
2167 }
2168
2169 const TCHAR* StrPtr = Data.GetData() + ThisLen - SuffixLen;
2170 if (SearchCase == ESearchCase::IgnoreCase)
2171 {
2172 return !FCString::Stricmp(StrPtr, InSuffix);
2173 }
2174 else
2175 {
2176 return !FCString::Strcmp(StrPtr, InSuffix);
2177 }
2178}
2179
2180inline bool FString::EndsWith(const FString& InSuffix, ESearchCase::Type SearchCase) const
2181{
2182 if (SearchCase == ESearchCase::IgnoreCase)
2183 {
2184 return InSuffix.Len() > 0 &&
2185 Len() >= InSuffix.Len() &&
2186 !FCString::Stricmp(&(*this)[Len() - InSuffix.Len()], *InSuffix);
2187 }
2188 else
2189 {
2190 return InSuffix.Len() > 0 &&
2191 Len() >= InSuffix.Len() &&
2192 !FCString::Strcmp(&(*this)[Len() - InSuffix.Len()], *InSuffix);
2193 }
2194}
2195
2196inline bool FString::RemoveFromStart(const FString& InPrefix, ESearchCase::Type SearchCase)
2197{
2198 if (InPrefix.IsEmpty())
2199 {
2200 return false;
2201 }
2202
2203 if (StartsWith(InPrefix, SearchCase))
2204 {
2205 RemoveAt(0, InPrefix.Len());
2206 return true;
2207 }
2208
2209 return false;
2210}
2211
2212inline bool FString::RemoveFromEnd(const FString& InSuffix, ESearchCase::Type SearchCase)
2213{
2214 if (InSuffix.IsEmpty())
2215 {
2216 return false;
2217 }
2218
2219 if (EndsWith(InSuffix, SearchCase))
2220 {
2221 RemoveAt(Len() - InSuffix.Len(), InSuffix.Len());
2222 return true;
2223 }
2224
2225 return false;
2226}
2227
2234inline void FString::PathAppend(const TCHAR* Str, int32 StrLength)
2235{
2236 int32 DataNum = Data.Num();
2237 if (StrLength == 0)
2238 {
2239 if (DataNum > 1 && Data[DataNum - 2] != TEXT('/') && Data[DataNum - 2] != TEXT('\\'))
2240 {
2241 Data[DataNum - 1] = TEXT('/');
2242 Data.Add(TEXT('\0'));
2243 }
2244 }
2245 else
2246 {
2247 if (DataNum > 0)
2248 {
2249 if (DataNum > 1 && Data[DataNum - 2] != TEXT('/') && Data[DataNum - 2] != TEXT('\\') && *Str != TEXT('/'))
2250 {
2251 Data[DataNum - 1] = TEXT('/');
2252 }
2253 else
2254 {
2255 Data.Pop(false);
2256 --DataNum;
2257 }
2258 }
2259
2260 Data.Reserve(DataNum + StrLength + 1);
2261 Data.Append(Str, StrLength);
2262 Data.Add(TEXT('\0'));
2263 }
2264}
2265
2267{
2268 TrimEndInline();
2270}
2271
2273{
2274 FString Result(*this);
2275 Result.TrimStartAndEndInline();
2276 return Result;
2277}
2278
2280{
2281 FString Result(MoveTemp(*this));
2282 Result.TrimStartAndEndInline();
2283 return Result;
2284}
2285
2287{
2288 int32 Pos = 0;
2289 while (Pos < Len() && FChar::IsWhitespace((*this)[Pos]))
2290 {
2291 Pos++;
2292 }
2293 RemoveAt(0, Pos);
2294}
2295
2297{
2298 FString Result(*this);
2299 Result.TrimStartInline();
2300 return Result;
2301}
2302
2304{
2305 FString Result(MoveTemp(*this));
2306 Result.TrimStartInline();
2307 return Result;
2308}
2309
2311{
2312 int32 End = Len();
2313 while (End > 0 && FChar::IsWhitespace((*this)[End - 1]))
2314 {
2315 End--;
2316 }
2317 RemoveAt(End, Len() - End);
2318}
2319
2321{
2322 FString Result(*this);
2323 Result.TrimEndInline();
2324 return Result;
2325}
2326
2328{
2329 FString Result(MoveTemp(*this));
2330 Result.TrimEndInline();
2331 return Result;
2332}
2333
2334inline FString FString::TrimQuotes(bool* bQuotesRemoved) const
2335{
2336 bool bQuotesWereRemoved = false;
2337 int32 Start = 0, Count = Len();
2338 if (Count > 0)
2339 {
2340 if ((*this)[0] == TCHAR('"'))
2341 {
2342 Start++;
2343 Count--;
2344 bQuotesWereRemoved = true;
2345 }
2346
2347 if (Len() > 1 && (*this)[Len() - 1] == TCHAR('"'))
2348 {
2349 Count--;
2350 bQuotesWereRemoved = true;
2351 }
2352 }
2353
2354 if (bQuotesRemoved != nullptr)
2355 {
2356 *bQuotesRemoved = bQuotesWereRemoved;
2357 }
2358 return Mid(Start, Count);
2359}
2360
2362{
2363 FString Empty;
2364 InArray->Remove(Empty);
2365 return InArray->Num();
2366}
2367
2369{
2370 FString New(*this);
2371 New.ReverseString();
2372 return New;
2373}
2374
2376{
2377 if (Len() > 0)
2378 {
2379 TCHAR* StartChar = &(*this)[0];
2380 TCHAR* EndChar = &(*this)[Len() - 1];
2381 TCHAR TempChar;
2382 do
2383 {
2384 TempChar = *StartChar; // store the current value of StartChar
2385 *StartChar = *EndChar; // change the value of StartChar to the value of EndChar
2386 *EndChar = TempChar; // change the value of EndChar to the character that was previously at StartChar
2387
2388 StartChar++;
2389 EndChar--;
2390
2391 } while (StartChar < EndChar); // repeat until we've reached the midpoint of the string
2392 }
2393}
2394
2396{
2397 FString Number = FString::FromInt(InNumber), Result;
2398
2399 int32 dec = 0;
2400 for (int32 x = Number.Len() - 1; x > -1; --x)
2401 {
2402 Result += Number.Mid(x, 1);
2403
2404 dec++;
2405 if (dec == 3 && x > 0)
2406 {
2407 Result += TEXT(",");
2408 dec = 0;
2409 }
2410 }
2411
2412 return Result.Reverse();
2413}
2414
2415inline void FString::AppendInt(int32 InNum)
2416{
2417 int64 Num = InNum; // This avoids having to deal with negating -MAX_int32-1
2418 const TCHAR* NumberChar[11] = { TEXT("0"), TEXT("1"), TEXT("2"), TEXT("3"), TEXT("4"), TEXT("5"), TEXT("6"), TEXT("7"), TEXT("8"), TEXT("9"), TEXT("-") };
2419 bool bIsNumberNegative = false;
2420 TCHAR TempNum[16]; // 16 is big enough
2421 int32 TempAt = 16; // fill the temp string from the top down.
2422
2423 // Correctly handle negative numbers and convert to positive integer.
2424 if (Num < 0)
2425 {
2426 bIsNumberNegative = true;
2427 Num = -Num;
2428 }
2429
2430 TempNum[--TempAt] = 0; // NULL terminator
2431
2432 // Convert to string assuming base ten and a positive integer.
2433 do
2434 {
2435 TempNum[--TempAt] = *NumberChar[Num % 10];
2436 Num /= 10;
2437 } while (Num);
2438
2439 // Append sign as we're going to reverse string afterwards.
2440 if (bIsNumberNegative)
2441 {
2442 TempNum[--TempAt] = *NumberChar[10];
2443 }
2444
2445 *this += TempNum + TempAt;
2446}
2447
2448inline bool FString::ToBlob(const FString& Source, uint8* DestBuffer, const uint32 DestSize)
2449{
2450 // Make sure the buffer is at least half the size and that the string is an
2451 // even number of characters long
2452 if (DestSize >= (uint32)(Source.Len() / 3) &&
2453 (Source.Len() % 3) == 0)
2454 {
2455 TCHAR ConvBuffer[4];
2456 ConvBuffer[3] = TEXT('\0');
2457 int32 WriteIndex = 0;
2458 // Walk the string 3 chars at a time
2459 for (int32 Index = 0; Index < Source.Len(); Index += 3, WriteIndex++)
2460 {
2461 ConvBuffer[0] = Source[Index];
2462 ConvBuffer[1] = Source[Index + 1];
2463 ConvBuffer[2] = Source[Index + 2];
2464 DestBuffer[WriteIndex] = FCString::Atoi(ConvBuffer);
2465 }
2466 return true;
2467 }
2468 return false;
2469}
2470
2471inline bool FString::ToHexBlob(const FString& Source, uint8* DestBuffer, const uint32 DestSize)
2472{
2473 // Make sure the buffer is at least half the size and that the string is an
2474 // even number of characters long
2475 if (DestSize >= (uint32)(Source.Len() / 2) &&
2476 (Source.Len() % 2) == 0)
2477 {
2478 TCHAR ConvBuffer[3];
2479 ConvBuffer[2] = TEXT('\0');
2480 int32 WriteIndex = 0;
2481 // Walk the string 2 chars at a time
2482 TCHAR* End = nullptr;
2483 for (int32 Index = 0; Index < Source.Len(); Index += 2, WriteIndex++)
2484 {
2485 ConvBuffer[0] = Source[Index];
2486 ConvBuffer[1] = Source[Index + 1];
2487 DestBuffer[WriteIndex] = FCString::Strtoi(ConvBuffer, &End, 16);
2488 }
2489 return true;
2490 }
2491 return false;
2492}
2493
2495{
2496 TCHAR Temp[2] = { Ch,0 };
2497 return FString(Temp);
2498}
2499
2500
2501inline FString FString::ChrN(int32 NumCharacters, TCHAR Char)
2502{
2503 FString Temp;
2504 Temp.Data.AddUninitialized(NumCharacters + 1);
2505 for (int32 Cx = 0; Cx < NumCharacters; ++Cx)
2506 {
2507 Temp[Cx] = Char;
2508 }
2509 Temp.Data[NumCharacters] = 0;
2510 return Temp;
2511}
2512
2513inline FString FString::LeftPad(int32 ChCount) const
2514{
2515 int32 Pad = ChCount - Len();
2516
2517 if (Pad > 0)
2518 {
2519 return ChrN(Pad, ' ') + *this;
2520 }
2521 else
2522 {
2523 return *this;
2524 }
2525}
2526
2527inline FString FString::RightPad(int32 ChCount) const
2528{
2529 int32 Pad = ChCount - Len();
2530
2531 if (Pad > 0)
2532 {
2533 return *this + ChrN(Pad, ' ');
2534 }
2535 else
2536 {
2537 return *this;
2538 }
2539}
2540
2541inline bool FString::IsNumeric() const
2542{
2543 if (IsEmpty())
2544 {
2545 return 0;
2546 }
2547
2549}
2550
2560inline int32 FString::ParseIntoArray(TArray<FString>& OutArray, const TCHAR* pchDelim, const bool InCullEmpty) const
2561{
2562 // Make sure the delimit string is not null or empty
2563 OutArray.Reset();
2564 const TCHAR *Start = Data.GetData();
2565 const int32 DelimLength = FCString::Strlen(pchDelim);
2566 if (Start && *Start != TEXT('\0') && DelimLength)
2567 {
2568 while (const TCHAR *At = FCString::Strstr(Start, pchDelim))
2569 {
2570 if (!InCullEmpty || At - Start)
2571 {
2572 OutArray.Emplace(At - Start, Start);
2573 }
2574 Start = At + DelimLength;
2575 }
2576 if (!InCullEmpty || *Start)
2577 {
2578 OutArray.Emplace(Start);
2579 }
2580
2581 }
2582 return OutArray.Num();
2583}
2584
2585inline bool FString::MatchesWildcard(const FString& InWildcard, ESearchCase::Type SearchCase) const
2586{
2587 FString Wildcard(InWildcard);
2588 FString Target(*this);
2589 int32 IndexOfStar = Wildcard.Find(TEXT("*"), ESearchCase::CaseSensitive, ESearchDir::FromEnd); // last occurance
2590 int32 IndexOfQuestion = Wildcard.Find(TEXT("?"), ESearchCase::CaseSensitive, ESearchDir::FromEnd); // last occurance
2591 int32 Suffix = FMath::Max<int32>(IndexOfStar, IndexOfQuestion);
2592 if (Suffix == INDEX_NONE)
2593 {
2594 // no wildcards
2595 if (SearchCase == ESearchCase::IgnoreCase)
2596 {
2597 return FCString::Stricmp(*Target, *Wildcard) == 0;
2598 }
2599 else
2600 {
2601 return FCString::Strcmp(*Target, *Wildcard) == 0;
2602 }
2603 }
2604 else
2605 {
2606 if (Suffix + 1 < Wildcard.Len())
2607 {
2608 FString SuffixString = Wildcard.Mid(Suffix + 1);
2609 if (!Target.EndsWith(SuffixString, SearchCase))
2610 {
2611 return false;
2612 }
2613 Wildcard = Wildcard.Left(Suffix + 1);
2614 Target = Target.Left(Target.Len() - SuffixString.Len());
2615 }
2616 int32 PrefixIndexOfStar = Wildcard.Find(TEXT("*"), ESearchCase::CaseSensitive);
2617 int32 PrefixIndexOfQuestion = Wildcard.Find(TEXT("?"), ESearchCase::CaseSensitive);
2618 int32 Prefix = FMath::Min<int32>(PrefixIndexOfStar < 0 ? INT_MAX : PrefixIndexOfStar, PrefixIndexOfQuestion < 0 ? INT_MAX : PrefixIndexOfQuestion);
2619 if (Prefix > 0)
2620 {
2621 FString PrefixString = Wildcard.Left(Prefix);
2622 if (!Target.StartsWith(PrefixString, SearchCase))
2623 {
2624 return false;
2625 }
2626 Wildcard = Wildcard.Mid(Prefix);
2627 Target = Target.Mid(Prefix);
2628 }
2629 }
2630 // This routine is very slow, though it does ok with one wildcard
2631 TCHAR FirstWild = Wildcard[0];
2632 Wildcard = Wildcard.Right(Wildcard.Len() - 1);
2633 if (FirstWild == TEXT('*') || FirstWild == TEXT('?'))
2634 {
2635 if (!Wildcard.Len())
2636 {
2637 if (FirstWild == TEXT('*') || Target.Len() < 2)
2638 {
2639 return true;
2640 }
2641 }
2642 int32 MaxNum = FMath::Min<int32>(Target.Len(), FirstWild == TEXT('?') ? 1 : INT_MAX);
2643 for (int32 Index = 0; Index <= MaxNum; Index++)
2644 {
2645 if (Target.Right(Target.Len() - Index).MatchesWildcard(Wildcard, SearchCase))
2646 {
2647 return true;
2648 }
2649 }
2650 return false;
2651 }
2652 else
2653 {
2654 return false;
2655 }
2656}
2657
2658
2660inline int32 FString::ParseIntoArrayWS(TArray<FString>& OutArray, const TCHAR* pchExtraDelim, bool InCullEmpty) const
2661{
2662 // default array of White Spaces, the last entry can be replaced with the optional pchExtraDelim string
2663 // (if you want to split on white space and another character)
2664 static const TCHAR* WhiteSpace[] =
2665 {
2666 TEXT(" "),
2667 TEXT("\t"),
2668 TEXT("\r"),
2669 TEXT("\n"),
2670 TEXT(""),
2671 };
2672
2673 // start with just the standard whitespaces
2674 int32 NumWhiteSpaces = ARRAY_COUNT(WhiteSpace) - 1;
2675 // if we got one passed in, use that in addition
2676 if (pchExtraDelim && *pchExtraDelim)
2677 {
2678 WhiteSpace[NumWhiteSpaces++] = pchExtraDelim;
2679 }
2680
2681 return ParseIntoArray(OutArray, WhiteSpace, NumWhiteSpaces, InCullEmpty);
2682}
2683
2684inline int32 FString::ParseIntoArrayLines(TArray<FString>& OutArray, bool InCullEmpty) const
2685{
2686 // default array of LineEndings
2687 static const TCHAR* LineEndings[] =
2688 {
2689 TEXT("\r\n"),
2690 TEXT("\r"),
2691 TEXT("\n"),
2692 };
2693
2694 // start with just the standard line endings
2695 int32 NumLineEndings = ARRAY_COUNT(LineEndings);
2696 return ParseIntoArray(OutArray, LineEndings, NumLineEndings, InCullEmpty);
2697}
2698
2699#pragma warning(push)
2700#pragma warning(disable : 4291)
2701
2702inline int32 FString::ParseIntoArray(TArray<FString>& OutArray, const TCHAR** DelimArray, int32 NumDelims, bool InCullEmpty) const
2703{
2704 // Make sure the delimit string is not null or empty
2705 OutArray.Empty();
2706 const TCHAR *Start = Data.GetData();
2707 const int32 Length = Len();
2708 if (Start)
2709 {
2710 int32 SubstringBeginIndex = 0;
2711
2712 // Iterate through string.
2713 for (int32 i = 0; i < Len();)
2714 {
2715 int32 SubstringEndIndex = INDEX_NONE;
2716 int32 DelimiterLength = 0;
2717
2718 // Attempt each delimiter.
2719 for (int32 DelimIndex = 0; DelimIndex < NumDelims; ++DelimIndex)
2720 {
2721 DelimiterLength = FCString::Strlen(DelimArray[DelimIndex]);
2722
2723 // If we found a delimiter...
2724 if (FCString::Strncmp(Start + i, DelimArray[DelimIndex], DelimiterLength) == 0)
2725 {
2726 // Mark the end of the substring.
2727 SubstringEndIndex = i;
2728 break;
2729 }
2730 }
2731
2732 if (SubstringEndIndex != INDEX_NONE)
2733 {
2734 const int32 SubstringLength = SubstringEndIndex - SubstringBeginIndex;
2735 // If we're not culling empty strings or if we are but the string isn't empty anyways...
2736 if (!InCullEmpty || SubstringLength != 0)
2737 {
2738 // ... add new string from substring beginning up to the beginning of this delimiter.
2739 new (OutArray) FString(SubstringEndIndex - SubstringBeginIndex, Start + SubstringBeginIndex);
2740 }
2741 // Next substring begins at the end of the discovered delimiter.
2742 SubstringBeginIndex = SubstringEndIndex + DelimiterLength;
2743 i = SubstringBeginIndex;
2744 }
2745 else
2746 {
2747 ++i;
2748 }
2749 }
2750
2751 // Add any remaining characters after the last delimiter.
2752 const int32 SubstringLength = Length - SubstringBeginIndex;
2753 // If we're not culling empty strings or if we are but the string isn't empty anyways...
2754 if (!InCullEmpty || SubstringLength != 0)
2755 {
2756 // ... add new string from substring beginning up to the beginning of this delimiter.
2757 new (OutArray) FString(Start + SubstringBeginIndex);
2758 }
2759 }
2760
2761 return OutArray.Num();
2762}
2763
2764#pragma warning(pop)
2765
2766inline FString FString::Replace(const TCHAR* From, const TCHAR* To, ESearchCase::Type SearchCase) const
2767{
2768 // Previous code used to accidentally accept a nullptr replacement string - this is no longer accepted.
2769
2770 if (IsEmpty() || !From || !*From)
2771 {
2772 return *this;
2773 }
2774
2775 // get a pointer into the character data
2776 const TCHAR* Travel = Data.GetData();
2777
2778 // precalc the lengths of the replacement strings
2779 int32 FromLength = FCString::Strlen(From);
2780 int32 ToLength = FCString::Strlen(To);
2781
2782 FString Result;
2783 while (true)
2784 {
2785 // look for From in the remaining string
2786 const TCHAR* FromLocation = SearchCase == ESearchCase::IgnoreCase ? FCString::Stristr(Travel, From) : FCString::Strstr(Travel, From);
2787 if (!FromLocation)
2788 break;
2789
2790 // copy everything up to FromLocation
2791 Result.AppendChars(Travel, FromLocation - Travel);
2792
2793 // copy over the To
2794 Result.AppendChars(To, ToLength);
2795
2796 Travel = FromLocation + FromLength;
2797 }
2798
2799 // copy anything left over
2800 Result += Travel;
2801
2802 return Result;
2803}
2804
2805inline int32 FString::ReplaceInline(const TCHAR* SearchText, const TCHAR* ReplacementText, ESearchCase::Type SearchCase)
2806{
2807 int32 ReplacementCount = 0;
2808
2809 if (Len() > 0
2810 && SearchText != nullptr && *SearchText != 0
2811 && ReplacementText != nullptr && (SearchCase == ESearchCase::IgnoreCase || FCString::Strcmp(SearchText, ReplacementText) != 0))
2812 {
2813 const int32 NumCharsToReplace = FCString::Strlen(SearchText);
2814 const int32 NumCharsToInsert = FCString::Strlen(ReplacementText);
2815
2816 if (NumCharsToInsert == NumCharsToReplace)
2817 {
2818 TCHAR* Pos = SearchCase == ESearchCase::IgnoreCase ? FCString::Stristr(&(*this)[0], SearchText) : FCString::Strstr(&(*this)[0], SearchText);
2819 while (Pos != nullptr)
2820 {
2821 ReplacementCount++;
2822
2823 // FCString::Strcpy now inserts a terminating zero so can't use that
2824 for (int32 i = 0; i < NumCharsToInsert; i++)
2825 {
2826 Pos[i] = ReplacementText[i];
2827 }
2828
2829 if (Pos + NumCharsToReplace - **this < Len())
2830 {
2831 Pos = SearchCase == ESearchCase::IgnoreCase ? FCString::Stristr(Pos + NumCharsToReplace, SearchText) : FCString::Strstr(Pos + NumCharsToReplace, SearchText);
2832 }
2833 else
2834 {
2835 break;
2836 }
2837 }
2838 }
2839 else if (Contains(SearchText, SearchCase))
2840 {
2841 FString Copy(*this);
2842 Empty(Len());
2843
2844 // get a pointer into the character data
2845 TCHAR* WritePosition = (TCHAR*)Copy.Data.GetData();
2846 // look for From in the remaining string
2847 TCHAR* SearchPosition = SearchCase == ESearchCase::IgnoreCase ? FCString::Stristr(WritePosition, SearchText) : FCString::Strstr(WritePosition, SearchText);
2848 while (SearchPosition != nullptr)
2849 {
2850 ReplacementCount++;
2851
2852 // replace the first letter of the From with 0 so we can do a strcpy (FString +=)
2853 *SearchPosition = 0;
2854
2855 // copy everything up to the SearchPosition
2856 (*this) += WritePosition;
2857
2858 // copy over the ReplacementText
2859 (*this) += ReplacementText;
2860
2861 // restore the letter, just so we don't have 0's in the string
2862 *SearchPosition = *SearchText;
2863
2864 WritePosition = SearchPosition + NumCharsToReplace;
2865 SearchPosition = SearchCase == ESearchCase::IgnoreCase ? FCString::Stristr(WritePosition, SearchText) : FCString::Strstr(WritePosition, SearchText);
2866 }
2867
2868 // copy anything left over
2869 (*this) += WritePosition;
2870 }
2871 }
2872
2873 return ReplacementCount;
2874}
2875
2876
2881{
2882 if (Contains(TEXT("\""), ESearchCase::CaseSensitive))
2883 {
2884 FString Result;
2885
2886 const TCHAR* pChar = **this;
2887
2888 bool bEscaped = false;
2889 while (*pChar != 0)
2890 {
2891 if (bEscaped)
2892 {
2893 bEscaped = false;
2894 }
2895 else if (*pChar == TCHAR('\\'))
2896 {
2897 bEscaped = true;
2898 }
2899 else if (*pChar == TCHAR('"'))
2900 {
2901 Result += TCHAR('\\');
2902 }
2903
2904 Result += *pChar++;
2905 }
2906
2907 return Result;
2908 }
2909
2910 return *this;
2911}
2912
2913static const TCHAR* CharToEscapeSeqMap[][2] =
2914{
2915 // Always replace \\ first to avoid double-escaping characters
2916 { TEXT("\\"), TEXT("\\\\") },
2917{ TEXT("\n"), TEXT("\\n") },
2918{ TEXT("\r"), TEXT("\\r") },
2919{ TEXT("\t"), TEXT("\\t") },
2920{ TEXT("\'"), TEXT("\\'") },
2921{ TEXT("\""), TEXT("\\\"") }
2922};
2923
2925
2934inline FString FString::ReplaceCharWithEscapedChar(const TArray<TCHAR>* Chars/*=nullptr*/) const
2935{
2936 if (Len() > 0 && (Chars == nullptr || Chars->Num() > 0))
2937 {
2938 FString Result(*this);
2939 for (int32 ChIdx = 0; ChIdx < MaxSupportedEscapeChars; ChIdx++)
2940 {
2941 if (Chars == nullptr || Chars->Contains(*(CharToEscapeSeqMap[ChIdx][0])))
2942 {
2943 // use ReplaceInline as that won't create a copy of the string if the character isn't found
2944 Result.ReplaceInline(CharToEscapeSeqMap[ChIdx][0], CharToEscapeSeqMap[ChIdx][1]);
2945 }
2946 }
2947 return Result;
2948 }
2949
2950 return *this;
2951}
2956inline FString FString::ReplaceEscapedCharWithChar(const TArray<TCHAR>* Chars/*=nullptr*/) const
2957{
2958 if (Len() > 0 && (Chars == nullptr || Chars->Num() > 0))
2959 {
2960 FString Result(*this);
2961 // Spin CharToEscapeSeqMap backwards to ensure we're doing the inverse of ReplaceCharWithEscapedChar
2962 for (int32 ChIdx = MaxSupportedEscapeChars - 1; ChIdx >= 0; ChIdx--)
2963 {
2964 if (Chars == nullptr || Chars->Contains(*(CharToEscapeSeqMap[ChIdx][0])))
2965 {
2966 // use ReplaceInline as that won't create a copy of the string if the character isn't found
2967 Result.ReplaceInline(CharToEscapeSeqMap[ChIdx][1], CharToEscapeSeqMap[ChIdx][0]);
2968 }
2969 }
2970 return Result;
2971 }
2972
2973 return *this;
2974}
2975
2980inline FString FString::ConvertTabsToSpaces(const int32 InSpacesPerTab)
2981{
2982 //must call this with at least 1 space so the modulus operation works
2983
2984 FString FinalString = *this;
2985 int32 TabIndex;
2986 while ((TabIndex = FinalString.Find(TEXT("\t"))) != INDEX_NONE)
2987 {
2988 FString LeftSide = FinalString.Left(TabIndex);
2989 FString RightSide = FinalString.Mid(TabIndex + 1);
2990
2991 FinalString = LeftSide;
2992 //for a tab size of 4,
2993 int32 LineBegin = LeftSide.Find(TEXT("\n"), ESearchCase::IgnoreCase, ESearchDir::FromEnd, TabIndex);
2994 if (LineBegin == INDEX_NONE)
2995 {
2996 LineBegin = 0;
2997 }
2998 int32 CharactersOnLine = (LeftSide.Len() - LineBegin);
2999
3000 int32 NumSpacesForTab = InSpacesPerTab - (CharactersOnLine % InSpacesPerTab);
3001 for (int32 i = 0; i < NumSpacesForTab; ++i)
3002 {
3003 FinalString.AppendChar(' ');
3004 }
3005 FinalString += RightSide;
3006 }
3007
3008 return FinalString;
3009}
3010
3011inline int32 FindMatchingClosingParenthesis(const FString& TargetString, const int32 StartSearch)
3012{
3013 const TCHAR* const StartPosition = (*TargetString) + StartSearch;
3014 const TCHAR* CurrPosition = StartPosition;
3015 int32 ParenthesisCount = 0;
3016
3017 // Move to first open parenthesis
3018 while (*CurrPosition != 0 && *CurrPosition != TEXT('('))
3019 {
3020 ++CurrPosition;
3021 }
3022
3023 // Did we find the open parenthesis
3024 if (*CurrPosition == TEXT('('))
3025 {
3026 ++ParenthesisCount;
3027 ++CurrPosition;
3028
3029 while (*CurrPosition != 0 && ParenthesisCount > 0)
3030 {
3031 if (*CurrPosition == TEXT('('))
3032 {
3033 ++ParenthesisCount;
3034 }
3035 else if (*CurrPosition == TEXT(')'))
3036 {
3037 --ParenthesisCount;
3038 }
3039 ++CurrPosition;
3040 }
3041
3042 // Did we find the matching close parenthesis
3043 if (ParenthesisCount == 0 && *(CurrPosition - 1) == TEXT(')'))
3044 {
3045 return StartSearch + ((CurrPosition - 1) - StartPosition);
3046 }
3047 }
3048
3049 return INDEX_NONE;
3050}
3051
3052#pragma warning(pop)
3053
FPlatformTypes::int16 int16
A 16-bit signed integer.
Definition: BasicTypes.h:108
FPlatformTypes::int8 int8
An 8-bit signed integer.
Definition: BasicTypes.h:106
FPlatformTypes::SIZE_T SIZE_T
An unsigned integer the same size as a pointer, the same as UPTRINT.
Definition: BasicTypes.h:135
FPlatformTypes::uint8 uint8
Definition: BasicTypes.h:96
FPlatformTypes::uint16 uint16
A 16-bit unsigned integer.
Definition: BasicTypes.h:98
#define check(expr)
Definition: BasicTypes.h:14
FPlatformTypes::TCHAR TCHAR
Either ANSICHAR or WIDECHAR, depending on whether the platform supports wide characters or the requir...
Definition: BasicTypes.h:120
FPlatformTypes::int32 int32
A 32-bit signed integer.
Definition: BasicTypes.h:110
FPlatformTypes::int64 int64
A 64-bit signed integer.
Definition: BasicTypes.h:112
FPlatformTypes::uint32 uint32
A 32-bit unsigned integer.
Definition: BasicTypes.h:100
@ INDEX_NONE
Definition: BasicTypes.h:144
FPlatformTypes::uint64 uint64
A 64-bit unsigned integer.
Definition: BasicTypes.h:102
int32 FindMatchingClosingParenthesis(const FString &TargetString, const int32 StartSearch)
Definition: FString.h:3011
int32 HexToBytes(const FString &HexString, uint8 *OutBytes)
Definition: FString.h:1803
const uint8 TCharToNibble(const TCHAR Char)
Definition: FString.h:1783
const bool CheckTCharIsHex(const TCHAR Char)
Definition: FString.h:1773
FORCEINLINE uint32 GetTypeHash(const FString &Thing)
Definition: FString.h:1646
TCHAR * GetData(FString &String)
Definition: FString.h:1667
SIZE_T GetNum(const FString &String)
Definition: FString.h:1677
void ByteToHex(uint8 In, FString &Result)
Definition: FString.h:1743
static const uint32 MaxSupportedEscapeChars
Definition: FString.h:2924
FString BytesToHex(const uint8 *In, int32 Count)
Definition: FString.h:1755
int32 StringToBytes(const FString &String, uint8 *OutBytes, int32 MaxBufferSize)
Definition: FString.h:1714
static const TCHAR * CharToEscapeSeqMap[][2]
Definition: FString.h:2913
TCHAR NibbleToTChar(uint8 Num)
Definition: FString.h:1729
FString BytesToString(const uint8 *In, int32 Count)
Definition: FString.h:1688
FORCEINLINE TEnableIf<!TIsTriviallyCopyAssignable< ElementType >::Value >::Type CopyAssignItems(ElementType *Dest, const ElementType *Source, int32 Count)
Definition: MemoryOps.h:149
FORCEINLINE TRemoveReference< T >::Type && MoveTempIfPossible(T &&Obj)
#define ARRAY_COUNT(array)
FORCEINLINE TRemoveReference< T >::Type && MoveTemp(T &&Obj)
#define Expose_TNameOf(type)
FORCEINLINE const DataType & GetCharArray() const
Definition: FString.h:299
FORCEINLINE friend bool operator<=(const FString &Lhs, const CharType *Rhs)
Definition: FString.h:844
TArray< TCHAR >::TConstIterator TConstIterator
Definition: FString.h:189
FORCEINLINE void RemoveAt(int32 Index, int32 Count=1, bool bAllowShrinking=true)
Definition: FString.h:435
FORCEINLINE friend FString operator+(FString &&Lhs, FString &&Rhs)
Definition: FString.h:661
FORCEINLINE FString & Append(const FString &Text)
Definition: FString.h:396
FORCEINLINE uint32 GetAllocatedSize() const
Definition: FString.h:214
void ToUpperInline()
Definition: FString.h:2097
FString TrimStart() const &
Definition: FString.h:2296
int32 Find(const TCHAR *SubStr, ESearchCase::Type SearchCase=ESearchCase::IgnoreCase, ESearchDir::Type SearchDir=ESearchDir::FromStart, int32 StartPosition=INDEX_NONE) const
Definition: FString.h:2027
FORCEINLINE friend FString operator/(const FString &Lhs, const FString &Rhs)
Definition: FString.h:781
FORCEINLINE FString(const std::string &str)
Definition: FString.h:129
bool IsNumeric() const
Definition: FString.h:2541
FORCEINLINE friend FString operator+(const FString &Lhs, const TCHAR *Rhs)
Definition: FString.h:700
FORCEINLINE friend bool operator!=(const FString &Lhs, const CharType *Rhs)
Definition: FString.h:1049
FORCEINLINE int32 Find(const FString &SubStr, ESearchCase::Type SearchCase=ESearchCase::IgnoreCase, ESearchDir::Type SearchDir=ESearchDir::FromStart, int32 StartPosition=INDEX_NONE) const
Definition: FString.h:1128
FORCEINLINE friend DataType::RangedForIteratorType end(FString &Str)
Definition: FString.h:210
FORCEINLINE friend FString operator+(FString &&Lhs, const FString &Rhs)
Definition: FString.h:635
FString(FString &&)=default
FORCEINLINE FString & operator=(const TCHAR *Other)
Definition: FString.h:147
FORCEINLINE friend bool operator<(const CharType *Lhs, const FString &Rhs)
Definition: FString.h:899
FString TrimEnd() const &
Definition: FString.h:2320
void TrimStartInline()
Definition: FString.h:2286
FString Replace(const TCHAR *From, const TCHAR *To, ESearchCase::Type SearchCase=ESearchCase::IgnoreCase) const
Definition: FString.h:2766
FORCEINLINE FString LeftChop(int32 Count) const
Definition: FString.h:1081
FORCEINLINE bool FindChar(TCHAR InChar, int32 &Index) const
Definition: FString.h:1169
FORCEINLINE friend bool operator!=(const FString &Lhs, const FString &Rhs)
Definition: FString.h:1035
int32 ReplaceInline(const TCHAR *SearchText, const TCHAR *ReplacementText, ESearchCase::Type SearchCase=ESearchCase::IgnoreCase)
Definition: FString.h:2805
FORCEINLINE FString Mid(int32 Start, int32 Count=INT_MAX) const
Definition: FString.h:1099
FORCEINLINE FString(FString &&Other, int32 ExtraSlack)
Definition: FString.h:87
static FORCEINLINE FString ConcatFStrings(typename TIdentity< LhsType >::Type Lhs, typename TIdentity< RhsType >::Type Rhs)
Definition: FString.h:550
TArray< TCHAR >::TIterator TIterator
Definition: FString.h:188
static FString Chr(TCHAR Ch)
Definition: FString.h:2494
FORCEINLINE friend DataType::RangedForIteratorType begin(FString &Str)
Definition: FString.h:208
FORCEINLINE friend FString operator+(const FString &Lhs, FString &&Rhs)
Definition: FString.h:648
FORCEINLINE DataType & GetCharArray()
Definition: FString.h:293
FORCEINLINE friend bool operator==(const FString &Lhs, const CharType *Rhs)
Definition: FString.h:1008
static FORCEINLINE FString FromInt(int32 Num)
Definition: FString.h:1548
FORCEINLINE FString & operator+=(const FString &Str)
Definition: FString.h:500
FString & Append(const TCHAR *Text, int32 Count)
Definition: FString.h:402
FORCEINLINE FString & operator/=(const FString &Str)
Definition: FString.h:736
FORCEINLINE friend FString operator+(const FString &Lhs, const FString &Rhs)
Definition: FString.h:622
FORCEINLINE int32 Compare(const FString &Other, ESearchCase::Type SearchCase=ESearchCase::CaseSensitive) const
Definition: FString.h:1240
FORCEINLINE FString(const std::wstring &str)
Definition: FString.h:137
FORCEINLINE friend bool operator<=(const CharType *Lhs, const FString &Rhs)
Definition: FString.h:858
FORCEINLINE friend bool operator==(const FString &Lhs, const FString &Rhs)
Definition: FString.h:994
FORCEINLINE friend FString operator+(const TCHAR *Lhs, const FString &Rhs)
Definition: FString.h:674
FORCEINLINE TIterator CreateIterator()
Definition: FString.h:192
FORCEINLINE void Reserve(const uint32 CharacterCount)
Definition: FString.h:1542
FString ReplaceQuotesWithEscapedQuotes() const
Definition: FString.h:2880
FString & operator=(FString &&)=default
static int32 CullArray(TArray< FString > *InArray)
Definition: FString.h:2361
bool MatchesWildcard(const FString &Wildcard, ESearchCase::Type SearchCase=ESearchCase::IgnoreCase) const
Definition: FString.h:2585
FString Reverse() const
Definition: FString.h:2368
FString ConvertTabsToSpaces(const int32 InSpacesPerTab)
Definition: FString.h:2980
bool StartsWith(const TCHAR *InSuffix, ESearchCase::Type SearchCase=ESearchCase::IgnoreCase) const
Definition: FString.h:2131
FORCEINLINE friend bool operator!=(const CharType *Lhs, const FString &Rhs)
Definition: FString.h:1063
static FORCEINLINE FString ConcatTCHARsToFString(const TCHAR *Lhs, typename TIdentity< RhsType >::Type Rhs)
Definition: FString.h:569
FORCEINLINE FString Left(int32 Count) const
Definition: FString.h:1075
static bool ToHexBlob(const FString &Source, uint8 *DestBuffer, const uint32 DestSize)
Definition: FString.h:2471
int32 ParseIntoArrayLines(TArray< FString > &OutArray, bool InCullEmpty=true) const
Definition: FString.h:2684
FORCEINLINE bool FindLastChar(TCHAR InChar, int32 &Index) const
Definition: FString.h:1181
std::string ToString() const
Convert FString to std::string.
Definition: FString.h:1611
FString TrimQuotes(bool *bQuotesRemoved=nullptr) const
Definition: FString.h:2334
FORCEINLINE FString & operator+=(const TCHAR *Str)
Definition: FString.h:347
void AppendInt(int32 InNum)
Definition: FString.h:2415
FORCEINLINE const TCHAR * operator*() const
Definition: FString.h:282
FORCEINLINE friend FString operator/(FString &&Lhs, const TCHAR *Rhs)
Definition: FString.h:765
FString()=default
FORCEINLINE friend FString operator/(FString &&Lhs, const FString &Rhs)
Definition: FString.h:797
FString RightPad(int32 ChCount) const
Definition: FString.h:2527
FORCEINLINE friend TEnableIf< TIsCharType< CharType >::Value, FString >::Type operator+(const FString &Lhs, CharType Rhs)
Definition: FString.h:519
FORCEINLINE friend DataType::RangedForConstIteratorType end(const FString &Str)
Definition: FString.h:211
void PathAppend(const TCHAR *Str, int32 StrLength)
Definition: FString.h:2234
FORCEINLINE bool Contains(const FString &SubStr, ESearchCase::Type SearchCase=ESearchCase::IgnoreCase, ESearchDir::Type SearchDir=ESearchDir::FromStart) const
Definition: FString.h:1156
FORCEINLINE FString(const CharType *Src, typename TEnableIf< TIsCharType< CharType >::Value >::Type *Dummy=nullptr)
Definition: FString.h:98
void TrimEndInline()
Definition: FString.h:2310
FORCEINLINE FString RightChop(int32 Count) const
Definition: FString.h:1093
static FString ChrN(int32 NumCharacters, TCHAR Char)
Definition: FString.h:2501
static FORCEINLINE FString ConcatFStringToTCHARs(typename TIdentity< LhsType >::Type Lhs, const TCHAR *Rhs)
Definition: FString.h:596
FORCEINLINE friend FString operator+(const TCHAR *Lhs, FString &&Rhs)
Definition: FString.h:687
FORCEINLINE TConstIterator CreateConstIterator() const
Definition: FString.h:198
FString ToUpper() const &
Definition: FString.h:2084
FString(const FString &)=default
static FString FormatAsNumber(int32 InNumber)
Definition: FString.h:2395
FORCEINLINE bool Equals(const FString &Other, ESearchCase::Type SearchCase=ESearchCase::CaseSensitive) const
Definition: FString.h:1221
FORCEINLINE bool IsValidIndex(int32 Index) const
Definition: FString.h:272
FORCEINLINE friend FString operator/(const FString &Lhs, const TCHAR *Rhs)
Definition: FString.h:749
void ToLowerInline()
Definition: FString.h:2121
TArray< TCHAR > DataType
Definition: FString.h:58
DataType Data
Definition: FString.h:59
void TrimStartAndEndInline()
Definition: FString.h:2266
int32 ParseIntoArray(TArray< FString > &OutArray, const TCHAR *pchDelim, bool InCullEmpty=true) const
Definition: FString.h:2560
bool EndsWith(const TCHAR *InSuffix, ESearchCase::Type SearchCase=ESearchCase::IgnoreCase) const
Definition: FString.h:2155
FORCEINLINE FString(int32 InCount, const TCHAR *InSrc)
Definition: FString.h:116
FORCEINLINE friend DataType::RangedForConstIteratorType begin(const FString &Str)
Definition: FString.h:209
FORCEINLINE friend bool operator>(const FString &Lhs, const CharType *Rhs)
Definition: FString.h:967
FString ReplaceCharWithEscapedChar(const TArray< TCHAR > *Chars=nullptr) const
Definition: FString.h:2934
static bool ToBlob(const FString &Source, uint8 *DestBuffer, const uint32 DestSize)
Definition: FString.h:2448
FORCEINLINE TCHAR & operator[](int32 Index)
Definition: FString.h:169
FORCEINLINE void InsertAt(int32 Index, TCHAR Character)
Definition: FString.h:440
FORCEINLINE friend bool operator>=(const CharType *Lhs, const FString &Rhs)
Definition: FString.h:940
FORCEINLINE friend FString operator/(const TCHAR *Lhs, const FString &Rhs)
Definition: FString.h:813
FORCEINLINE void AppendChars(const TCHAR *Array, int32 Count)
Definition: FString.h:322
FORCEINLINE friend TEnableIf< TIsCharType< CharType >::Value, FString >::Type operator+(FString &&Lhs, CharType Rhs)
Definition: FString.h:538
FORCEINLINE void Shrink()
Definition: FString.h:260
FORCEINLINE friend bool operator>(const CharType *Lhs, const FString &Rhs)
Definition: FString.h:981
void ReverseString()
Definition: FString.h:2375
FORCEINLINE bool IsEmpty() const
Definition: FString.h:241
FORCEINLINE FString Right(int32 Count) const
Definition: FString.h:1087
FORCEINLINE void InsertAt(int32 Index, const FString &Characters)
Definition: FString.h:455
FORCEINLINE bool Contains(const TCHAR *SubStr, ESearchCase::Type SearchCase=ESearchCase::IgnoreCase, ESearchDir::Type SearchDir=ESearchDir::FromStart) const
Definition: FString.h:1142
FORCEINLINE friend bool operator>(const FString &Lhs, const FString &Rhs)
Definition: FString.h:953
TCHAR ElementType
Definition: FString.h:62
FORCEINLINE friend bool operator==(const CharType *Lhs, const FString &Rhs)
Definition: FString.h:1022
FORCEINLINE friend bool operator<(const FString &Lhs, const CharType *Rhs)
Definition: FString.h:885
static FString Join(const TArray< T, Allocator > &Array, const TCHAR *Separator)
Definition: FString.h:1587
bool RemoveFromEnd(const FString &InSuffix, ESearchCase::Type SearchCase=ESearchCase::IgnoreCase)
Definition: FString.h:2212
FORCEINLINE TEnableIf< TIsCharType< CharType >::Value, FString & >::Type operator+=(CharType InChar)
Definition: FString.h:363
FORCEINLINE const TCHAR & operator[](int32 Index) const
Definition: FString.h:180
FORCEINLINE friend bool operator<(const FString &Lhs, const FString &Rhs)
Definition: FString.h:871
FORCEINLINE friend bool operator>=(const FString &Lhs, const FString &Rhs)
Definition: FString.h:912
FString ToLower() const &
Definition: FString.h:2108
int32 ParseIntoArrayWS(TArray< FString > &OutArray, const TCHAR *pchExtraDelim=nullptr, bool InCullEmpty=true) const
Definition: FString.h:2660
bool Split(const FString &InS, FString *LeftS, FString *RightS, ESearchCase::Type SearchCase=ESearchCase::IgnoreCase, ESearchDir::Type SearchDir=ESearchDir::FromStart) const
Definition: FString.h:1262
static FString Format(const T *format, Args &&... args)
Formats text using fmt::format.
Definition: FString.h:1633
FString LeftPad(int32 ChCount) const
Definition: FString.h:2513
FORCEINLINE int32 FindLastCharByPredicate(Predicate Pred) const
Definition: FString.h:1209
FORCEINLINE void Reset(int32 NewReservedSize=0)
Definition: FString.h:251
FORCEINLINE void Empty(int32 Slack=0)
Definition: FString.h:231
FORCEINLINE int32 Len() const
Definition: FString.h:1069
FORCEINLINE int32 FindLastCharByPredicate(Predicate Pred, int32 Count) const
Definition: FString.h:1195
void TrimToNullTerminator()
Definition: FString.h:2015
bool RemoveFromStart(const FString &InPrefix, ESearchCase::Type SearchCase=ESearchCase::IgnoreCase)
Definition: FString.h:2196
FORCEINLINE FString & AppendChar(const TCHAR InChar)
Definition: FString.h:390
FORCEINLINE friend bool operator>=(const FString &Lhs, const CharType *Rhs)
Definition: FString.h:926
FORCEINLINE friend bool operator<=(const FString &Lhs, const FString &Rhs)
Definition: FString.h:830
FORCEINLINE void CheckInvariants() const
Definition: FString.h:222
FORCEINLINE friend FString operator+(FString &&Lhs, const TCHAR *Rhs)
Definition: FString.h:713
FString ReplaceEscapedCharWithChar(const TArray< TCHAR > *Chars=nullptr) const
Definition: FString.h:2956
FORCEINLINE FString(const FString &Other, int32 ExtraSlack)
Definition: FString.h:76
FORCEINLINE FString & operator/=(const TCHAR *Str)
Definition: FString.h:724
FString & operator=(const FString &)=default
FString TrimStartAndEnd() const &
Definition: FString.h:2272
Definition: TArray.h:268
FORCEINLINE bool Find(const ElementType &Item, int32 &Index) const
Definition: TArray.h:760
FORCEINLINE int32 Num() const
Definition: TArray.h:611
int32 FindLastByPredicate(Predicate Pred, int32 Count) const
Definition: TArray.h:827
TIterator CreateIterator()
Definition: TArray.h:1913
FORCEINLINE int32 Emplace(ArgsType &&... Args)
Definition: TArray.h:1526
FORCEINLINE void Shrink()
Definition: TArray.h:743
void Append(const TArray< OtherElementType, OtherAllocator > &Source)
Definition: TArray.h:1407
FORCEINLINE bool FindLast(const ElementType &Item, int32 &Index) const
Definition: TArray.h:794
void Reset(int32 NewSize=0)
Definition: TArray.h:1302
bool Contains(const ComparisonType &Item) const
Definition: TArray.h:992
FORCEINLINE void RemoveAt(int32 Index)
Definition: TArray.h:1276
int32 Remove(const ElementType &Item)
Definition: TArray.h:1709
FORCEINLINE ElementType Pop(bool bAllowShrinking=true)
Definition: TArray.h:657
void Empty(int32 Slack=0)
Definition: TArray.h:1321
TConstIterator CreateConstIterator() const
Definition: TArray.h:1923
FORCEINLINE void Reserve(int32 Number)
Definition: TArray.h:1648
FORCEINLINE int32 AddUninitialized(int32 Count=1)
Definition: TArray.h:1051
FORCEINLINE ElementType * GetData() const
Definition: TArray.h:533
int32 Insert(std::initializer_list< ElementType > InitList, const int32 InIndex)
Definition: TArray.h:1129
FORCEINLINE uint32 GetAllocatedSize(void) const
Definition: TArray.h:554
FORCEINLINE int32 Add(ElementType &&Item)
Definition: TArray.h:1555
const EC_POINT BIGNUM * x
Definition: ec.h:545
@ IgnoreCase
Definition: FString.h:31
@ CaseSensitive
Definition: FString.h:28
@ FromEnd
Definition: FString.h:44
@ FromStart
Definition: FString.h:41
Definition: FString.h:1823
void FromString(int8 &OutValue, const TCHAR *Buffer)
Definition: FString.h:1837
TEnableIf< TIsCharType< CharType >::Value, FString >::Type ToString(const CharType *Ptr)
Definition: FString.h:1851
FString ToSanitizedString(const T &Value)
Definition: FString.h:1873
static TEnableIf< TIsArithmetic< T >::Value, bool >::Type TryParseString(T &OutValue, const TCHAR *Buffer)
Definition: FString.h:1882
bool MatchesWildcardRecursive(const TCHAR *Target, int32 TargetLength, const TCHAR *Wildcard, int32 WildcardLength)
Definition: FString.h:1933
std::string format(CStringRef format_str, ArgList args)
Definition: format.h:3443
static uint32 MemCrc32(const void *Data, int32 Lenght)
Definition: Crc.h:12
static CONSTEXPR FORCEINLINE T Max(const T A, const T B)
static TEnableIf< TAreEncodingsCompatible< SourceEncoding, DestEncoding >::Value, DestEncoding * >::Type Convert(DestEncoding *Dest, int32 DestSize, const SourceEncoding *Src, int32 SrcSize, DestEncoding BogusChar=(DestEncoding)'?')
static FORCEINLINE T Clamp(const T X, const T Min, const T Max)
static FORCEINLINE void * Memcpy(void *Dest, const void *Src, SIZE_T Count)
Definition: UnrealMemory.h:61
static FORCEINLINE int32 Stricmp(const ANSICHAR *String1, const ANSICHAR *String2)
static FORCEINLINE uint64 Strtoui64(const CharType *Start, CharType **End, int32 Base)
Definition: CString.h:743
static FORCEINLINE const CharType * Strstr(const CharType *String, const CharType *Find)
Definition: CString.h:584
static FORCEINLINE double Atod(const CharType *String)
Definition: CString.h:722
static FORCEINLINE int32 Stricmp(const CharType *String1, const CharType *String2)
Definition: CString.h:563
static FORCEINLINE int32 Strnicmp(const CharType *String1, const CharType *String2, SIZE_T Count)
Definition: CString.h:570
static FORCEINLINE float Atof(const CharType *String)
Definition: CString.h:715
static FORCEINLINE int32 Strlen(const CharType *String)
Definition: CString.h:577
static FORCEINLINE int32 Atoi(const CharType *String)
Definition: CString.h:701
static FORCEINLINE CharType * Strncpy(CharType *Dest, const CharType *Src, int32 MaxLen)
Definition: CString.h:527
static FORCEINLINE int32 Strncmp(const CharType *String1, const CharType *String2, SIZE_T Count)
Definition: CString.h:556
static FORCEINLINE int32 Strtoi(const CharType *Start, CharType **End, int32 Base)
Definition: CString.h:729
static bool IsNumeric(const CharType *Str)
Definition: CString.h:30
static const CharType * Stristr(const CharType *Str, const CharType *Find)
Definition: CString.h:485
static FORCEINLINE int64 Atoi64(const CharType *String)
Definition: CString.h:708
static FORCEINLINE int32 Strcmp(const CharType *String1, const CharType *String2)
Definition: CString.h:549
static CharType ToLower(CharType Char)
static bool IsWhitespace(CharType Char)
static CharType ToUpper(CharType Char)
static void FromString(T &Value, const TCHAR *Buffer)
Definition: FString.h:1907
static FString ToSanitizedString(const T &Value)
Definition: FString.h:1902
static FString ToString(const T &Value)
Definition: FString.h:1901
static FORCEINLINE bool Compare(TCHAR Lhs, TCHAR Rhs)
Definition: FString.h:1926
static FORCEINLINE bool Compare(TCHAR Lhs, TCHAR Rhs)
Definition: FString.h:1918