Converted over to new name sanitization routine
This commit is contained in:
@@ -221,10 +221,10 @@ void WingTokenizer::PrintEverything() const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FString WingTokenizer::ExternalizeID(const FString &S)
|
FString WingTokenizer::ExternalizeID(const FString &InternalID)
|
||||||
{
|
{
|
||||||
TStringBuilder<512> Result;
|
TStringBuilder<512> Result;
|
||||||
for (TCHAR Ch : S)
|
for (TCHAR Ch : InternalID)
|
||||||
{
|
{
|
||||||
if (Ch == ' ') Result.AppendChar('.');
|
if (Ch == ' ') Result.AppendChar('.');
|
||||||
else if (WingCharacterClasses::GetCat(Ch) == Cat::Identifier) Result.AppendChar(Ch);
|
else if (WingCharacterClasses::GetCat(Ch) == Cat::Identifier) Result.AppendChar(Ch);
|
||||||
@@ -247,15 +247,26 @@ FString WingTokenizer::ExternalizeID(const FString &S)
|
|||||||
return Result.ToString();
|
return Result.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
FString WingTokenizer::TryInternalizeID(const FString &S, FString &Error)
|
bool WingTokenizer::WouldExternalizeReadably(const FString &InternalID)
|
||||||
{
|
{
|
||||||
FStringView Input(S);
|
if (InternalID.IsEmpty()) return false;
|
||||||
|
for (TCHAR Ch : InternalID)
|
||||||
|
{
|
||||||
|
if (Ch == ' ') continue;
|
||||||
|
if (WingCharacterClasses::GetCat(Ch) != Cat::Identifier) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
FString WingTokenizer::TryInternalizeID(const FString &ExternalID, FString &Error)
|
||||||
|
{
|
||||||
|
FStringView Input(ExternalID);
|
||||||
Error.Empty();
|
Error.Empty();
|
||||||
FString Result = TokenizeIdentifier(Input, Error);
|
FString InternalID = TokenizeIdentifier(Input, Error);
|
||||||
// If there's already an error, annotate with context
|
// If there's already an error, annotate with context
|
||||||
if (!Error.IsEmpty())
|
if (!Error.IsEmpty())
|
||||||
{
|
{
|
||||||
Error = FString::Printf(TEXT("ERROR parsing id %s: %s"), *S, *Error);
|
Error = FString::Printf(TEXT("ERROR parsing id %s: %s"), *ExternalID, *Error);
|
||||||
return FString();
|
return FString();
|
||||||
}
|
}
|
||||||
// If the identifier tokenizer stops before consuming the whole
|
// If the identifier tokenizer stops before consuming the whole
|
||||||
@@ -266,37 +277,37 @@ FString WingTokenizer::TryInternalizeID(const FString &S, FString &Error)
|
|||||||
Cat Category = WingCharacterClasses::GetCat(Input[0]);
|
Cat Category = WingCharacterClasses::GetCat(Input[0]);
|
||||||
if (Input[0] == ' ')
|
if (Input[0] == ' ')
|
||||||
{
|
{
|
||||||
Error = FString::Printf(TEXT("ERROR parsing id %s: in ids, spaces must be escaped"), *S);
|
Error = FString::Printf(TEXT("ERROR parsing id %s: in ids, spaces must be escaped"), *ExternalID);
|
||||||
}
|
}
|
||||||
else if (Category == Cat::Punctuation)
|
else if (Category == Cat::Punctuation)
|
||||||
{
|
{
|
||||||
Error = FString::Printf(TEXT("ERROR parsing id %s: in ids, these marks must be escaped: %s"),
|
Error = FString::Printf(TEXT("ERROR parsing id %s: in ids, these marks must be escaped: %s"),
|
||||||
*S, WingCharacterClasses::PunctuationString);
|
*ExternalID, WingCharacterClasses::PunctuationString);
|
||||||
}
|
}
|
||||||
else if (Category == Cat::Control)
|
else if (Category == Cat::Control)
|
||||||
{
|
{
|
||||||
Error = FString::Printf(TEXT("ERROR parsing id %s: in ids, control characters must be escaped"), *S);
|
Error = FString::Printf(TEXT("ERROR parsing id %s: in ids, control characters must be escaped"), *ExternalID);
|
||||||
}
|
}
|
||||||
else Error = FString::Printf(TEXT("ERROR parsing id %s: unparseable character in id"), *S);
|
else Error = FString::Printf(TEXT("ERROR parsing id %s: unparseable character in id"), *ExternalID);
|
||||||
return FString();
|
return FString();
|
||||||
}
|
}
|
||||||
// One last error case: empty input
|
// One last error case: empty input
|
||||||
if (Result.IsEmpty())
|
if (InternalID.IsEmpty())
|
||||||
{
|
{
|
||||||
Error = TEXT("ERROR: Empty identifiers are not allowed");
|
Error = TEXT("ERROR: Empty identifiers are not allowed");
|
||||||
return FString();
|
return FString();
|
||||||
}
|
}
|
||||||
return Result;
|
return InternalID;
|
||||||
}
|
}
|
||||||
|
|
||||||
FString WingTokenizer::CheckInternalizeID(const FString &S)
|
FString WingTokenizer::CheckInternalizeID(const FString &ExternalID)
|
||||||
{
|
{
|
||||||
FString Error;
|
FString Error;
|
||||||
FString Result = TryInternalizeID(S, Error);
|
FString InternalID = TryInternalizeID(ExternalID, Error);
|
||||||
if (!Error.IsEmpty())
|
if (!Error.IsEmpty())
|
||||||
{
|
{
|
||||||
UWingServer::Printf(TEXT("%s\n"), *Error);
|
UWingServer::Printf(TEXT("%s\n"), *Error);
|
||||||
UWingServer::SuggestManual(WingManual::Section::IdentifierSanitization);
|
UWingServer::SuggestManual(WingManual::Section::IdentifierSanitization);
|
||||||
}
|
}
|
||||||
return Result;
|
return InternalID;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include "WingTypes.h"
|
#include "WingTypes.h"
|
||||||
#include "WingServer.h"
|
#include "WingServer.h"
|
||||||
#include "WingHandler.h"
|
#include "WingHandler.h"
|
||||||
|
#include "WingTokenizer.h"
|
||||||
#include "Engine/Blueprint.h"
|
#include "Engine/Blueprint.h"
|
||||||
#include "Engine/MemberReference.h"
|
#include "Engine/MemberReference.h"
|
||||||
#include "Engine/World.h"
|
#include "Engine/World.h"
|
||||||
@@ -56,50 +57,31 @@
|
|||||||
|
|
||||||
FString WingUtils::SanitizeName(const FString &InName)
|
FString WingUtils::SanitizeName(const FString &InName)
|
||||||
{
|
{
|
||||||
FString Name = InName;
|
return WingTokenizer::ExternalizeID(InName);
|
||||||
int32 Dst = 0;
|
|
||||||
for (int32 Src = 0; Src < Name.Len(); Src++)
|
|
||||||
{
|
|
||||||
TCHAR c = Name[Src];
|
|
||||||
if (c < 0x20 || c == 0x7F) continue;
|
|
||||||
if (c == ' ') c=L'·';
|
|
||||||
if (c == '<') c=L'◁';
|
|
||||||
if (c == '>') c=L'▷';
|
|
||||||
if (c == '(') c=L'❨';
|
|
||||||
if (c == ')') c=L'❩';
|
|
||||||
if (c == '=') c=L'≡';
|
|
||||||
if (c == ',') c=L'▾';
|
|
||||||
Name[Dst++] = c;
|
|
||||||
}
|
|
||||||
if (Dst == 0) Name[Dst++] = L'·';
|
|
||||||
Name.LeftInline(Dst);
|
|
||||||
return Name;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FString WingUtils::UnsanitizeName(const FString &InName)
|
FString WingUtils::UnsanitizeName(const FString &InName)
|
||||||
{
|
{
|
||||||
FString Name = InName;
|
FString Error;
|
||||||
int32 Dst = 0;
|
return WingTokenizer::TryInternalizeID(InName, Error);
|
||||||
for (int32 Src = 0; Src < Name.Len(); Src++)
|
|
||||||
{
|
|
||||||
TCHAR c = Name[Src];
|
|
||||||
if (c < 0x20 || c == 0x7F) continue;
|
|
||||||
if (c == L'·') c=' ';
|
|
||||||
if (c == L'◁') c='<';
|
|
||||||
if (c == L'▷') c='>';
|
|
||||||
if (c == L'❨') c='(';
|
|
||||||
if (c == L'❩') c=')';
|
|
||||||
if (c == L'≡') c='=';
|
|
||||||
if (c == L'▾') c=',';
|
|
||||||
Name[Dst++] = c;
|
|
||||||
}
|
|
||||||
Name.LeftInline(Dst);
|
|
||||||
return Name;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FString WingUtils::SanitizeName(FName Name)
|
FString WingUtils::SanitizeName(FName Name)
|
||||||
{
|
{
|
||||||
return SanitizeName(Name.ToString());
|
return WingTokenizer::ExternalizeID(Name.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
FString WingUtils::CheckProposedName(const FString &ExternalID)
|
||||||
|
{
|
||||||
|
FString InternalID = WingTokenizer::CheckInternalizeID(ExternalID);
|
||||||
|
if (!InternalID.IsEmpty() && WingTokenizer::WouldExternalizeReadably(InternalID))
|
||||||
|
{
|
||||||
|
UWingServer::Printf(TEXT("ERROR: id %s would not be a readable id, may not create item with this name"),
|
||||||
|
*ExternalID);
|
||||||
|
UWingServer::SuggestManual(WingManual::Section::IdentifierSanitization);
|
||||||
|
return FString();
|
||||||
|
}
|
||||||
|
return InternalID;
|
||||||
}
|
}
|
||||||
|
|
||||||
FString WingUtils::StandardizeMenuItem(const FString &Item)
|
FString WingUtils::StandardizeMenuItem(const FString &Item)
|
||||||
@@ -128,16 +110,7 @@ FString WingUtils::StandardizeMenuItem(const FString &Item)
|
|||||||
return Sanitized;
|
return Sanitized;
|
||||||
}
|
}
|
||||||
|
|
||||||
FString WingUtils::CheckProposedName(const FString &Name)
|
|
||||||
{
|
|
||||||
FString Unsanitized = UnsanitizeName(Name);
|
|
||||||
if ((Unsanitized.IsEmpty()) || (SanitizeName(Unsanitized) != Name))
|
|
||||||
{
|
|
||||||
UWingServer::Printf(TEXT("Names must not contain control characters or be empty\n"));
|
|
||||||
return FString();
|
|
||||||
}
|
|
||||||
return Unsanitized;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================
|
// ============================================================
|
||||||
// Name Lookup
|
// Name Lookup
|
||||||
|
|||||||
@@ -129,7 +129,12 @@ struct WingTokenizer
|
|||||||
// Convert an internal ID into an external ID.
|
// Convert an internal ID into an external ID.
|
||||||
// Spaces are converted to periods. Any other
|
// Spaces are converted to periods. Any other
|
||||||
// non-identifier character is HTML escaped.
|
// non-identifier character is HTML escaped.
|
||||||
static FString ExternalizeID(const FString &S);
|
static FString ExternalizeID(const FString &InternalID);
|
||||||
|
|
||||||
|
// Return true if the internal ID would convert
|
||||||
|
// to a readable, easy-to-understand external ID without
|
||||||
|
// HTML escape sequences.
|
||||||
|
static bool WouldExternalizeReadably(const FString &InternalID);
|
||||||
|
|
||||||
// Convert an external ID into an internal ID.
|
// Convert an external ID into an internal ID.
|
||||||
// Periods are converted back to spaces. HTML escapes
|
// Periods are converted back to spaces. HTML escapes
|
||||||
@@ -137,13 +142,13 @@ struct WingTokenizer
|
|||||||
// fail, for example, if the external name contains an
|
// fail, for example, if the external name contains an
|
||||||
// invalid HTML escape. If it does, returns empty
|
// invalid HTML escape. If it does, returns empty
|
||||||
// string and sets the error message.
|
// string and sets the error message.
|
||||||
static FString TryInternalizeID(const FString &S, FString &Error);
|
static FString TryInternalizeID(const FString &ExternalID, FString &Error);
|
||||||
|
|
||||||
// Calls TryInternalizeName. If this generates an
|
// Calls TryInternalizeName. If this generates an
|
||||||
// error, prints the error message, suggests the manual
|
// error, prints the error message, suggests the manual
|
||||||
// entry on identifier sanitization, and returns empty
|
// entry on identifier sanitization, and returns empty
|
||||||
// string.
|
// string.
|
||||||
static FString CheckInternalizeID(const FString &S);
|
static FString CheckInternalizeID(const FString &ExternalID);
|
||||||
|
|
||||||
// Print all tokens to the log for debugging.
|
// Print all tokens to the log for debugging.
|
||||||
void PrintEverything() const;
|
void PrintEverything() const;
|
||||||
|
|||||||
Reference in New Issue
Block a user