2012-06-14 09:06:06 -04:00
// cFile.cpp
// Implements the cFile class providing an OS-independent abstraction of a file.
# include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
2012-09-23 17:23:33 -04:00
# include "File.h"
2013-10-09 08:19:14 -04:00
# include <fstream>
2014-06-30 15:41:14 -04:00
# ifdef _WIN32
# include <share.h> // for _SH_DENYWRITE
# endif // _WIN32
2012-06-14 09:06:06 -04:00
cFile : : cFile ( void ) :
# ifdef USE_STDIO_FILE
m_File ( NULL )
# else
m_File ( INVALID_HANDLE_VALUE )
# endif // USE_STDIO_FILE
{
// Nothing needed yet
}
2013-02-07 04:15:55 -05:00
cFile : : cFile ( const AString & iFileName , eMode iMode ) :
2012-06-14 09:06:06 -04:00
# ifdef USE_STDIO_FILE
m_File ( NULL )
# else
m_File ( INVALID_HANDLE_VALUE )
# endif // USE_STDIO_FILE
{
Open ( iFileName , iMode ) ;
}
cFile : : ~ cFile ( )
{
if ( IsOpen ( ) )
{
Close ( ) ;
}
}
2013-02-07 04:15:55 -05:00
bool cFile : : Open ( const AString & iFileName , eMode iMode )
2012-06-14 09:06:06 -04:00
{
ASSERT ( ! IsOpen ( ) ) ; // You should close the file before opening another one
if ( IsOpen ( ) )
{
Close ( ) ;
}
const char * Mode = NULL ;
switch ( iMode )
{
case fmRead : Mode = " rb " ; break ;
case fmWrite : Mode = " wb " ; break ;
case fmReadWrite : Mode = " rb+ " ; break ;
2014-04-25 23:49:55 -04:00
}
if ( Mode = = NULL )
{
ASSERT ( ! " Unhandled file mode " ) ;
return false ;
2012-06-14 09:06:06 -04:00
}
2014-02-03 17:25:16 -05:00
# ifdef _WIN32
2014-05-02 14:55:50 -04:00
m_File = _fsopen ( ( FILE_IO_PREFIX + iFileName ) . c_str ( ) , Mode , _SH_DENYWR ) ;
2014-02-03 17:25:16 -05:00
# else
m_File = fopen ( ( FILE_IO_PREFIX + iFileName ) . c_str ( ) , Mode ) ;
2014-07-17 16:15:34 -04:00
# endif // _WIN32
2014-02-03 17:25:16 -05:00
2012-06-14 09:06:06 -04:00
if ( ( m_File = = NULL ) & & ( iMode = = fmReadWrite ) )
{
// Fix for MS not following C spec, opening "a" mode files for writing at the end only
// The file open operation has been tried with "read update", fails if file not found
// So now we know either the file doesn't exist or we don't have rights, no need to worry about file contents.
// Simply re-open for read-writing, erasing existing contents:
2014-02-03 17:25:16 -05:00
# ifdef _WIN32
2014-05-02 14:55:50 -04:00
m_File = _fsopen ( ( FILE_IO_PREFIX + iFileName ) . c_str ( ) , " wb+ " , _SH_DENYWR ) ;
2014-02-03 17:25:16 -05:00
# else
m_File = fopen ( ( FILE_IO_PREFIX + iFileName ) . c_str ( ) , " wb+ " ) ;
2014-07-17 16:15:34 -04:00
# endif // _WIN32
2014-02-03 17:25:16 -05:00
2012-06-14 09:06:06 -04:00
}
return ( m_File ! = NULL ) ;
}
void cFile : : Close ( void )
{
if ( ! IsOpen ( ) )
{
2013-02-25 14:06:37 -05:00
// Closing an unopened file is a legal nop
2012-06-14 09:06:06 -04:00
return ;
}
fclose ( m_File ) ;
m_File = NULL ;
}
bool cFile : : IsOpen ( void ) const
{
return ( m_File ! = NULL ) ;
}
bool cFile : : IsEOF ( void ) const
{
ASSERT ( IsOpen ( ) ) ;
if ( ! IsOpen ( ) )
{
// Unopened files behave as at EOF
return true ;
}
return ( feof ( m_File ) ! = 0 ) ;
}
2014-04-28 13:31:07 -04:00
int cFile : : Read ( void * iBuffer , size_t iNumBytes )
2012-06-14 09:06:06 -04:00
{
ASSERT ( IsOpen ( ) ) ;
if ( ! IsOpen ( ) )
{
return - 1 ;
}
2014-04-01 08:58:05 -04:00
return ( int ) fread ( iBuffer , 1 , ( size_t ) iNumBytes , m_File ) ; // fread() returns the portion of Count parameter actually read, so we need to send iNumBytes as Count
2012-06-14 09:06:06 -04:00
}
2014-04-28 13:31:07 -04:00
int cFile : : Write ( const void * iBuffer , size_t iNumBytes )
2012-06-14 09:06:06 -04:00
{
ASSERT ( IsOpen ( ) ) ;
if ( ! IsOpen ( ) )
{
return - 1 ;
}
2014-04-01 08:58:05 -04:00
int res = ( int ) fwrite ( iBuffer , 1 , ( size_t ) iNumBytes , m_File ) ; // fwrite() returns the portion of Count parameter actually written, so we need to send iNumBytes as Count
2012-06-14 09:06:06 -04:00
return res ;
}
int cFile : : Seek ( int iPosition )
{
ASSERT ( IsOpen ( ) ) ;
if ( ! IsOpen ( ) )
{
return - 1 ;
}
if ( fseek ( m_File , iPosition , SEEK_SET ) ! = 0 )
{
return - 1 ;
}
2014-04-01 08:58:05 -04:00
return ( int ) ftell ( m_File ) ;
2012-06-14 09:06:06 -04:00
}
int cFile : : Tell ( void ) const
{
ASSERT ( IsOpen ( ) ) ;
if ( ! IsOpen ( ) )
{
return - 1 ;
}
2014-04-01 08:58:05 -04:00
return ( int ) ftell ( m_File ) ;
2012-06-14 09:06:06 -04:00
}
int cFile : : GetSize ( void ) const
{
ASSERT ( IsOpen ( ) ) ;
if ( ! IsOpen ( ) )
{
return - 1 ;
}
2014-04-01 08:58:05 -04:00
int CurPos = Tell ( ) ;
2012-06-14 09:06:06 -04:00
if ( CurPos < 0 )
{
return - 1 ;
}
if ( fseek ( m_File , 0 , SEEK_END ) ! = 0 )
{
return - 1 ;
}
2014-04-01 08:58:05 -04:00
int res = Tell ( ) ;
2014-04-01 10:00:20 -04:00
if ( fseek ( m_File , ( long ) CurPos , SEEK_SET ) ! = 0 )
2012-06-14 09:06:06 -04:00
{
return - 1 ;
}
return res ;
}
int cFile : : ReadRestOfFile ( AString & a_Contents )
{
ASSERT ( IsOpen ( ) ) ;
if ( ! IsOpen ( ) )
{
return - 1 ;
}
int DataSize = GetSize ( ) - Tell ( ) ;
// HACK: This depends on the internal knowledge that AString's data() function returns the internal buffer directly
2014-04-01 08:58:05 -04:00
a_Contents . assign ( ( size_t ) DataSize , ' \0 ' ) ;
2012-06-14 09:06:06 -04:00
return Read ( ( void * ) a_Contents . data ( ) , DataSize ) ;
}
bool cFile : : Exists ( const AString & a_FileName )
{
cFile test ( a_FileName , fmRead ) ;
return test . IsOpen ( ) ;
}
2012-09-29 09:50:05 -04:00
2013-05-01 12:59:36 -04:00
bool cFile : : Delete ( const AString & a_FileName )
{
return ( remove ( a_FileName . c_str ( ) ) = = 0 ) ;
}
bool cFile : : Rename ( const AString & a_OrigFileName , const AString & a_NewFileName )
{
return ( rename ( a_OrigFileName . c_str ( ) , a_NewFileName . c_str ( ) ) = = 0 ) ;
}
2013-10-09 03:38:47 -04:00
bool cFile : : Copy ( const AString & a_SrcFileName , const AString & a_DstFileName )
{
# ifdef _WIN32
return ( CopyFile ( a_SrcFileName . c_str ( ) , a_DstFileName . c_str ( ) , true ) ! = 0 ) ;
# else
// Other OSs don't have a direct CopyFile equivalent, do it the harder way:
2013-10-09 08:19:14 -04:00
std : : ifstream src ( a_SrcFileName . c_str ( ) , std : : ios : : binary ) ;
std : : ofstream dst ( a_DstFileName . c_str ( ) , std : : ios : : binary ) ;
2013-10-09 03:38:47 -04:00
if ( dst . good ( ) )
{
dst < < src . rdbuf ( ) ;
return true ;
}
else
{
return false ;
}
# endif
}
2013-09-18 12:43:03 -04:00
bool cFile : : IsFolder ( const AString & a_Path )
{
# ifdef _WIN32
2013-10-09 03:57:48 -04:00
DWORD FileAttrib = GetFileAttributes ( a_Path . c_str ( ) ) ;
return ( ( FileAttrib ! = INVALID_FILE_ATTRIBUTES ) & & ( ( FileAttrib & FILE_ATTRIBUTE_DIRECTORY ) ! = 0 ) ) ;
2013-09-18 12:43:03 -04:00
# else
2013-10-09 03:57:48 -04:00
struct stat st ;
return ( ( stat ( a_Path . c_str ( ) , & st ) = = 0 ) & & S_ISDIR ( st . st_mode ) ) ;
2013-09-18 12:43:03 -04:00
# endif
}
2013-10-09 03:38:47 -04:00
bool cFile : : IsFile ( const AString & a_Path )
{
# ifdef _WIN32
2013-10-09 03:57:48 -04:00
DWORD FileAttrib = GetFileAttributes ( a_Path . c_str ( ) ) ;
return ( ( FileAttrib ! = INVALID_FILE_ATTRIBUTES ) & & ( ( FileAttrib & ( FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_DEVICE ) ) = = 0 ) ) ;
2013-10-09 03:38:47 -04:00
# else
2013-10-09 03:57:48 -04:00
struct stat st ;
return ( ( stat ( a_Path . c_str ( ) , & st ) = = 0 ) & & S_ISREG ( st . st_mode ) ) ;
2013-10-09 03:38:47 -04:00
# endif
}
int cFile : : GetSize ( const AString & a_FileName )
{
struct stat st ;
if ( stat ( a_FileName . c_str ( ) , & st ) = = 0 )
{
2014-04-01 08:58:05 -04:00
return ( int ) st . st_size ;
2013-10-09 03:38:47 -04:00
}
return - 1 ;
}
2013-10-09 03:57:48 -04:00
bool cFile : : CreateFolder ( const AString & a_FolderPath )
{
# ifdef _WIN32
return ( CreateDirectory ( a_FolderPath . c_str ( ) , NULL ) ! = 0 ) ;
# else
return ( mkdir ( a_FolderPath . c_str ( ) , S_IRWXU | S_IRWXG | S_IRWXO ) = = 0 ) ;
# endif
}
2013-11-22 14:11:24 -05:00
AStringVector cFile : : GetFolderContents ( const AString & a_Folder )
{
AStringVector AllFiles ;
# ifdef _WIN32
// If the folder name doesn't contain the terminating slash / backslash, add it:
AString FileFilter = a_Folder ;
if (
! FileFilter . empty ( ) & &
( FileFilter [ FileFilter . length ( ) - 1 ] ! = ' \\ ' ) & &
( FileFilter [ FileFilter . length ( ) - 1 ] ! = ' / ' )
)
{
FileFilter . push_back ( ' \\ ' ) ;
}
// Find all files / folders:
FileFilter . append ( " *.* " ) ;
HANDLE hFind ;
WIN32_FIND_DATA FindFileData ;
if ( ( hFind = FindFirstFile ( FileFilter . c_str ( ) , & FindFileData ) ) ! = INVALID_HANDLE_VALUE )
{
do
{
AllFiles . push_back ( FindFileData . cFileName ) ;
} while ( FindNextFile ( hFind , & FindFileData ) ) ;
FindClose ( hFind ) ;
}
# else // _WIN32
DIR * dp ;
struct dirent * dirp ;
2013-11-25 15:24:41 -05:00
AString Folder = a_Folder ;
if ( Folder . empty ( ) )
2013-11-22 14:11:24 -05:00
{
2013-11-25 15:24:41 -05:00
Folder = " . " ;
2013-11-22 14:11:24 -05:00
}
2013-11-25 15:24:41 -05:00
if ( ( dp = opendir ( Folder . c_str ( ) ) ) = = NULL )
2013-11-22 14:11:24 -05:00
{
2013-11-25 15:24:41 -05:00
LOGERROR ( " Error (%i) opening directory \" %s \" \n " , errno , Folder . c_str ( ) ) ;
2013-11-22 14:11:24 -05:00
}
else
{
while ( ( dirp = readdir ( dp ) ) ! = NULL )
{
AllFiles . push_back ( dirp - > d_name ) ;
}
closedir ( dp ) ;
}
# endif // else _WIN32
return AllFiles ;
}
2013-11-23 14:26:00 -05:00
AString cFile : : ReadWholeFile ( const AString & a_FileName )
{
cFile f ;
if ( ! f . Open ( a_FileName , fmRead ) )
{
return " " ;
}
AString Contents ;
f . ReadRestOfFile ( Contents ) ;
return Contents ;
}
2012-09-29 09:50:05 -04:00
int cFile : : Printf ( const char * a_Fmt , . . . )
{
AString buf ;
2014-01-16 02:34:10 -05:00
va_list args ;
2012-09-29 09:50:05 -04:00
va_start ( args , a_Fmt ) ;
2014-01-16 02:34:10 -05:00
AppendVPrintf ( buf , a_Fmt , args ) ;
2012-09-29 09:50:05 -04:00
va_end ( args ) ;
2014-04-01 08:58:05 -04:00
return Write ( buf . c_str ( ) , ( int ) buf . length ( ) ) ;
2012-09-29 09:50:05 -04:00
}
2014-01-25 09:27:34 -05:00
void cFile : : Flush ( void )
{
fflush ( m_File ) ;
}