Files
UnrealEngineUWP/Engine/Source/Runtime/SandboxFile/Public/IPlatformFileSandboxWrapper.h
Robert Manuszewski 301e5763c2 Copying //UE4/Dev-Core to //UE4/Dev-Main (Source: //UE4/Dev-Core @ 3228803)
#lockdown Nick.Penwarden
#rb none

==========================
MAJOR FEATURES + CHANGES
==========================

Change 3209807 on 2016/11/24 by Chris.Wood

	CRP now has improved handling of lost comms with website/DB (CRP v.1.2.9)
	[UE-38397] - CrashReportProcess should not lose crashes when the website goes down.

Change 3209936 on 2016/11/24 by Steven.Hutton

	Reconciled offline work. Fixed a number of display bugs with the reports page.

Change 3209938 on 2016/11/24 by Steven.Hutton

	Reconciled offline work

	Adding JQuery UI packages

Change 3210736 on 2016/11/28 by Steve.Robb

	Unset() made protected, which is an implementation details of TFunction and not the way to unbind one (may leak memory).
	Fixes to existing calls.

	https://answers.unrealengine.com/questions/494947/proper-way-to-deal-with-destroying-a-tfunction.html

Change 3211181 on 2016/11/28 by Steve.Robb

	Improved error message when binding a delegate to a pending kill object.

	#jira UE-5232

Change 3211214 on 2016/11/28 by Steve.Robb

	PR #2978: fixed typo in FMallocLeakDetection (Contributed by finap)

	#jira UE-39049

Change 3211301 on 2016/11/28 by Steve.Robb

	PR #2892: Copy bCustomVersionsAreReset when creating an Archive from another Ar. (Contributed by surakin)

	#jira UE-37941

Change 3213387 on 2016/11/29 by Steven.Hutton

	Test of a release note parsed from the changelist

Change 3213553 on 2016/11/29 by Gil.Gribb

	UE4 - Rework dependencies and UStruct creation so that we can create UBlueprintGeneratedClass's without needing the parent class serialized.

Change 3214800 on 2016/11/30 by Robert.Manuszewski

	ModuleManager will now use a critical section instead of FMultiReaderSingleWriterGT to make it really thread safe.

	- removed FMultiReaderSingleWriterGT because it was not fully thread safe

Change 3214926 on 2016/11/30 by Robert.Manuszewski

	Merging using Dev-Core_To_Dev-LoadTimes (reversed)

Change 3214981 on 2016/11/30 by Gil.Gribb

	UE4 - Make sure that subobjects of CDOs are exported even if they don't have any direct references; they might be archetypes.

Change 3215392 on 2016/11/30 by Steve.Robb

	Error out on editor builds when reading a non-boolean value in an archive.

Change 3215674 on 2016/11/30 by Steve.Robb

	Replacement of a custom scope-exit setup with our standard macro.

Change 3215720 on 2016/11/30 by Steve.Robb

	Default constructor for TTuple which value-initializes the elements.

Change 3216777 on 2016/12/01 by Graeme.Thornton

	Add NoRedist and NotForLicensees folders in the game folder to the C# version of config file hierarchy.

Change 3216858 on 2016/12/01 by Graeme.Thornton

	Improvements to pak signing and encryption
	 - Remove compile time defines for encryption key and signing keys
	 - Embed keys in executable by including in the UBT generated UELinkerFixups.cpp file
	 - Add key access core delegate for passing these keys through to pak platform file

Change 3216860 on 2016/12/01 by Graeme.Thornton

	Re-enable pak signing and encryption in ShooterGame

Change 3216861 on 2016/12/01 by Graeme.Thornton

	Re-enable pak signing and encryption in Paragon

Change 3217076 on 2016/12/01 by Gil.Gribb

	UE4 - replaced !GIsIntialLoad with EVENT_DRIVEN_ASYNC_LOAD_ACTIVE_AT_RUNTIME as a first step toward boot time EDL

Change 3221139 on 2016/12/05 by Ben.Woodhouse

	Dummy integrate of CL 3221131 (versioning workarounds) from Dev-LoadTimes4.14 with accept target to prevent those workarounds being merged out of dev-loadtimes4.14.

	Command:
	p4 integrate //UE4/Dev-LoadTimes4.14/...@3221131,3221131

	w/ resolve/accept-target

