Converted over to new name sanitization routine

This commit is contained in:
2026-03-28 20:04:48 -04:00
parent 88fa260c9d
commit 22fe60f431
3 changed files with 53 additions and 64 deletions

View File

@@ -221,10 +221,10 @@ void WingTokenizer::PrintEverything() const
}
}
FString WingTokenizer::ExternalizeID(const FString &S)
FString WingTokenizer::ExternalizeID(const FString &InternalID)
{
TStringBuilder<512> Result;
for (TCHAR Ch : S)
for (TCHAR Ch : InternalID)
{
if (Ch == ' ') Result.AppendChar('.');
else if (WingCharacterClasses::GetCat(Ch) == Cat::Identifier) Result.AppendChar(Ch);
@@ -247,15 +247,26 @@ FString WingTokenizer::ExternalizeID(const FString &S)
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();
FString Result = TokenizeIdentifier(Input, Error);
FString InternalID = TokenizeIdentifier(Input, Error);
// If there's already an error, annotate with context
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();
}
// 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]);
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)
{
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)
{
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();
}
// One last error case: empty input
if (Result.IsEmpty())
if (InternalID.IsEmpty())
{
Error = TEXT("ERROR: Empty identifiers are not allowed");
return FString();
}
return Result;
return InternalID;
}
FString WingTokenizer::CheckInternalizeID(const FString &S)
FString WingTokenizer::CheckInternalizeID(const FString &ExternalID)
{
FString Error;
FString Result = TryInternalizeID(S, Error);
FString InternalID = TryInternalizeID(ExternalID, Error);
if (!Error.IsEmpty())
{
UWingServer::Printf(TEXT("%s\n"), *Error);
UWingServer::SuggestManual(WingManual::Section::IdentifierSanitization);
}
return Result;
return InternalID;
}

View File

@@ -4,6 +4,7 @@
#include "WingTypes.h"
#include "WingServer.h"
#include "WingHandler.h"
#include "WingTokenizer.h"
#include "Engine/Blueprint.h"
#include "Engine/MemberReference.h"
#include "Engine/World.h"
@@ -56,50 +57,31 @@
FString WingUtils::SanitizeName(const FString &InName)
{
FString Name = 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;
return WingTokenizer::ExternalizeID(InName);
}
FString WingUtils::UnsanitizeName(const FString &InName)
{
FString Name = InName;
int32 Dst = 0;
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 Error;
return WingTokenizer::TryInternalizeID(InName, Error);
}
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)
@@ -128,16 +110,7 @@ FString WingUtils::StandardizeMenuItem(const FString &Item)
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

View File

@@ -129,7 +129,12 @@ struct WingTokenizer
// Convert an internal ID into an external ID.
// Spaces are converted to periods. Any other
// 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.
// Periods are converted back to spaces. HTML escapes
@@ -137,13 +142,13 @@ struct WingTokenizer
// fail, for example, if the external name contains an
// invalid HTML escape. If it does, returns empty
// 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
// error, prints the error message, suggests the manual
// entry on identifier sanitization, and returns empty
// string.
static FString CheckInternalizeID(const FString &S);
static FString CheckInternalizeID(const FString &ExternalID);
// Print all tokens to the log for debugging.
void PrintEverything() const;