Files
UnrealEngine/Engine/Source/Programs/BuildPatchTool/Public/Interfaces/ToolMode.h
2025-05-18 13:04:45 +08:00

174 lines
5.2 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Interfaces/IBuildPatchServicesModule.h"
namespace BuildPatchTool
{
enum class EReturnCode : int32;
class IToolMode
{
public:
TCHAR const * const EqualsStr = TEXT("=");
TCHAR const * const QuoteStr = TEXT("\"");
public:
virtual EReturnCode Execute() = 0;
/**
* Helper for normalizing a URI referring to a file. We make sure not to cause issues with URIs that separate a protocol and authority with ://
* and windows UNC paths that begin with \\. Windows UNC paths still work in UE4 code with //.
*
* @param UriFile The file URI to be Normalized.
*/
void NormalizeUriFile(FString& UriFile)
{
// Replace all slashes.
UriFile.ReplaceInline(TEXT("\\"), TEXT("/"), ESearchCase::CaseSensitive);
}
/**
* Helper for normalizing a URI referring to a path. We make sure not to cause issues with URIs that separate a protocol and authority with ://
* and windows UNC paths that begin with \\. Windows UNC paths still work in UE4 code with //.
*
* @param UriPath The path URI to be Normalized.
*/
void NormalizeUriPath(FString& UriPath)
{
// Fix all slashes.
NormalizeUriFile(UriPath);
// Remove trailing slashes, unless it is for a windows based drive (e.g. "C:/")
int32 TrailingSlashIdx = UriPath.Len() - 1;
while (UriPath.EndsWith(TEXT("/"), ESearchCase::CaseSensitive) && !UriPath.EndsWith(TEXT(":/"), ESearchCase::CaseSensitive))
{
// Overwrite trailing slash with terminator, and trim size.
UriPath.GetCharArray()[TrailingSlashIdx--] = 0;
UriPath.GetCharArray().SetNum(UriPath.GetCharArray().Num() - 1, EAllowShrinking::No);
}
}
/**
* Helper for parsing a switch from an array of switches, usually produced using FCommandLine::Parse(..)
*
* @param InSwitch The switch name, ending with =. E.g. option=, foo=. It would usually be a compile time const.
* @param Value Receives the value from the switch.
* @param Switches The array of switches to search through.
* @return true if the switch was found.
*/
template <typename TValueType>
bool ParseSwitch(const TCHAR* InSwitch, TValueType& Value, const TArray<FString>& Switches)
{
// Debug check requirements for InSwitch
checkSlow(InSwitch != nullptr);
checkSlow(InSwitch[FCString::Strlen(InSwitch)-1] == TEXT('='));
for (const FString& Switch : Switches)
{
if (Switch.StartsWith(InSwitch))
{
FString StringValue;
Switch.Split(EqualsStr, nullptr, &StringValue);
return ParseValue(StringValue, Value);
}
}
return false;
}
/**
* Helper for parsing an array of multiple same name switches from the full array of switches, usually produced using FCommandLine::Parse(..)
*
* @param InSwitch The switch name, ending with =. E.g. option=, foo=. It would usually be a compile time const.
* @param Values Receives the values from the switches.
* @param Switches The array of switches to search through.
* @return true if at least one match was found.
*/
template <typename TValueType>
bool ParseSwitches(const TCHAR* InSwitch, TArray<TValueType>& Values, const TArray<FString>& Switches)
{
// Debug check requirements for InSwitch
checkSlow(InSwitch != nullptr);
checkSlow(InSwitch[FCString::Strlen(InSwitch)-1] == TEXT('='));
bool bFoundValue = false;
for (const FString& Switch : Switches)
{
if (Switch.StartsWith(InSwitch))
{
FString StringValue;
TValueType Value;
Switch.Split(EqualsStr, nullptr, &StringValue);
if (ParseValue(StringValue, Value))
{
Values.Emplace(MoveTemp(Value));
bFoundValue = true;
}
}
}
return bFoundValue;
}
bool ParseOption(const TCHAR* InSwitch, const TArray<FString>& Switches)
{
return Switches.Contains(InSwitch);
}
bool ParseValue(const FString& ValueIn, FString& ValueOut)
{
ValueOut = ValueIn.TrimQuotes();
return true;
}
bool ParseValue(const FString& ValueIn, uint64& ValueOut)
{
if (FCString::IsNumeric(*ValueIn) && !ValueIn.Contains(TEXT("-"), ESearchCase::CaseSensitive))
{
ValueOut = FCString::Strtoui64(*ValueIn, nullptr, 10);
return true;
}
return false;
}
bool ParseValue(const FString& ValueIn, uint32& ValueOut)
{
if (FCString::IsNumeric(*ValueIn) && !ValueIn.Contains(TEXT("-"), ESearchCase::CaseSensitive))
{
ValueOut = (uint32)FCString::Strtoi(*ValueIn, nullptr, 10);
return true;
}
return false;
}
template<typename ContainerType>
bool ParseValue(const FString& ValueIn, ContainerType& ValueOut)
{
TArray<FString> TempOut;
ValueOut.Empty();
FString CleanValueIn = ValueIn.TrimQuotes();
CleanValueIn.RemoveSpacesInline();
if (CleanValueIn.ParseIntoArray(TempOut, TEXT(","), false) != 0)
{
ValueOut.Append(MoveTemp(TempOut));
}
else
{
// Add a single empty element. This is what is intended if switch is present on the command
// line and contains no commas.
ValueOut.Add(TEXT(""));
}
return true;
}
};
typedef TSharedRef<IToolMode> IToolModeRef;
typedef TSharedPtr<IToolMode> IToolModePtr;
class FToolModeFactory
{
public:
static IToolModeRef Create(IBuildPatchServicesModule& BpsInterface);
};
}