Change 3221410 on 2016/12/05 by Steve.Robb

	Allow Algo::IsSorted to work on C arrays and initializer_lists.

Change 3221673 on 2016/12/05 by Gil.Gribb

	set up an intentional merge conflict so we can do the right thing when dev-BP and dev-core come together

Change 3223182 on 2016/12/06 by Chris.Wood

	Add EngineModeEx to CrashReportCommon
	[UE-39258] - Update CrashReporter to include whether Engine crashes are from vanilla build or not

Change 3224646 on 2016/12/07 by Robert.Manuszewski

	It's no longer necessary to rebuild the cooked exe to enable the event driven loader. EDL and the new async IO are now controlled with ini settings only.

Change 3224647 on 2016/12/07 by Robert.Manuszewski

	Event Driven Loader is now enabled by default.

Change 3224669 on 2016/12/07 by Chris.Wood

	Compressing some crash files output from CRP to S3 (CRP v1.2.11)
	[UE-37564] - Add compression support for CRP crash files in S3

	Add EngineModeEx to support to CRP (CRP v1.2.10)
	[UE-39258] - Update CrashReporter to include whether Engine crashes are from vanilla build or not

Change 3224873 on 2016/12/07 by Robert.Manuszewski

	A few fixes to the EDL macro refactor.

Change 3224933 on 2016/12/07 by Robert.Manuszewski

	Async Loading settings will now be logged on startup in cooked games

Change 3224984 on 2016/12/07 by Robert.Manuszewski

	Small fix to EDL and new async IO global var init.

Change 3225027 on 2016/12/07 by Robert.Manuszewski

	Re-enabling EDL in ShooterGame since it no longer requires the cooked exe to be re-compiled (and EDL is on by default anyway).

Change 3226702 on 2016/12/08 by Steve.Robb

	UHT can now skip over macro-like identifiers while parsing.
	Correctly handles FTypefaceEntry::Name parsing, which was broken by the workaround in CL# 3219332.
	Syntax workaround reverted in FTypefaceEntry.

	#jira UE-38231

Change 3226756 on 2016/12/08 by Steve.Robb

	LexicalConversion renamed to Lex after #core discussion.
	Lex::ToString overloads added for FString itself.

Change 3226766 on 2016/12/08 by Steve.Robb

	FCookStatsManager::ToString replaced with Lex::ToString, as it now supports the required functionality.

Change 3226949 on 2016/12/08 by Robert.Manuszewski

	Fixing static analysis warnings

Change 3228566 on 2016/12/09 by Robert.Manuszewski

	Making UBT not think it needs to use separate temporary target for non source code projects when EDL settings don't match default.

Change 3228601 on 2016/12/09 by Steve.Robb

	Fix for TSparseArray visualization of types smaller than 8 bytes.

Change 3228654 on 2016/12/09 by Gil.Gribb

	UE4 - Fix very old bug with lock free lists, probably not relevant to anything we currently use.

Change 3228697 on 2016/12/09 by Graeme.Thornton

	Rebuilt UnrealPak

[CL 3228932 by Robert Manuszewski in Main branch]
2016-12-09 11:36:14 -05:00

639 lines
20 KiB
C++

// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "GenericPlatform/GenericPlatformFile.h"
#include "Templates/ScopedPointer.h"
#include "Misc/Paths.h"
#include "UniquePtr.h"
class IAsyncReadFileHandle;
/**
* Wrapper to log the low level file system
**/
DECLARE_LOG_CATEGORY_EXTERN(SandboxFile, Log, All);
class SANDBOXFILE_API FSandboxFileHandle : public IFileHandle
{
TUniquePtr<IFileHandle> FileHandle;
FString Filename;
public:
FSandboxFileHandle(IFileHandle* InFileHandle, const TCHAR* InFilename)
: FileHandle(InFileHandle)
, Filename(InFilename)
{
}
virtual ~FSandboxFileHandle()
{
}
virtual int64 Tell() override
{
return FileHandle->Tell();
}
virtual bool Seek(int64 NewPosition) override
{
return FileHandle->Seek(NewPosition);
}
virtual bool SeekFromEnd(int64 NewPositionRelativeToEnd) override
{
return FileHandle->SeekFromEnd(NewPositionRelativeToEnd);
}
virtual bool Read(uint8* Destination, int64 BytesToRead) override
{
return FileHandle->Read(Destination, BytesToRead);
}
virtual bool Write(const uint8* Source, int64 BytesToWrite) override
{
return FileHandle->Write(Source, BytesToWrite);
}
virtual int64 Size() override
{
return FileHandle->Size();
}
};
class SANDBOXFILE_API FSandboxPlatformFile : public IPlatformFile
{
/** Wrapped file */
IPlatformFile* LowerLevel;
/** Absolute path to the sandbox directory */
FString SandboxDirectory;
/** Name of the game's sandbox directory */
FString GameSandboxDirectoryName;
/** Relative path to root directory. Cached for faster access */
FString RelativeRootDirectory;
/** Absolute path to root directory. Cached for faster access */
FString AbsoluteRootDirectory;
/** Absolute game directory. Cached for faster access */
FString AbsoluteGameDirectory;
/** Absolute path to game directory. Cached for faster access */
FString AbsolutePathToGameDirectory;
/** Access to any file (in unreal standard form) matching this is not allowed */
TArray<FString> FileExclusionWildcards;
/** Access to any directory (in unreal standard form) matching this is not allowed */
TArray<FString> DirectoryExclusionWildcards;
bool bEntireEngineWillUseThisSandbox;
/**
* Whether the sandbox is enabled or not.
* Defaults to true.
* Set to false when operations require writing to the actual physical location given.
*/
bool bSandboxEnabled;
/**
* Clears the contents of the specified folder
*
* @param AbsolutePath Absolute path to the folder to wipe
* @return true if the folder's contents could be deleted, false otherwise
*/
bool WipeSandboxFolder( const TCHAR* AbsolutePath );
/**
* Finds all files or folders in the given directory.
* This is partially copied from file manager but since IPlatformFile is lower level
* it's better to have local version which doesn't use the wrapped IPlatformFile.
*
* @param Result List of found files or folders.
* @param InFilename Path to the folder to look in.
* @param Files true to include files in the Result
* @param Files true to include directories in the Result
*/
void FindFiles( TArray<FString>& Result, const TCHAR* InFilename, bool Files, bool Directories );
/**
* Deletes a directory
* This is partially copied from file manager but since IPlatformFile is lower level
* it's better to have local version which doesn't use the wrapped IPlatformFile.
*
* @param Path Path to the directory to delete.
* @param Tree true to recursively delete the directory and its contents
* @return true if the operaton was successful.
*/
bool DeleteDirectory( const TCHAR* Path, bool Tree );
/**
* Check if a file or directory has been filtered, and hence is unavailable to the outside world
*
* @param FilenameOrDirectoryName
* @param bIsDirectory if true, this is a directory
* @return true if it is ok to access the non-sandboxed files here
*/
bool OkForInnerAccess(const TCHAR* InFilenameOrDirectoryName, bool bIsDirectory = false) const
{
if (DirectoryExclusionWildcards.Num() || FileExclusionWildcards.Num())
{
FString FilenameOrDirectoryName(InFilenameOrDirectoryName);
FPaths::MakeStandardFilename(FilenameOrDirectoryName);
if (bIsDirectory)
{
for (int32 Index = 0; Index < DirectoryExclusionWildcards.Num(); Index++)
{
if (FilenameOrDirectoryName.MatchesWildcard(DirectoryExclusionWildcards[Index]))
{
return false;
}
}
}
else
{
for (int32 Index = 0; Index < FileExclusionWildcards.Num(); Index++)
{
if (FilenameOrDirectoryName.MatchesWildcard(FileExclusionWildcards[Index]))
{
return false;
}
}
}
}
return true;
}
public:
static const TCHAR* GetTypeName()
{
return TEXT("SandboxFile");
}
/**
* Converts passed in filename to use a sandbox path.
* @param InLowerLevel File system to use for actual disk access
* @param InSandboxDirectory Directory to use for the sandbox, reads are tried here first and all deletes and writes go here
* @param bEntireEngineWillUseThisSandbox If true, the we set up the engine so that subprocesses also use this subdirectory
*/
FSandboxPlatformFile(bool bInEntireEngineWillUseThisSandbox = false);
virtual ~FSandboxPlatformFile()
{
}
/**
* Set whether the sandbox is enabled or not
*
* @param bInEnabled true to enable the sandbox, false to disable it
*/
virtual void SetSandboxEnabled(bool bInEnabled) override
{
bSandboxEnabled = bInEnabled;
}
/**
* Returns whether the sandbox is enabled or not
*
* @return bool true if enabled, false if not
*/
virtual bool IsSandboxEnabled() const override
{
return bSandboxEnabled;
}
virtual bool ShouldBeUsed(IPlatformFile* Inner, const TCHAR* CmdLine) const override;
virtual bool Initialize(IPlatformFile* Inner, const TCHAR* CmdLine) override;
virtual IPlatformFile* GetLowerLevel() override
{
return LowerLevel;
}
virtual void SetLowerLevel(IPlatformFile* NewLowerLevel) override
{
LowerLevel = NewLowerLevel;
}
virtual const TCHAR* GetName() const override
{
return FSandboxPlatformFile::GetTypeName();
}
/**
* Converts passed in filename to use a sandbox path.
*
* @param Filename filename (under game directory) to convert to use a sandbox path. Can be relative or absolute.
*
* @return filename using sandbox path
*/
FString ConvertToSandboxPath( const TCHAR* Filename ) const;
FString ConvertFromSandboxPath(const TCHAR* Filename) const;
/** Returns sandbox directory */
const FString& GetSandboxDirectory() const
{
return SandboxDirectory;
}
/** Returns the name of the sandbox directory for the game's content */
const FString& GetGameSandboxDirectoryName();
/** Returns absolute root directory */
const FString& GetAbsoluteRootDirectory() const
{
return AbsoluteRootDirectory;
}
/** Returns absolute game directory */
const FString& GetAbsoluteGameDirectory();
/** Returns absolute path to game directory (without the game directory itself) */
const FString& GetAbsolutePathToGameDirectory();
/**
* Add exclusion. These files and / or directories pretend not to exist so that they cannot be accessed at all (except in the sandbox)
* @param Wildcard FString::MatchesWildcard-type wild card to test for exclusion
* @param bIsDirectory if true, this is a directory
* @Caution, these have a performance cost
*/
void AddExclusion(const TCHAR* Wildcard, bool bIsDirectory = false)
{
if (bIsDirectory)
{
DirectoryExclusionWildcards.AddUnique(FString(Wildcard));
}
else
{
FileExclusionWildcards.AddUnique(FString(Wildcard));
}
}
// IPlatformFile Interface
virtual bool FileExists(const TCHAR* Filename) override
{
// First look for the file in the user dir.
bool Result = LowerLevel->FileExists( *ConvertToSandboxPath( Filename ) );
if( Result == false && OkForInnerAccess(Filename))
{
Result = LowerLevel->FileExists( Filename );
}
return Result;
}
virtual int64 FileSize(const TCHAR* Filename) override
{
// First look for the file in the user dir.
int64 Result = LowerLevel->FileSize( *ConvertToSandboxPath( Filename ) );
if( Result < 0 && OkForInnerAccess(Filename))
{
Result = LowerLevel->FileSize( Filename );
}
return Result;
}
virtual bool DeleteFile(const TCHAR* Filename) override
{
// Delete only sandbox files. If the sendbox version doesn't exists
// assume the delete was successful because we only care if the sandbox version is gone.
bool Result = true;
FString SandboxFilename( *ConvertToSandboxPath( Filename ) );
if( LowerLevel->FileExists( *SandboxFilename ) )
{
Result = LowerLevel->DeleteFile( *ConvertToSandboxPath( Filename ) );
}
return Result;
}
virtual bool IsReadOnly(const TCHAR* Filename) override
{
// If the file exists in the sandbox folder and is read-only return true
// Otherwise it can always be 'overwritten' in the sandbox
bool Result = false;
FString SandboxFilename( *ConvertToSandboxPath( Filename ) );
if( LowerLevel->FileExists( *SandboxFilename ) )
{
// If the file exists in sandbox dir check its read-only flag
Result = LowerLevel->IsReadOnly( *SandboxFilename );
}
//else
//{
// // Fall back to normal directory
// Result = LowerLevel->IsReadOnly( Filename );
//}
return Result;
}
virtual bool MoveFile(const TCHAR* To, const TCHAR* From) override
{
// Only files within the sandbox dir can be moved
bool Result = false;
FString SandboxFilename( *ConvertToSandboxPath( From ) );
if( LowerLevel->FileExists( *SandboxFilename ) )
{
Result = LowerLevel->MoveFile( *ConvertToSandboxPath( To ), *SandboxFilename );
}
return Result;
}
virtual bool SetReadOnly(const TCHAR* Filename, bool bNewReadOnlyValue) override
{
bool Result = false;
FString UserFilename( *ConvertToSandboxPath( Filename ) );
if( LowerLevel->FileExists( *UserFilename ) )
{
Result = LowerLevel->SetReadOnly( *UserFilename, bNewReadOnlyValue );
}
return Result;
}
virtual FDateTime GetTimeStamp(const TCHAR* Filename) override
{
FDateTime Result = FDateTime::MinValue();
FString UserFilename( *ConvertToSandboxPath( Filename ) );
if( LowerLevel->FileExists( *UserFilename ) )
{
Result = LowerLevel->GetTimeStamp( *UserFilename );
}
else if (OkForInnerAccess(Filename))
{
Result = LowerLevel->GetTimeStamp( Filename );
}
return Result;
}
virtual void SetTimeStamp(const TCHAR* Filename, FDateTime DateTime) override
{
FString UserFilename( *ConvertToSandboxPath( Filename ) );
if( LowerLevel->FileExists( *UserFilename ) )
{
LowerLevel->SetTimeStamp( *UserFilename, DateTime );
}
else if (OkForInnerAccess(Filename))
{
LowerLevel->SetTimeStamp( Filename, DateTime );
}
}
virtual FDateTime GetAccessTimeStamp(const TCHAR* Filename) override
{
FDateTime Result = FDateTime::MinValue();
FString UserFilename( *ConvertToSandboxPath( Filename ) );
if( LowerLevel->FileExists( *UserFilename ) )
{
Result = LowerLevel->GetAccessTimeStamp( *UserFilename );
}
else if (OkForInnerAccess(Filename))
{
Result = LowerLevel->GetAccessTimeStamp( Filename );
}
return Result;
}
virtual FString GetFilenameOnDisk(const TCHAR* Filename) override
{
FString Result;
FString UserFilename(*ConvertToSandboxPath(Filename));
if (LowerLevel->FileExists(*UserFilename))
{
Result = LowerLevel->GetFilenameOnDisk(*UserFilename);
}
else if (OkForInnerAccess(Filename))
{
Result = LowerLevel->GetFilenameOnDisk(Filename);
}
return Result;
}
virtual IFileHandle* OpenRead(const TCHAR* Filename, bool bAllowWrite = false) override
{
IFileHandle* Result = LowerLevel->OpenRead( *ConvertToSandboxPath(Filename), bAllowWrite );
if( !Result && OkForInnerAccess(Filename) )
{
Result = LowerLevel->OpenRead( Filename );
}
return Result;
}
virtual IFileHandle* OpenWrite(const TCHAR* Filename, bool bAppend = false, bool bAllowRead = false) override
{
// Only files from the sandbox directory can be opened for wiriting
return LowerLevel->OpenWrite( *ConvertToSandboxPath( Filename ), bAppend, bAllowRead );
}
virtual bool DirectoryExists(const TCHAR* Directory) override
{
bool Result = LowerLevel->DirectoryExists( *ConvertToSandboxPath( Directory ) );
if( Result == false && OkForInnerAccess(Directory, true) )
{
Result = LowerLevel->DirectoryExists( Directory );
}
return Result;
}
virtual bool CreateDirectory(const TCHAR* Directory) override
{
// Directories can be created only under the sandbox path
return LowerLevel->CreateDirectory( *ConvertToSandboxPath( Directory ) );
}
virtual bool DeleteDirectory(const TCHAR* Directory) override
{
// Directories can be deleted only under the sandbox path
return LowerLevel->DeleteDirectory( *ConvertToSandboxPath( Directory ) );
}
virtual FFileStatData GetStatData(const TCHAR* FilenameOrDirectory) override
{
FFileStatData Result = LowerLevel->GetStatData( *ConvertToSandboxPath( FilenameOrDirectory ) );
if (!Result.bIsValid && (OkForInnerAccess(FilenameOrDirectory, false) && OkForInnerAccess(FilenameOrDirectory, true)))
{
Result = LowerLevel->GetStatData( FilenameOrDirectory );
}
return Result;
}
class FSandboxVisitor : public IPlatformFile::FDirectoryVisitor
{
public:
FDirectoryVisitor& Visitor;
FSandboxPlatformFile& SandboxFile;
TSet<FString> VisitedSandboxFiles;
FSandboxVisitor( FDirectoryVisitor& InVisitor, FSandboxPlatformFile& InSandboxFile )
: Visitor( InVisitor )
, SandboxFile( InSandboxFile )
{
}
virtual bool Visit( const TCHAR* FilenameOrDirectory, bool bIsDirectory ) override
{
bool CanVisit = true;
FString LocalFilename( FilenameOrDirectory );
if( FCString::Strnicmp( *LocalFilename, *SandboxFile.GetSandboxDirectory(), SandboxFile.GetSandboxDirectory().Len() ) == 0 )
{
// FilenameOrDirectory is already pointing to the sandbox directory so add it to the list of sanbox files.
// The filename is always stored with the abslute sandbox path.
VisitedSandboxFiles.Add( *LocalFilename );
// Now convert the sandbox path back to engine path because the sandbox folder should not be exposed
// to the engine and remain transparent.
LocalFilename = LocalFilename.Mid(SandboxFile.GetSandboxDirectory().Len());
if (LocalFilename.StartsWith(TEXT("Engine/")))
{
LocalFilename = SandboxFile.GetAbsoluteRootDirectory() / LocalFilename;
}
else
{
LocalFilename = LocalFilename.Mid(SandboxFile.GetGameSandboxDirectoryName().Len());
LocalFilename = SandboxFile.GetAbsoluteGameDirectory() / LocalFilename;
}
}
else
{
// Favourize Sandbox files over normal path files.
CanVisit = !VisitedSandboxFiles.Contains( SandboxFile.ConvertToSandboxPath(*LocalFilename ) )
&& SandboxFile.OkForInnerAccess(*LocalFilename, bIsDirectory);
}
if( CanVisit )
{
bool Result = Visitor.Visit( *LocalFilename, bIsDirectory );
return Result;
}
else
{
// Continue iterating.
return true;
}
}
};
virtual bool IterateDirectory(const TCHAR* Directory, IPlatformFile::FDirectoryVisitor& Visitor) override
{
FSandboxVisitor SandboxVisitor( Visitor, *this );
bool Result = false;
LowerLevel->IterateDirectory( *ConvertToSandboxPath( Directory ), SandboxVisitor );
Result = LowerLevel->IterateDirectory( Directory, SandboxVisitor );
return Result;
}
virtual bool IterateDirectoryRecursively(const TCHAR* Directory, IPlatformFile::FDirectoryVisitor& Visitor) override
{
FSandboxVisitor SandboxVisitor( Visitor, *this );
bool Result = false;
LowerLevel->IterateDirectoryRecursively( *ConvertToSandboxPath( Directory ), SandboxVisitor );
Result = LowerLevel->IterateDirectoryRecursively( Directory, SandboxVisitor );
return Result;
}
class FSandboxStatVisitor : public IPlatformFile::FDirectoryStatVisitor
{
public:
FDirectoryStatVisitor& Visitor;
FSandboxPlatformFile& SandboxFile;
TSet<FString> VisitedSandboxFiles;
FSandboxStatVisitor( FDirectoryStatVisitor& InVisitor, FSandboxPlatformFile& InSandboxFile )
: Visitor( InVisitor )
, SandboxFile( InSandboxFile )
{
}
virtual bool Visit( const TCHAR* FilenameOrDirectory, const FFileStatData& StatData ) override
{
bool CanVisit = true;
FString LocalFilename( FilenameOrDirectory );
if( FCString::Strnicmp( *LocalFilename, *SandboxFile.GetSandboxDirectory(), SandboxFile.GetSandboxDirectory().Len() ) == 0 )
{
// FilenameOrDirectory is already pointing to the sandbox directory so add it to the list of sanbox files.
// The filename is always stored with the abslute sandbox path.
VisitedSandboxFiles.Add( *LocalFilename );
// Now convert the sandbox path back to engine path because the sandbox folder should not be exposed
// to the engine and remain transparent.
LocalFilename = LocalFilename.Mid(SandboxFile.GetSandboxDirectory().Len());
if (LocalFilename.StartsWith(TEXT("Engine/")))
{
LocalFilename = SandboxFile.GetAbsoluteRootDirectory() / LocalFilename;
}
else
{
LocalFilename = SandboxFile.GetAbsolutePathToGameDirectory() / LocalFilename;
}
}
else
{
// Favourize Sandbox files over normal path files.
CanVisit = !VisitedSandboxFiles.Contains( SandboxFile.ConvertToSandboxPath(*LocalFilename ) )
&& SandboxFile.OkForInnerAccess(*LocalFilename, StatData.bIsDirectory);
}
if( CanVisit )
{
bool Result = Visitor.Visit( *LocalFilename, StatData );
return Result;
}
else
{
// Continue iterating.
return true;
}
}
};
virtual bool IterateDirectoryStat(const TCHAR* Directory, IPlatformFile::FDirectoryStatVisitor& Visitor) override
{
FSandboxStatVisitor SandboxVisitor( Visitor, *this );
bool Result = false;
LowerLevel->IterateDirectoryStat( *ConvertToSandboxPath( Directory ), SandboxVisitor );
Result = LowerLevel->IterateDirectoryStat( Directory, SandboxVisitor );
return Result;
}
virtual bool IterateDirectoryStatRecursively(const TCHAR* Directory, IPlatformFile::FDirectoryStatVisitor& Visitor) override
{
FSandboxStatVisitor SandboxVisitor( Visitor, *this );
bool Result = false;
LowerLevel->IterateDirectoryStatRecursively( *ConvertToSandboxPath( Directory ), SandboxVisitor );
Result = LowerLevel->IterateDirectoryStatRecursively( Directory, SandboxVisitor );
return Result;
}
virtual bool DeleteDirectoryRecursively(const TCHAR* Directory) override
{
// Directories can be deleted only under the sandbox path
return LowerLevel->DeleteDirectoryRecursively( *ConvertToSandboxPath( Directory ) );
}
virtual bool CreateDirectoryTree(const TCHAR* Directory) override
{
// Directories can only be created only under the sandbox path
return LowerLevel->CreateDirectoryTree( *ConvertToSandboxPath( Directory ) );
}
virtual bool CopyFile(const TCHAR* To, const TCHAR* From, EPlatformFileRead ReadFlags = EPlatformFileRead::None, EPlatformFileWrite WriteFlags = EPlatformFileWrite::None) override
{
// Files can be copied only to the sandbox directory
bool Result = false;
if( LowerLevel->FileExists( *ConvertToSandboxPath( From ) ) )
{
Result = LowerLevel->CopyFile( *ConvertToSandboxPath( To ), *ConvertToSandboxPath( From ), ReadFlags, WriteFlags);
}
else
{
Result = LowerLevel->CopyFile( *ConvertToSandboxPath( To ), From, ReadFlags, WriteFlags);
}
return Result;
}
virtual FString ConvertToAbsolutePathForExternalAppForRead( const TCHAR* Filename ) override;
virtual FString ConvertToAbsolutePathForExternalAppForWrite( const TCHAR* Filename ) override;
virtual IAsyncReadFileHandle* OpenAsyncRead(const TCHAR* Filename) override
{
FString UserFilename(*ConvertToSandboxPath(Filename));
if (!OkForInnerAccess(Filename) || LowerLevel->FileExists(*UserFilename))
{
return LowerLevel->OpenAsyncRead(*UserFilename);
}
return LowerLevel->OpenAsyncRead(Filename);
}
};