Files
UnrealEngineUWP/Engine/Source/Runtime/SandboxFile/Public/IPlatformFileSandboxWrapper.h
Jaroslaw Palczynski ebce413232 UE4 Refactoring. Changed OVERRIDE and FINAL macros to keywords override and final.
[CL 2104397 by Jaroslaw Palczynski in Main branch]
2014-06-13 06:14:46 -04:00

493 lines
15 KiB
C++

// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.
#pragma once
/**
* Wrapper to log the low level file system
**/
DECLARE_LOG_CATEGORY_EXTERN(SandboxFile, Log, All);
class SANDBOXFILE_API FSandboxFileHandle : public IFileHandle
{
TAutoPtr<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;
/** Relative path to root directory. Cached for faster access */
FString RelativeRootDirectory;
/** Absolute path to root directory. Cached for faster access */
FString AbsoluteRootDirectory;
/** 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 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;
/** Returns sandbox directory */
const FString& GetSandboxDirectory() const
{
return SandboxDirectory;
}
/** Returns absolute game directory */
const FString& GetAbsoluteRootDirectory() const
{
return AbsoluteRootDirectory;
}
/**
* 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 IFileHandle* OpenRead(const TCHAR* Filename) override
{
IFileHandle* Result = LowerLevel->OpenRead( *ConvertToSandboxPath( Filename ) );
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 ) );
}
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 )
{
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.Replace( *SandboxFile.GetSandboxDirectory(), *SandboxFile.GetAbsoluteRootDirectory(), ESearchCase::IgnoreCase );
}
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;
}
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) 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 ) );
}
else
{
Result = LowerLevel->CopyFile( *ConvertToSandboxPath( To ), From );
}
return Result;
}
virtual FString ConvertToAbsolutePathForExternalAppForRead( const TCHAR* Filename ) override;
virtual FString ConvertToAbsolutePathForExternalAppForWrite( const TCHAR* Filename ) override;
};