@ -10,13 +10,13 @@
# ifdef _WIN32
# ifdef _WIN32
# include <windows.h>
# include <windows.h>
# include <shlobj.h> // for SHGetFolderPath
// windows.h needs to be included before other windows headers
# include <shellapi.h>
# include <commdlg.h> // for GetSaveFileName
# include <commdlg.h> // for GetSaveFileName
# include <io.h>
# include <direct.h> // getcwd
# include <direct.h> // getcwd
# include <io.h>
# include <shellapi.h>
# include <shlobj.h> // for SHGetFolderPath
# include <tchar.h>
# include <tchar.h>
# include "common/string_util.h"
# include "common/string_util.h"
// 64 bit offsets for windows
// 64 bit offsets for windows
@ -40,9 +40,9 @@
# endif
# endif
# if defined(__APPLE__)
# if defined(__APPLE__)
# include <CoreFoundation/CFBundle.h>
# include <CoreFoundation/CFString.h>
# include <CoreFoundation/CFString.h>
# include <CoreFoundation/CFURL.h>
# include <CoreFoundation/CFURL.h>
# include <CoreFoundation/CFBundle.h>
# endif
# endif
# include <algorithm>
# include <algorithm>
@ -60,15 +60,12 @@
// This namespace has various generic functions related to files and paths.
// This namespace has various generic functions related to files and paths.
// The code still needs a ton of cleanup.
// The code still needs a ton of cleanup.
// REMEMBER: strdup considered harmful!
// REMEMBER: strdup considered harmful!
namespace FileUtil
namespace FileUtil {
{
// Remove any ending forward slashes from directory paths
// Remove any ending forward slashes from directory paths
// Modifies argument.
// Modifies argument.
static void StripTailDirSlashes ( std : : string & fname )
static void StripTailDirSlashes ( std : : string & fname ) {
{
if ( fname . length ( ) > 1 ) {
if ( fname . length ( ) > 1 )
{
size_t i = fname . length ( ) ;
size_t i = fname . length ( ) ;
while ( i > 0 & & fname [ i - 1 ] = = DIR_SEP_CHR )
while ( i > 0 & & fname [ i - 1 ] = = DIR_SEP_CHR )
- - i ;
- - i ;
@ -78,8 +75,7 @@ static void StripTailDirSlashes(std::string &fname)
}
}
// Returns true if file filename exists
// Returns true if file filename exists
bool Exists ( const std : : string & filename )
bool Exists ( const std : : string & filename ) {
{
struct stat64 file_info ;
struct stat64 file_info ;
std : : string copy ( filename ) ;
std : : string copy ( filename ) ;
@ -99,8 +95,7 @@ bool Exists(const std::string &filename)
}
}
// Returns true if filename is a directory
// Returns true if filename is a directory
bool IsDirectory ( const std : : string & filename )
bool IsDirectory ( const std : : string & filename ) {
{
struct stat64 file_info ;
struct stat64 file_info ;
std : : string copy ( filename ) ;
std : : string copy ( filename ) ;
@ -117,8 +112,8 @@ bool IsDirectory(const std::string &filename)
# endif
# endif
if ( result < 0 ) {
if ( result < 0 ) {
LOG_WARNING ( Common_Filesystem , " stat failed on %s: %s " ,
LOG_WARNING ( Common_Filesystem , " stat failed on %s: %s " , filename . c_str ( ) ,
filename . c_str ( ) , GetLastErrorMsg ( ) ) ;
GetLastErrorMsg ( ) ) ;
return false ;
return false ;
}
}
@ -127,36 +122,32 @@ bool IsDirectory(const std::string &filename)
// Deletes a given filename, return true on success
// Deletes a given filename, return true on success
// Doesn't supports deleting a directory
// Doesn't supports deleting a directory
bool Delete ( const std : : string & filename )
bool Delete ( const std : : string & filename ) {
{
LOG_INFO ( Common_Filesystem , " file %s " , filename . c_str ( ) ) ;
LOG_INFO ( Common_Filesystem , " file %s " , filename . c_str ( ) ) ;
// Return true because we care about the file no
// Return true because we care about the file no
// being there, not the actual delete.
// being there, not the actual delete.
if ( ! Exists ( filename ) )
if ( ! Exists ( filename ) ) {
{
LOG_WARNING ( Common_Filesystem , " %s does not exist " , filename . c_str ( ) ) ;
LOG_WARNING ( Common_Filesystem , " %s does not exist " , filename . c_str ( ) ) ;
return true ;
return true ;
}
}
// We can't delete a directory
// We can't delete a directory
if ( IsDirectory ( filename ) )
if ( IsDirectory ( filename ) ) {
{
LOG_ERROR ( Common_Filesystem , " Failed: %s is a directory " , filename . c_str ( ) ) ;
LOG_ERROR ( Common_Filesystem , " Failed: %s is a directory " , filename . c_str ( ) ) ;
return false ;
return false ;
}
}
# ifdef _WIN32
# ifdef _WIN32
if ( ! DeleteFileW ( Common : : UTF8ToUTF16W ( filename ) . c_str ( ) ) )
if ( ! DeleteFileW ( Common : : UTF8ToUTF16W ( filename ) . c_str ( ) ) ) {
{
LOG_ERROR ( Common_Filesystem , " DeleteFile failed on %s: %s " , filename . c_str ( ) ,
LOG_ERROR ( Common_Filesystem , " DeleteFile failed on %s: %s " ,
GetLastErrorMsg ( ) ) ;
filename . c_str ( ) , GetLastErrorMsg ( ) ) ;
return false ;
return false ;
}
}
# else
# else
if ( unlink ( filename . c_str ( ) ) = = - 1 ) {
if ( unlink ( filename . c_str ( ) ) = = - 1 ) {
LOG_ERROR ( Common_Filesystem , " unlink failed on %s: %s " ,
LOG_ERROR ( Common_Filesystem , " unlink failed on %s: %s " , filename . c_str ( ) ,
filename . c_str ( ) , GetLastErrorMsg ( ) ) ;
GetLastErrorMsg ( ) ) ;
return false ;
return false ;
}
}
# endif
# endif
@ -165,16 +156,15 @@ bool Delete(const std::string &filename)
}
}
// Returns true if successful, or path already exists.
// Returns true if successful, or path already exists.
bool CreateDir ( const std : : string & path )
bool CreateDir ( const std : : string & path ) {
{
LOG_TRACE ( Common_Filesystem , " directory %s " , path . c_str ( ) ) ;
LOG_TRACE ( Common_Filesystem , " directory %s " , path . c_str ( ) ) ;
# ifdef _WIN32
# ifdef _WIN32
if ( : : CreateDirectoryW ( Common : : UTF8ToUTF16W ( path ) . c_str ( ) , nullptr ) )
if ( : : CreateDirectoryW ( Common : : UTF8ToUTF16W ( path ) . c_str ( ) , nullptr ) )
return true ;
return true ;
DWORD error = GetLastError ( ) ;
DWORD error = GetLastError ( ) ;
if ( error = = ERROR_ALREADY_EXISTS )
if ( error = = ERROR_ALREADY_EXISTS ) {
{
LOG_WARNING ( Common_Filesystem , " CreateDirectory failed on %s: already exists " ,
LOG_WARNING ( Common_Filesystem , " CreateDirectory failed on %s: already exists " , path . c_str ( ) ) ;
path . c_str ( ) ) ;
return true ;
return true ;
}
}
LOG_ERROR ( Common_Filesystem , " CreateDirectory failed on %s: %i " , path . c_str ( ) , error ) ;
LOG_ERROR ( Common_Filesystem , " CreateDirectory failed on %s: %i " , path . c_str ( ) , error ) ;
@ -185,8 +175,7 @@ bool CreateDir(const std::string &path)
int err = errno ;
int err = errno ;
if ( err = = EEXIST )
if ( err = = EEXIST ) {
{
LOG_WARNING ( Common_Filesystem , " mkdir failed on %s: already exists " , path . c_str ( ) ) ;
LOG_WARNING ( Common_Filesystem , " mkdir failed on %s: already exists " , path . c_str ( ) ) ;
return true ;
return true ;
}
}
@ -197,20 +186,17 @@ bool CreateDir(const std::string &path)
}
}
// Creates the full path of fullPath returns true on success
// Creates the full path of fullPath returns true on success
bool CreateFullPath ( const std : : string & fullPath )
bool CreateFullPath ( const std : : string & fullPath ) {
{
int panicCounter = 100 ;
int panicCounter = 100 ;
LOG_TRACE ( Common_Filesystem , " path %s " , fullPath . c_str ( ) ) ;
LOG_TRACE ( Common_Filesystem , " path %s " , fullPath . c_str ( ) ) ;
if ( FileUtil : : Exists ( fullPath ) )
if ( FileUtil : : Exists ( fullPath ) ) {
{
LOG_WARNING ( Common_Filesystem , " path exists %s " , fullPath . c_str ( ) ) ;
LOG_WARNING ( Common_Filesystem , " path exists %s " , fullPath . c_str ( ) ) ;
return true ;
return true ;
}
}
size_t position = 0 ;
size_t position = 0 ;
while ( true )
while ( true ) {
{
// Find next sub path
// Find next sub path
position = fullPath . find ( DIR_SEP_CHR , position ) ;
position = fullPath . find ( DIR_SEP_CHR , position ) ;
@ -227,8 +213,7 @@ bool CreateFullPath(const std::string &fullPath)
// A safety check
// A safety check
panicCounter - - ;
panicCounter - - ;
if ( panicCounter < = 0 )
if ( panicCounter < = 0 ) {
{
LOG_ERROR ( Common , " CreateFullPath: directory structure is too deep " ) ;
LOG_ERROR ( Common , " CreateFullPath: directory structure is too deep " ) ;
return false ;
return false ;
}
}
@ -236,15 +221,12 @@ bool CreateFullPath(const std::string &fullPath)
}
}
}
}
// Deletes a directory filename, returns true on success
// Deletes a directory filename, returns true on success
bool DeleteDir ( const std : : string & filename )
bool DeleteDir ( const std : : string & filename ) {
{
LOG_INFO ( Common_Filesystem , " directory %s " , filename . c_str ( ) ) ;
LOG_INFO ( Common_Filesystem , " directory %s " , filename . c_str ( ) ) ;
// check if a directory
// check if a directory
if ( ! FileUtil : : IsDirectory ( filename ) )
if ( ! FileUtil : : IsDirectory ( filename ) ) {
{
LOG_ERROR ( Common_Filesystem , " Not a directory %s " , filename . c_str ( ) ) ;
LOG_ERROR ( Common_Filesystem , " Not a directory %s " , filename . c_str ( ) ) ;
return false ;
return false ;
}
}
@ -262,33 +244,31 @@ bool DeleteDir(const std::string &filename)
}
}
// renames file srcFilename to destFilename, returns true on success
// renames file srcFilename to destFilename, returns true on success
bool Rename ( const std : : string & srcFilename , const std : : string & destFilename )
bool Rename ( const std : : string & srcFilename , const std : : string & destFilename ) {
{
LOG_TRACE ( Common_Filesystem , " %s --> %s " , srcFilename . c_str ( ) , destFilename . c_str ( ) ) ;
LOG_TRACE ( Common_Filesystem , " %s --> %s " ,
srcFilename . c_str ( ) , destFilename . c_str ( ) ) ;
# ifdef _WIN32
# ifdef _WIN32
if ( _wrename ( Common : : UTF8ToUTF16W ( srcFilename ) . c_str ( ) , Common : : UTF8ToUTF16W ( destFilename ) . c_str ( ) ) = = 0 )
if ( _wrename ( Common : : UTF8ToUTF16W ( srcFilename ) . c_str ( ) ,
Common : : UTF8ToUTF16W ( destFilename ) . c_str ( ) ) = = 0 )
return true ;
return true ;
# else
# else
if ( rename ( srcFilename . c_str ( ) , destFilename . c_str ( ) ) = = 0 )
if ( rename ( srcFilename . c_str ( ) , destFilename . c_str ( ) ) = = 0 )
return true ;
return true ;
# endif
# endif
LOG_ERROR ( Common_Filesystem , " failed %s --> %s: %s " ,
LOG_ERROR ( Common_Filesystem , " failed %s --> %s: %s " , srcFilename . c_str ( ) , destFilename . c_str ( ) ,
srcFilename. c_str ( ) , destFilename . c_str ( ) , GetLastErrorMsg( ) ) ;
GetLastErrorMsg( ) ) ;
return false ;
return false ;
}
}
// copies file srcFilename to destFilename, returns true on success
// copies file srcFilename to destFilename, returns true on success
bool Copy ( const std : : string & srcFilename , const std : : string & destFilename )
bool Copy ( const std : : string & srcFilename , const std : : string & destFilename ) {
{
LOG_TRACE ( Common_Filesystem , " %s --> %s " , srcFilename . c_str ( ) , destFilename . c_str ( ) ) ;
LOG_TRACE ( Common_Filesystem , " %s --> %s " ,
srcFilename . c_str ( ) , destFilename . c_str ( ) ) ;
# ifdef _WIN32
# ifdef _WIN32
if ( CopyFileW ( Common : : UTF8ToUTF16W ( srcFilename ) . c_str ( ) , Common : : UTF8ToUTF16W ( destFilename ) . c_str ( ) , FALSE ) )
if ( CopyFileW ( Common : : UTF8ToUTF16W ( srcFilename ) . c_str ( ) ,
Common : : UTF8ToUTF16W ( destFilename ) . c_str ( ) , FALSE ) )
return true ;
return true ;
LOG_ERROR ( Common_Filesystem , " failed %s --> %s: %s " ,
LOG_ERROR ( Common_Filesystem , " failed %s --> %s: %s " , srcFilename . c_str ( ) , destFilename . c_str ( ) ,
srcFilename . c_str ( ) , destFilename . c_str ( ) , GetLastErrorMsg ( ) ) ;
GetLastErrorMsg ( ) ) ;
return false ;
return false ;
# else
# else
@ -299,34 +279,28 @@ bool Copy(const std::string &srcFilename, const std::string &destFilename)
// Open input file
// Open input file
FILE * input = fopen ( srcFilename . c_str ( ) , " rb " ) ;
FILE * input = fopen ( srcFilename . c_str ( ) , " rb " ) ;
if ( ! input )
if ( ! input ) {
{
LOG_ERROR ( Common_Filesystem , " opening input failed %s --> %s: %s " , srcFilename . c_str ( ) ,
LOG_ERROR ( Common_Filesystem , " opening input failed %s --> %s: %s " ,
destFilename . c_str ( ) , GetLastErrorMsg ( ) ) ;
srcFilename . c_str ( ) , destFilename . c_str ( ) , GetLastErrorMsg ( ) ) ;
return false ;
return false ;
}
}
// open output file
// open output file
FILE * output = fopen ( destFilename . c_str ( ) , " wb " ) ;
FILE * output = fopen ( destFilename . c_str ( ) , " wb " ) ;
if ( ! output )
if ( ! output ) {
{
fclose ( input ) ;
fclose ( input ) ;
LOG_ERROR ( Common_Filesystem , " opening output failed %s --> %s: %s " ,
LOG_ERROR ( Common_Filesystem , " opening output failed %s --> %s: %s " , srcFilename . c_str ( ) ,
srcFilename . c_str ( ) , destFilename . c_str ( ) , GetLastErrorMsg ( ) ) ;
destFilename . c_str ( ) , GetLastErrorMsg ( ) ) ;
return false ;
return false ;
}
}
// copy loop
// copy loop
while ( ! feof ( input ) )
while ( ! feof ( input ) ) {
{
// read input
// read input
int rnum = fread ( buffer , sizeof ( char ) , BSIZE , input ) ;
int rnum = fread ( buffer , sizeof ( char ) , BSIZE , input ) ;
if ( rnum ! = BSIZE )
if ( rnum ! = BSIZE ) {
{
if ( ferror ( input ) ! = 0 ) {
if ( ferror ( input ) ! = 0 )
LOG_ERROR ( Common_Filesystem , " failed reading from source, %s --> %s: %s " ,
{
LOG_ERROR ( Common_Filesystem ,
" failed reading from source, %s --> %s: %s " ,
srcFilename . c_str ( ) , destFilename . c_str ( ) , GetLastErrorMsg ( ) ) ;
srcFilename . c_str ( ) , destFilename . c_str ( ) , GetLastErrorMsg ( ) ) ;
goto bail ;
goto bail ;
}
}
@ -334,10 +308,8 @@ bool Copy(const std::string &srcFilename, const std::string &destFilename)
// write output
// write output
int wnum = fwrite ( buffer , sizeof ( char ) , rnum , output ) ;
int wnum = fwrite ( buffer , sizeof ( char ) , rnum , output ) ;
if ( wnum ! = rnum )
if ( wnum ! = rnum ) {
{
LOG_ERROR ( Common_Filesystem , " failed writing to output, %s --> %s: %s " ,
LOG_ERROR ( Common_Filesystem ,
" failed writing to output, %s --> %s: %s " ,
srcFilename . c_str ( ) , destFilename . c_str ( ) , GetLastErrorMsg ( ) ) ;
srcFilename . c_str ( ) , destFilename . c_str ( ) , GetLastErrorMsg ( ) ) ;
goto bail ;
goto bail ;
}
}
@ -356,16 +328,13 @@ bail:
}
}
// Returns the size of filename (64bit)
// Returns the size of filename (64bit)
u64 GetSize ( const std : : string & filename )
u64 GetSize ( const std : : string & filename ) {
{
if ( ! Exists ( filename ) ) {
if ( ! Exists ( filename ) )
{
LOG_ERROR ( Common_Filesystem , " failed %s: No such file " , filename . c_str ( ) ) ;
LOG_ERROR ( Common_Filesystem , " failed %s: No such file " , filename . c_str ( ) ) ;
return 0 ;
return 0 ;
}
}
if ( IsDirectory ( filename ) )
if ( IsDirectory ( filename ) ) {
{
LOG_ERROR ( Common_Filesystem , " failed %s: is a directory " , filename . c_str ( ) ) ;
LOG_ERROR ( Common_Filesystem , " failed %s: is a directory " , filename . c_str ( ) ) ;
return 0 ;
return 0 ;
}
}
@ -377,65 +346,54 @@ u64 GetSize(const std::string &filename)
if ( stat64 ( filename . c_str ( ) , & buf ) = = 0 )
if ( stat64 ( filename . c_str ( ) , & buf ) = = 0 )
# endif
# endif
{
{
LOG_TRACE ( Common_Filesystem , " %s: %lld " ,
LOG_TRACE ( Common_Filesystem , " %s: %lld " , filename . c_str ( ) , ( long long ) buf . st_size ) ;
filename . c_str ( ) , ( long long ) buf . st_size ) ;
return buf . st_size ;
return buf . st_size ;
}
}
LOG_ERROR ( Common_Filesystem , " Stat failed %s: %s " ,
LOG_ERROR ( Common_Filesystem , " Stat failed %s: %s " , filename . c_str ( ) , GetLastErrorMsg ( ) ) ;
filename . c_str ( ) , GetLastErrorMsg ( ) ) ;
return 0 ;
return 0 ;
}
}
// Overloaded GetSize, accepts file descriptor
// Overloaded GetSize, accepts file descriptor
u64 GetSize ( const int fd )
u64 GetSize ( const int fd ) {
{
struct stat64 buf ;
struct stat64 buf ;
if ( fstat64 ( fd , & buf ) ! = 0 ) {
if ( fstat64 ( fd , & buf ) ! = 0 ) {
LOG_ERROR ( Common_Filesystem , " GetSize: stat failed %i: %s " ,
LOG_ERROR ( Common_Filesystem , " GetSize: stat failed %i: %s " , fd , GetLastErrorMsg ( ) ) ;
fd , GetLastErrorMsg ( ) ) ;
return 0 ;
return 0 ;
}
}
return buf . st_size ;
return buf . st_size ;
}
}
// Overloaded GetSize, accepts FILE*
// Overloaded GetSize, accepts FILE*
u64 GetSize ( FILE * f )
u64 GetSize ( FILE * f ) {
{
// can't use off_t here because it can be 32-bit
// can't use off_t here because it can be 32-bit
u64 pos = ftello ( f ) ;
u64 pos = ftello ( f ) ;
if ( fseeko ( f , 0 , SEEK_END ) ! = 0 ) {
if ( fseeko ( f , 0 , SEEK_END ) ! = 0 ) {
LOG_ERROR ( Common_Filesystem , " GetSize: seek failed %p: %s " ,
LOG_ERROR ( Common_Filesystem , " GetSize: seek failed %p: %s " , f , GetLastErrorMsg ( ) ) ;
f , GetLastErrorMsg ( ) ) ;
return 0 ;
return 0 ;
}
}
u64 size = ftello ( f ) ;
u64 size = ftello ( f ) ;
if ( ( size ! = pos ) & & ( fseeko ( f , pos , SEEK_SET ) ! = 0 ) ) {
if ( ( size ! = pos ) & & ( fseeko ( f , pos , SEEK_SET ) ! = 0 ) ) {
LOG_ERROR ( Common_Filesystem , " GetSize: seek failed %p: %s " ,
LOG_ERROR ( Common_Filesystem , " GetSize: seek failed %p: %s " , f , GetLastErrorMsg ( ) ) ;
f , GetLastErrorMsg ( ) ) ;
return 0 ;
return 0 ;
}
}
return size ;
return size ;
}
}
// creates an empty file filename, returns true on success
// creates an empty file filename, returns true on success
bool CreateEmptyFile ( const std : : string & filename )
bool CreateEmptyFile ( const std : : string & filename ) {
{
LOG_TRACE ( Common_Filesystem , " %s " , filename . c_str ( ) ) ;
LOG_TRACE ( Common_Filesystem , " %s " , filename . c_str ( ) ) ;
if ( ! FileUtil : : IOFile ( filename , " wb " ) )
if ( ! FileUtil : : IOFile ( filename , " wb " ) ) {
{
LOG_ERROR ( Common_Filesystem , " failed %s: %s " , filename . c_str ( ) , GetLastErrorMsg ( ) ) ;
LOG_ERROR ( Common_Filesystem , " failed %s: %s " ,
filename . c_str ( ) , GetLastErrorMsg ( ) ) ;
return false ;
return false ;
}
}
return true ;
return true ;
}
}
bool ForeachDirectoryEntry ( unsigned * num_entries_out , const std : : string & directory ,
bool ForeachDirectoryEntry ( unsigned * num_entries_out , const std : : string & directory , DirectoryEntryCallable callback )
DirectoryEntryCallable callback ) {
{
LOG_TRACE ( Common_Filesystem , " directory %s " , directory . c_str ( ) ) ;
LOG_TRACE ( Common_Filesystem , " directory %s " , directory . c_str ( ) ) ;
// How many files + directories we found
// How many files + directories we found
@ -493,8 +451,8 @@ bool ForeachDirectoryEntry(unsigned* num_entries_out, const std::string &directo
return true ;
return true ;
}
}
unsigned ScanDirectoryTree ( const std : : string & directory , FSTEntry & parent_entry , unsigned int recursion )
unsigned ScanDirectoryTree ( const std : : string & directory , FSTEntry & parent_entry ,
{
unsigned int recursion ) {
const auto callback = [ recursion , & parent_entry ] ( unsigned * num_entries_out ,
const auto callback = [ recursion , & parent_entry ] ( unsigned * num_entries_out ,
const std : : string & directory ,
const std : : string & directory ,
const std : : string & virtual_name ) - > bool {
const std : : string & virtual_name ) - > bool {
@ -526,11 +484,8 @@ unsigned ScanDirectoryTree(const std::string &directory, FSTEntry& parent_entry,
return ForeachDirectoryEntry ( & num_entries , directory , callback ) ? num_entries : 0 ;
return ForeachDirectoryEntry ( & num_entries , directory , callback ) ? num_entries : 0 ;
}
}
bool DeleteDirRecursively ( const std : : string & directory , unsigned int recursion ) {
bool DeleteDirRecursively ( const std : : string & directory , unsigned int recursion )
const auto callback = [ recursion ] ( unsigned * num_entries_out , const std : : string & directory ,
{
const auto callback = [ recursion ] ( unsigned * num_entries_out ,
const std : : string & directory ,
const std : : string & virtual_name ) - > bool {
const std : : string & virtual_name ) - > bool {
std : : string new_path = directory + DIR_SEP_CHR + virtual_name ;
std : : string new_path = directory + DIR_SEP_CHR + virtual_name ;
@ -551,43 +506,44 @@ bool DeleteDirRecursively(const std::string &directory, unsigned int recursion)
}
}
// Create directory and copy contents (does not overwrite existing files)
// Create directory and copy contents (does not overwrite existing files)
void CopyDir ( const std : : string & source_path , const std : : string & dest_path )
void CopyDir ( const std : : string & source_path , const std : : string & dest_path ) {
{
# ifndef _WIN32
# ifndef _WIN32
if ( source_path = = dest_path ) return ;
if ( source_path = = dest_path )
if ( ! FileUtil : : Exists ( source_path ) ) return ;
return ;
if ( ! FileUtil : : Exists ( dest_path ) ) FileUtil : : CreateFullPath ( dest_path ) ;
if ( ! FileUtil : : Exists ( source_path ) )
return ;
if ( ! FileUtil : : Exists ( dest_path ) )
FileUtil : : CreateFullPath ( dest_path ) ;
DIR * dirp = opendir ( source_path . c_str ( ) ) ;
DIR * dirp = opendir ( source_path . c_str ( ) ) ;
if ( ! dirp ) return ;
if ( ! dirp )
return ;
while ( struct dirent * result = readdir ( dirp ) ) {
while ( struct dirent * result = readdir ( dirp ) ) {
const std : : string virtualName ( result - > d_name ) ;
const std : : string virtualName ( result - > d_name ) ;
// check for "." and ".."
// check for "." and ".."
if ( ( ( virtualName [ 0 ] = = ' . ' ) & & ( virtualName [ 1 ] = = ' \0 ' ) ) | |
if ( ( ( virtualName [ 0 ] = = ' . ' ) & & ( virtualName [ 1 ] = = ' \0 ' ) ) | |
( ( virtualName [ 0 ] = = ' . ' ) & & ( virtualName [ 1 ] = = ' . ' ) & &
( ( virtualName [ 0 ] = = ' . ' ) & & ( virtualName [ 1 ] = = ' . ' ) & & ( virtualName [ 2 ] = = ' \0 ' ) ) )
( virtualName [ 2 ] = = ' \0 ' ) ) )
continue ;
continue ;
std : : string source , dest ;
std : : string source , dest ;
source = source_path + virtualName ;
source = source_path + virtualName ;
dest = dest_path + virtualName ;
dest = dest_path + virtualName ;
if ( IsDirectory ( source ) )
if ( IsDirectory ( source ) ) {
{
source + = ' / ' ;
source + = ' / ' ;
dest + = ' / ' ;
dest + = ' / ' ;
if ( ! FileUtil : : Exists ( dest ) ) FileUtil : : CreateFullPath ( dest ) ;
if ( ! FileUtil : : Exists ( dest ) )
FileUtil : : CreateFullPath ( dest ) ;
CopyDir ( source , dest ) ;
CopyDir ( source , dest ) ;
}
} else if ( ! FileUtil : : Exists ( dest ) )
else if ( ! FileUtil : : Exists ( dest ) ) FileUtil : : Copy ( source , dest ) ;
FileUtil : : Copy ( source , dest ) ;
}
}
closedir ( dirp ) ;
closedir ( dirp ) ;
# endif
# endif
}
}
// Returns the current directory
// Returns the current directory
std : : string GetCurrentDir ( )
std : : string GetCurrentDir ( ) {
{
// Get the current working directory (getcwd uses malloc)
// Get the current working directory (getcwd uses malloc)
# ifdef _WIN32
# ifdef _WIN32
wchar_t * dir ;
wchar_t * dir ;
@ -596,8 +552,7 @@ std::string GetCurrentDir()
char * dir ;
char * dir ;
if ( ! ( dir = getcwd ( nullptr , 0 ) ) ) {
if ( ! ( dir = getcwd ( nullptr , 0 ) ) ) {
# endif
# endif
LOG_ERROR ( Common_Filesystem , " GetCurrentDirectory failed: %s " ,
LOG_ERROR ( Common_Filesystem , " GetCurrentDirectory failed: %s " , GetLastErrorMsg ( ) ) ;
GetLastErrorMsg ( ) ) ;
return nullptr ;
return nullptr ;
}
}
# ifdef _WIN32
# ifdef _WIN32
@ -610,8 +565,7 @@ std::string GetCurrentDir()
}
}
// Sets the current directory to the given directory
// Sets the current directory to the given directory
bool SetCurrentDir ( const std : : string & directory )
bool SetCurrentDir ( const std : : string & directory ) {
{
# ifdef _WIN32
# ifdef _WIN32
return _wchdir ( Common : : UTF8ToUTF16W ( directory ) . c_str ( ) ) = = 0 ;
return _wchdir ( Common : : UTF8ToUTF16W ( directory ) . c_str ( ) ) = = 0 ;
# else
# else
@ -620,8 +574,7 @@ bool SetCurrentDir(const std::string &directory)
}
}
# if defined(__APPLE__)
# if defined(__APPLE__)
std : : string GetBundleDirectory ( )
std : : string GetBundleDirectory ( ) {
{
CFURLRef BundleRef ;
CFURLRef BundleRef ;
char AppBundlePath [ MAXPATHLEN ] ;
char AppBundlePath [ MAXPATHLEN ] ;
// Get the main bundle for the app
// Get the main bundle for the app
@ -636,11 +589,9 @@ std::string GetBundleDirectory()
# endif
# endif
# ifdef _WIN32
# ifdef _WIN32
std : : string & GetExeDirectory ( )
std : : string & GetExeDirectory ( ) {
{
static std : : string exe_path ;
static std : : string exe_path ;
if ( exe_path . empty ( ) )
if ( exe_path . empty ( ) ) {
{
wchar_t wchar_exe_path [ 2048 ] ;
wchar_t wchar_exe_path [ 2048 ] ;
GetModuleFileNameW ( nullptr , wchar_exe_path , 2048 ) ;
GetModuleFileNameW ( nullptr , wchar_exe_path , 2048 ) ;
exe_path = Common : : UTF16ToUTF8 ( wchar_exe_path ) ;
exe_path = Common : : UTF16ToUTF8 ( wchar_exe_path ) ;
@ -660,7 +611,8 @@ static const std::string& GetHomeDirectory() {
home_path = envvar ;
home_path = envvar ;
} else {
} else {
auto pw = getpwuid ( getuid ( ) ) ;
auto pw = getpwuid ( getuid ( ) ) ;
ASSERT_MSG ( pw , " $HOME isn’ t defined, and the current user can’ t be found in /etc/passwd. " ) ;
ASSERT_MSG ( pw ,
" $HOME isn’ t defined, and the current user can’ t be found in /etc/passwd. " ) ;
home_path = pw - > pw_dir ;
home_path = pw - > pw_dir ;
}
}
}
}
@ -699,8 +651,7 @@ static const std::string GetUserDirectory(const std::string& envvar) {
}
}
# endif
# endif
std : : string GetSysDirectory ( )
std : : string GetSysDirectory ( ) {
{
std : : string sysDir ;
std : : string sysDir ;
# if defined(__APPLE__)
# if defined(__APPLE__)
@ -718,13 +669,11 @@ std::string GetSysDirectory()
// Returns a string with a Citra data dir or file in the user's home
// Returns a string with a Citra data dir or file in the user's home
// directory. To be used in "multi-user" mode (that is, installed).
// directory. To be used in "multi-user" mode (that is, installed).
const std : : string & GetUserPath ( const unsigned int DirIDX , const std : : string & newPath )
const std : : string & GetUserPath ( const unsigned int DirIDX , const std : : string & newPath ) {
{
static std : : string paths [ NUM_PATH_INDICES ] ;
static std : : string paths [ NUM_PATH_INDICES ] ;
// Set up all paths and files on the first run
// Set up all paths and files on the first run
if ( paths [ D_USER_IDX ] . empty ( ) )
if ( paths [ D_USER_IDX ] . empty ( ) ) {
{
# ifdef _WIN32
# ifdef _WIN32
paths [ D_USER_IDX ] = GetExeDirectory ( ) + DIR_SEP USERDATA_DIR DIR_SEP ;
paths [ D_USER_IDX ] = GetExeDirectory ( ) + DIR_SEP USERDATA_DIR DIR_SEP ;
paths [ D_CONFIG_IDX ] = paths [ D_USER_IDX ] + CONFIG_DIR DIR_SEP ;
paths [ D_CONFIG_IDX ] = paths [ D_USER_IDX ] + CONFIG_DIR DIR_SEP ;
@ -764,20 +713,15 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string &new
paths [ F_MAINLOG_IDX ] = paths [ D_LOGS_IDX ] + MAIN_LOG ;
paths [ F_MAINLOG_IDX ] = paths [ D_LOGS_IDX ] + MAIN_LOG ;
}
}
if ( ! newPath . empty ( ) )
if ( ! newPath . empty ( ) ) {
{
if ( ! FileUtil : : IsDirectory ( newPath ) ) {
if ( ! FileUtil : : IsDirectory ( newPath ) )
{
LOG_ERROR ( Common_Filesystem , " Invalid path specified %s " , newPath . c_str ( ) ) ;
LOG_ERROR ( Common_Filesystem , " Invalid path specified %s " , newPath . c_str ( ) ) ;
return paths [ DirIDX ] ;
return paths [ DirIDX ] ;
}
} else {
else
{
paths [ DirIDX ] = newPath ;
paths [ DirIDX ] = newPath ;
}
}
switch ( DirIDX )
switch ( DirIDX ) {
{
case D_ROOT_IDX :
case D_ROOT_IDX :
paths [ D_USER_IDX ] = paths [ D_ROOT_IDX ] + DIR_SEP ;
paths [ D_USER_IDX ] = paths [ D_ROOT_IDX ] + DIR_SEP ;
paths [ D_SYSCONF_IDX ] = paths [ D_USER_IDX ] + SYSCONF_DIR + DIR_SEP ;
paths [ D_SYSCONF_IDX ] = paths [ D_USER_IDX ] + SYSCONF_DIR + DIR_SEP ;
@ -828,13 +772,11 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string &new
return paths [ DirIDX ] ;
return paths [ DirIDX ] ;
}
}
size_t WriteStringToFile ( bool text_file , const std : : string & str , const char * filename )
size_t WriteStringToFile ( bool text_file , const std : : string & str , const char * filename ) {
{
return FileUtil : : IOFile ( filename , text_file ? " w " : " wb " ) . WriteBytes ( str . data ( ) , str . size ( ) ) ;
return FileUtil : : IOFile ( filename , text_file ? " w " : " wb " ) . WriteBytes ( str . data ( ) , str . size ( ) ) ;
}
}
size_t ReadFileToString ( bool text_file , const char * filename , std : : string & str )
size_t ReadFileToString ( bool text_file , const char * filename , std : : string & str ) {
{
IOFile file ( filename , text_file ? " r " : " rb " ) ;
IOFile file ( filename , text_file ? " r " : " rb " ) ;
if ( ! file )
if ( ! file )
@ -886,42 +828,35 @@ void SplitFilename83(const std::string& filename, std::array<char, 9>& short_nam
}
}
}
}
IOFile : : IOFile ( )
IOFile : : IOFile ( ) { }
{
}
IOFile : : IOFile ( const std : : string & filename , const char openmode [ ] )
IOFile : : IOFile ( const std : : string & filename , const char openmode [ ] ) {
{
Open ( filename , openmode ) ;
Open ( filename , openmode ) ;
}
}
IOFile : : ~ IOFile ( )
IOFile : : ~ IOFile ( ) {
{
Close ( ) ;
Close ( ) ;
}
}
IOFile : : IOFile ( IOFile & & other )
IOFile : : IOFile ( IOFile & & other ) {
{
Swap ( other ) ;
Swap ( other ) ;
}
}
IOFile & IOFile : : operator = ( IOFile & & other )
IOFile & IOFile : : operator = ( IOFile & & other ) {
{
Swap ( other ) ;
Swap ( other ) ;
return * this ;
return * this ;
}
}
void IOFile : : Swap ( IOFile & other )
void IOFile : : Swap ( IOFile & other ) {
{
std : : swap ( m_file , other . m_file ) ;
std : : swap ( m_file , other . m_file ) ;
std : : swap ( m_good , other . m_good ) ;
std : : swap ( m_good , other . m_good ) ;
}
}
bool IOFile : : Open ( const std : : string & filename , const char openmode [ ] )
bool IOFile : : Open ( const std : : string & filename , const char openmode [ ] ) {
{
Close ( ) ;
Close ( ) ;
# ifdef _WIN32
# ifdef _WIN32
_wfopen_s ( & m_file , Common : : UTF8ToUTF16W ( filename ) . c_str ( ) , Common : : UTF8ToUTF16W ( openmode ) . c_str ( ) ) ;
_wfopen_s ( & m_file , Common : : UTF8ToUTF16W ( filename ) . c_str ( ) ,
Common : : UTF8ToUTF16W ( openmode ) . c_str ( ) ) ;
# else
# else
m_file = fopen ( filename . c_str ( ) , openmode ) ;
m_file = fopen ( filename . c_str ( ) , openmode ) ;
# endif
# endif
@ -930,8 +865,7 @@ bool IOFile::Open(const std::string& filename, const char openmode[])
return m_good ;
return m_good ;
}
}
bool IOFile : : Close ( )
bool IOFile : : Close ( ) {
{
if ( ! IsOpen ( ) | | 0 ! = std : : fclose ( m_file ) )
if ( ! IsOpen ( ) | | 0 ! = std : : fclose ( m_file ) )
m_good = false ;
m_good = false ;
@ -939,41 +873,37 @@ bool IOFile::Close()
return m_good ;
return m_good ;
}
}
u64 IOFile : : GetSize ( ) const
u64 IOFile : : GetSize ( ) const {
{
if ( IsOpen ( ) )
if ( IsOpen ( ) )
return FileUtil : : GetSize ( m_file ) ;
return FileUtil : : GetSize ( m_file ) ;
return 0 ;
return 0 ;
}
}
bool IOFile : : Seek ( s64 off , int origin )
bool IOFile : : Seek ( s64 off , int origin ) {
{
if ( ! IsOpen ( ) | | 0 ! = fseeko ( m_file , off , origin ) )
if ( ! IsOpen ( ) | | 0 ! = fseeko ( m_file , off , origin ) )
m_good = false ;
m_good = false ;
return m_good ;
return m_good ;
}
}
u64 IOFile : : Tell ( ) const
u64 IOFile : : Tell ( ) const {
{
if ( IsOpen ( ) )
if ( IsOpen ( ) )
return ftello ( m_file ) ;
return ftello ( m_file ) ;
return - 1 ;
return - 1 ;
}
}
bool IOFile : : Flush ( )
bool IOFile : : Flush ( ) {
{
if ( ! IsOpen ( ) | | 0 ! = std : : fflush ( m_file ) )
if ( ! IsOpen ( ) | | 0 ! = std : : fflush ( m_file ) )
m_good = false ;
m_good = false ;
return m_good ;
return m_good ;
}
}
bool IOFile : : Resize ( u64 size )
bool IOFile : : Resize ( u64 size ) {
{
if ( ! IsOpen ( ) | |
if ( ! IsOpen ( ) | | 0 ! =
0 ! =
# ifdef _WIN32
# ifdef _WIN32
// ector: _chsize sucks, not 64-bit safe
// ector: _chsize sucks, not 64-bit safe
// F|RES: changed to _chsize_s. i think it is 64-bit safe
// F|RES: changed to _chsize_s. i think it is 64-bit safe