2009-05-08 13:28:41 +00:00
/*
* OpenClonk , http : //www.openclonk.org
*
2009-06-05 13:41:20 +00:00
* Copyright ( c ) 1998 - 2000 , 2003 - 2004 , 2007 Matthes Bender
2011-09-01 14:58:52 +00:00
* Copyright ( c ) 2002 - 2003 , 2006 - 2009 , 2011 Sven Eberhardt
2009-06-05 13:41:20 +00:00
* Copyright ( c ) 2002 , 2004 - 2005 , 2008 Peter Wortmann
2011-09-01 14:58:52 +00:00
* Copyright ( c ) 2004 - 2006 , 2008 , 2011 G ü nther Brammer
* Copyright ( c ) 2009 - 2011 Nicolas Hake
2010-12-23 00:01:24 +00:00
* Copyright ( c ) 2009 Armin Burgmeier
* Copyright ( c ) 2010 Benjamin Herr
2009-05-08 13:28:41 +00:00
* Copyright ( c ) 2001 - 2009 , RedWolf Design GmbH , http : //www.clonk.de
*
* Portions might be copyrighted by other authors who have contributed
* to OpenClonk .
*
* Permission to use , copy , modify , and / or distribute this software for any
* purpose with or without fee is hereby granted , provided that the above
* copyright notice and this permission notice appear in all copies .
* See isc_license . txt for full license and disclaimer .
*
* " Clonk " is a registered trademark of Matthes Bender .
* See clonk_trademark_license . txt for full license .
*/
/* Lots of file helpers */
2009-10-20 03:39:24 +00:00
# include "C4Include.h"
2009-05-08 13:28:41 +00:00
# include <StdFile.h>
# include <StdBuf.h>
# include <stdio.h>
# ifdef HAVE_IO_H
# include <io.h>
# endif
# ifdef HAVE_DIRECT_H
# include <direct.h>
# endif
# ifdef HAVE_UNISTD_H
# include <unistd.h>
# endif
2011-03-12 14:29:21 +00:00
# ifdef _WIN32
2011-03-13 14:48:45 +00:00
# include <C4windowswrapper.h>
2011-03-12 14:29:21 +00:00
# endif
2009-05-08 13:28:41 +00:00
# include <errno.h>
# include <stdlib.h>
# include <ctype.h>
# include <fcntl.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <zlib.h>
2009-07-10 19:33:55 +00:00
# include <string>
2009-05-08 13:28:41 +00:00
/* Path & Filename */
2009-07-22 03:12:30 +00:00
# ifdef _WIN32
static const char * DirectorySeparators = " / \\ " ;
# else
static const char * DirectorySeparators = " / " ;
# endif
2009-05-08 13:28:41 +00:00
// Return pointer to position after last backslash.
char * GetFilename ( char * szPath )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( ! szPath ) return NULL ;
char * pPos , * pFilename = szPath ;
for ( pPos = szPath ; * pPos ; pPos + + ) if ( * pPos = = DirectorySeparator | | * pPos = = ' / ' ) pFilename = pPos + 1 ;
return pFilename ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
const char * GetFilename ( const char * szPath )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( ! szPath ) return NULL ;
const char * pPos , * pFilename = szPath ;
for ( pPos = szPath ; * pPos ; pPos + + ) if ( * pPos = = DirectorySeparator | | * pPos = = ' / ' ) pFilename = pPos + 1 ;
return pFilename ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
const char * GetFilenameOnly ( const char * strFilename )
{
// Get filename to static buffer
static char strBuffer [ _MAX_PATH + 1 ] ;
SCopy ( GetFilename ( strFilename ) , strBuffer ) ;
// Truncate extension
RemoveExtension ( strBuffer ) ;
// Return buffer
return strBuffer ;
}
const char * GetC4Filename ( const char * szPath )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// returns path to file starting at first .c4*-directory.
if ( ! szPath ) return NULL ;
const char * pPos , * pFilename = szPath ;
for ( pPos = szPath ; * pPos ; pPos + + )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( * pPos = = DirectorySeparator | | * pPos = = ' / ' )
2010-03-28 18:58:01 +00:00
{
2011-05-15 17:32:39 +00:00
if ( pPos > = szPath + 4 & & SEqual2NoCase ( pPos - 4 , " .oc " ) ) return pFilename ;
2009-05-08 13:28:41 +00:00
pFilename = pPos + 1 ;
}
}
2010-03-28 18:58:01 +00:00
return pFilename ;
}
2009-05-08 13:28:41 +00:00
int GetTrailingNumber ( const char * strString )
{
// Default
int iNumber = 0 ;
// Start from end
const char * cpPos = strString + SLen ( strString ) ;
// Walk back while number
while ( ( cpPos > strString ) & & Inside ( * ( cpPos - 1 ) , ' 0 ' , ' 9 ' ) ) cpPos - - ;
// Scan number
sscanf ( cpPos , " %d " , & iNumber ) ;
// Return result
return iNumber ;
}
// Like GetFilename, but searches for a slash instead of a backslash
// (unix-style paths)
char * GetFilenameWeb ( char * szPath )
2010-03-28 18:58:01 +00:00
{
if ( ! szPath ) return NULL ;
2009-05-08 13:28:41 +00:00
char * pPos , * pFilename = szPath ;
for ( pPos = szPath ; * pPos ; pPos + + ) if ( * pPos = = ' / ' ) pFilename = pPos + 1 ;
return pFilename ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
const char * GetFilenameWeb ( const char * szPath )
2010-03-28 18:58:01 +00:00
{
if ( ! szPath ) return NULL ;
2009-05-08 13:28:41 +00:00
const char * pPos , * pFilename = szPath ;
for ( pPos = szPath ; * pPos ; pPos + + ) if ( * pPos = = ' / ' ) pFilename = pPos + 1 ;
return pFilename ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Return pointer to last file extension.
char * GetExtension ( char * szFilename )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
int pos , end ;
for ( end = 0 ; szFilename [ end ] ; end + + ) { }
pos = end ;
while ( ( pos > 0 ) & & ( szFilename [ pos - 1 ] ! = ' . ' ) & & ( szFilename [ pos - 1 ] ! = DirectorySeparator ) ) - - pos ;
if ( ( pos > 0 ) & & szFilename [ pos - 1 ] = = ' . ' ) return szFilename + pos ;
return szFilename + end ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
const char * GetExtension ( const char * szFilename )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
int pos , end ;
for ( end = 0 ; szFilename [ end ] ; end + + ) { }
pos = end ;
while ( ( pos > 0 ) & & ( szFilename [ pos - 1 ] ! = ' . ' ) & & ( szFilename [ pos - 1 ] ! = DirectorySeparator ) ) pos - - ;
if ( szFilename [ pos - 1 ] = = ' . ' ) return szFilename + pos ;
return szFilename + end ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void RealPath ( const char * szFilename , char * pFullFilename )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
# ifdef _WIN32
2011-08-11 13:46:06 +00:00
wchar_t * wpath = _wfullpath ( 0 , GetWideChar ( szFilename ) , 0 ) ;
StdStrBuf path ( wpath ) ;
// I'm pretty sure pFullFilename will always have at least a size of _MAX_PATH, but ughh
// This should return a StdStrBuf
SCopy ( path . getData ( ) , pFullFilename , _MAX_PATH ) ;
free ( wpath ) ;
2009-05-08 13:28:41 +00:00
# else
2010-03-27 16:05:02 +00:00
char * pSuffix = NULL ;
2009-05-08 13:28:41 +00:00
char szCopy [ _MAX_PATH + 1 ] ;
2010-03-28 18:58:01 +00:00
for ( ; ; )
{
2009-05-08 13:28:41 +00:00
// Try to convert to full filename. Note this might fail if the given file doesn't exist
2010-03-28 18:58:01 +00:00
if ( realpath ( szFilename , pFullFilename ) )
2009-05-08 13:28:41 +00:00
break ;
2010-03-27 16:05:02 +00:00
// ... which is undesired behaviour here. Try to reduce the filename until it works.
2010-03-28 18:58:01 +00:00
if ( ! pSuffix )
{
2009-05-08 13:28:41 +00:00
SCopy ( szFilename , szCopy , _MAX_PATH ) ;
szFilename = szCopy ;
pSuffix = szCopy + SLen ( szCopy ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else
* pSuffix = ' / ' ;
2010-03-28 18:58:01 +00:00
while ( pSuffix > = szCopy )
if ( * - - pSuffix = = ' / ' )
2009-05-08 13:28:41 +00:00
break ;
2010-03-28 18:58:01 +00:00
if ( pSuffix < szCopy )
{
2009-05-08 13:28:41 +00:00
// Give up: Just copy whatever we got
SCopy ( szFilename , pFullFilename , _MAX_PATH ) ;
return ;
}
2010-03-28 18:58:01 +00:00
* pSuffix = 0 ;
}
2009-05-08 13:28:41 +00:00
// Append suffix
2010-03-28 18:58:01 +00:00
if ( pSuffix )
{
* pSuffix = ' / ' ;
2009-05-08 13:28:41 +00:00
SAppend ( pSuffix , pFullFilename , _MAX_PATH ) ;
}
2010-03-28 18:58:01 +00:00
# endif
}
2009-05-08 13:28:41 +00:00
// Copy (extended) parent path (without backslash) to target buffer.
bool GetParentPath ( const char * szFilename , char * szBuffer )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Prepare filename
SCopy ( szFilename , szBuffer , _MAX_PATH ) ;
// Extend relative single filenames
2010-03-28 18:58:01 +00:00
# ifdef _WIN32
2009-05-08 13:28:41 +00:00
if ( ! SCharCount ( DirectorySeparator , szFilename ) ) _fullpath ( szBuffer , szFilename , _MAX_PATH ) ;
2010-03-28 18:58:01 +00:00
# else
2009-05-08 13:28:41 +00:00
if ( ! SCharCount ( DirectorySeparator , szFilename ) ) RealPath ( szFilename , szBuffer ) ;
2010-03-28 18:58:01 +00:00
# endif
2009-05-08 13:28:41 +00:00
// Truncate path
return TruncatePath ( szBuffer ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool GetParentPath ( const char * szFilename , StdStrBuf * outBuf )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
char buf [ _MAX_PATH + 1 ] ; * buf = ' \0 ' ;
if ( ! GetParentPath ( szFilename , buf ) ) return false ;
outBuf - > Copy ( buf ) ;
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool GetRelativePath ( const char * strPath , const char * strRelativeTo , char * strBuffer , int iBufferSize )
{
// Specified path is relative to base path
// Copy relative section
const char * szCpy ;
SCopy ( szCpy = GetRelativePathS ( strPath , strRelativeTo ) , strBuffer , iBufferSize ) ;
// return whether it was made relative
return szCpy ! = strPath ;
}
const char * GetRelativePathS ( const char * strPath , const char * strRelativeTo )
{
// Specified path is relative to base path
2010-03-28 18:58:01 +00:00
# ifdef _WIN32
2009-05-08 13:28:41 +00:00
if ( SEqual2NoCase ( strPath , strRelativeTo ) )
2010-03-28 18:58:01 +00:00
# else
2009-05-08 13:28:41 +00:00
if ( SEqual2 ( strPath , strRelativeTo ) )
2010-03-28 18:58:01 +00:00
# endif
2009-05-08 13:28:41 +00:00
{
// return relative section
return strPath + SLen ( strRelativeTo ) + ( ( strPath [ SLen ( strRelativeTo ) ] = = DirectorySeparator ) ? + 1 : 0 ) ;
}
// Not relative: return full path
return strPath ;
}
bool IsGlobalPath ( const char * szPath )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
# ifdef _WIN32
// C:\...
if ( * szPath & & szPath [ 1 ] = = ' : ' ) return true ;
# endif
// /usr/bin, \Temp\, ...
if ( * szPath = = DirectorySeparator ) return true ;
return false ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Truncate string before last backslash.
2010-03-28 18:58:01 +00:00
bool TruncatePath ( char * szPath )
{
2009-05-08 13:28:41 +00:00
if ( ! szPath ) return false ;
int iBSPos ;
iBSPos = SCharLastPos ( DirectorySeparator , szPath ) ;
# ifndef _WIN32
int iBSPos2 ;
iBSPos2 = SCharLastPos ( ' \\ ' , szPath ) ;
if ( iBSPos2 > iBSPos ) fprintf ( stderr , " Warning: TruncatePath with a \\ (%s) \n " , szPath ) ;
# endif
if ( iBSPos < 0 ) return false ;
szPath [ iBSPos ] = 0 ;
return true ;
}
// Append terminating backslash if not present.
void AppendBackslash ( char * szFilename )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
int i = SLen ( szFilename ) ;
2011-09-28 17:44:03 +00:00
if ( i > 0 ) if ( szFilename [ i - 1 ] = = DirectorySeparator ) return ;
2010-03-27 16:05:02 +00:00
SAppendChar ( DirectorySeparator , szFilename ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Remove terminating backslash if present.
void TruncateBackslash ( char * szFilename )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
int i = SLen ( szFilename ) ;
2011-09-28 17:44:03 +00:00
if ( i > 0 ) if ( szFilename [ i - 1 ] = = DirectorySeparator ) szFilename [ i - 1 ] = 0 ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Append extension if no extension.
void DefaultExtension ( char * szFilename , const char * szExtension )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
if ( ! ( * GetExtension ( szFilename ) ) )
{ SAppend ( " . " , szFilename ) ; SAppend ( szExtension , szFilename ) ; }
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void DefaultExtension ( StdStrBuf * sFilename , const char * szExtension )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
assert ( sFilename ) ;
2010-03-27 16:05:02 +00:00
if ( ! ( * GetExtension ( sFilename - > getData ( ) ) ) )
{ sFilename - > AppendChar ( ' . ' ) ; sFilename - > Append ( szExtension ) ; }
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Append or overwrite extension.
void EnforceExtension ( char * szFilename , const char * szExtension )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
char * ext = GetExtension ( szFilename ) ;
2010-03-28 18:58:01 +00:00
if ( ext [ 0 ] ) { SCopy ( szExtension , ext ) ; }
2009-05-08 13:28:41 +00:00
else { SAppend ( " . " , szFilename ) ; SAppend ( szExtension , szFilename ) ; }
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void EnforceExtension ( StdStrBuf * sFilename , const char * szExtension )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
assert ( sFilename ) ;
const char * ext = GetExtension ( sFilename - > getData ( ) ) ;
2010-03-28 18:58:01 +00:00
if ( ext [ 0 ] ) { sFilename - > ReplaceEnd ( ext - sFilename - > getData ( ) , szExtension ) ; }
2009-05-08 13:28:41 +00:00
else { sFilename - > AppendChar ( ' . ' ) ; sFilename - > Append ( szExtension ) ; }
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// remove extension
void RemoveExtension ( char * szFilename )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
char * ext = GetExtension ( szFilename ) ;
2010-03-27 16:05:02 +00:00
if ( ext [ 0 ] ) ext [ - 1 ] = 0 ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void RemoveExtension ( StdStrBuf * psFileName )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( psFileName & & * psFileName )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
RemoveExtension ( psFileName - > getMData ( ) ) ;
psFileName - > SetLength ( strlen ( psFileName - > getData ( ) ) ) ;
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Enforce indexed extension until item does not exist.
void MakeTempFilename ( char * szFilename )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
DefaultExtension ( szFilename , " tmp " ) ;
char * fn_ext = GetExtension ( szFilename ) ;
int cnum = - 1 ;
do
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
cnum + + ;
osprintf ( fn_ext , " %03d " , cnum ) ;
}
2010-03-28 18:58:01 +00:00
while ( FileExists ( szFilename ) & & ( cnum < 999 ) ) ;
}
2009-05-08 13:28:41 +00:00
void MakeTempFilename ( StdStrBuf * sFilename )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
assert ( sFilename ) ;
if ( ! sFilename - > getLength ( ) ) sFilename - > Copy ( " temp.tmp " ) ;
EnforceExtension ( sFilename , " tmp " ) ;
2010-03-27 16:05:02 +00:00
char * fn_ext = GetExtension ( sFilename - > getMData ( ) ) ;
int cnum = - 1 ;
do
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
cnum + + ;
osprintf ( fn_ext , " %03d " , cnum ) ;
2009-05-08 13:28:41 +00:00
}
2010-03-28 18:58:01 +00:00
while ( FileExists ( sFilename - > getData ( ) ) & & ( cnum < 999 ) ) ;
}
2009-05-08 13:28:41 +00:00
bool WildcardListMatch ( const char * szWildcardList , const char * szString )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// safety
2010-03-28 18:58:01 +00:00
if ( ! szString | | ! szWildcardList ) return false ;
2009-05-08 13:28:41 +00:00
// match any item in list
StdStrBuf sWildcard , sWildcardList ( szWildcardList ) ;
int32_t i = 0 ;
while ( sWildcardList . GetSection ( i + + , & sWildcard , ' | ' ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( WildcardMatch ( sWildcard . getData ( ) , szString ) ) return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// none matched
return false ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2009-06-16 00:38:39 +00:00
bool IsWildcardString ( const char * szString )
2010-03-28 18:58:01 +00:00
{
2009-06-16 00:38:39 +00:00
// safety
2010-03-28 18:58:01 +00:00
if ( ! szString ) return false ;
2009-06-16 00:38:39 +00:00
// known wildcard characters: *?
return ( SCharCount ( ' ? ' , szString ) > 0 ) | | ( SCharCount ( ' * ' , szString ) > 0 ) ;
2010-03-28 18:58:01 +00:00
}
2009-06-16 00:38:39 +00:00
2009-05-08 13:28:41 +00:00
bool WildcardMatch ( const char * szWildcard , const char * szString )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// safety
2010-03-28 18:58:01 +00:00
if ( ! szString | | ! szWildcard ) return false ;
2010-03-27 16:05:02 +00:00
// match char-wise
const char * pWild = szWildcard , * pPos = szString ;
const char * pLWild = NULL , * pLPos = NULL ; // backtracking
2010-03-28 18:58:01 +00:00
while ( * pWild | | pLWild )
2010-03-27 16:05:02 +00:00
// string wildcard?
2010-03-28 18:58:01 +00:00
if ( * pWild = = ' * ' )
2010-03-27 16:05:02 +00:00
{ pLWild = + + pWild ; pLPos = pPos ; }
2010-03-28 18:58:01 +00:00
// nothing left to match?
else if ( ! * pPos )
2010-03-27 16:05:02 +00:00
break ;
2010-03-28 18:58:01 +00:00
// equal or one-character-wildcard? proceed
else if ( * pWild = = ' ? ' | | tolower ( * pWild ) = = tolower ( * pPos ) )
2010-03-27 16:05:02 +00:00
{ pWild + + ; pPos + + ; }
2010-03-28 18:58:01 +00:00
// backtrack possible?
else if ( pLPos )
2010-03-27 16:05:02 +00:00
{ pWild = pLWild ; pPos = + + pLPos ; }
2010-03-28 18:58:01 +00:00
// match failed
2010-03-27 16:05:02 +00:00
else
return false ;
// match complete if both strings are fully matched
return ! * pWild & & ! * pPos ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// create a valid file name from some title
void MakeFilenameFromTitle ( char * szTitle )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// copy all chars but those to be stripped
char * szFilename = szTitle , * szTitle2 = szTitle ;
while ( * szTitle2 )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
bool fStrip ;
if ( IsWhiteSpace ( * szTitle2 ) )
fStrip = ( szFilename = = szTitle ) ;
2011-09-07 12:22:35 +00:00
else if ( static_cast < unsigned int > ( * szTitle2 ) > 127 )
fStrip = true ;
2009-05-08 13:28:41 +00:00
else
2011-09-07 12:22:35 +00:00
fStrip = ( SCharPos ( * szTitle2 , " ! \" '%&/=?+*#:;<> \\ . " ) > = 0 ) ;
2009-05-08 13:28:41 +00:00
if ( ! fStrip ) * szFilename + + = * szTitle2 ;
+ + szTitle2 ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// truncate spaces from end
while ( IsWhiteSpace ( * - - szFilename ) ) if ( szFilename = = szTitle ) { - - szFilename ; break ; }
// terminate
* + + szFilename = 0 ;
// no name? (only invalid chars)
if ( ! * szTitle ) SCopy ( " unnamed " , szTitle , 50 ) ;
// done
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
/* Files */
bool FileExists ( const char * szFilename )
2010-03-28 18:58:01 +00:00
{
2011-08-11 13:46:06 +00:00
# ifdef _WIN32
return GetFileAttributes ( GetWideChar ( szFilename ) ) ! = INVALID_FILE_ATTRIBUTES ;
# else
2009-05-08 13:28:41 +00:00
return ( ! access ( szFilename , F_OK ) ) ;
2011-08-11 13:46:06 +00:00
# endif
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
size_t FileSize ( const char * szFilename )
2010-03-28 18:58:01 +00:00
{
2011-08-14 16:16:19 +00:00
# if defined(_WIN32) || defined(_WIN64)
2011-08-11 13:46:06 +00:00
WIN32_FILE_ATTRIBUTE_DATA attributes = { 0 } ;
if ( GetFileAttributesEx ( GetWideChar ( szFilename ) , GetFileExInfoStandard , & attributes ) = = 0 )
return 0 ;
2011-08-14 16:16:19 +00:00
# ifdef _WIN64
2011-08-11 13:46:06 +00:00
return ( static_cast < size_t > ( attributes . nFileSizeHigh ) < < ( sizeof ( attributes . nFileSizeLow ) * 8 ) ) | attributes . nFileSizeLow ;
2011-08-14 16:16:19 +00:00
# else
return attributes . nFileSizeLow ;
# endif
2011-08-11 13:46:06 +00:00
# else
2009-05-08 13:28:41 +00:00
struct stat stStats ;
if ( stat ( szFilename , & stStats ) ) return 0 ;
return stStats . st_size ;
2011-08-11 13:46:06 +00:00
# endif
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// operates on a filedescriptor from open or fileno
size_t FileSize ( int fdes )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
# ifdef _WIN32
2011-08-14 16:16:19 +00:00
return _filelength ( fdes ) ;
2009-05-08 13:28:41 +00:00
# else
struct stat stStats ;
if ( fstat ( fdes , & stStats ) ) return 0 ;
return stStats . st_size ;
# endif
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
int FileTime ( const char * szFilename )
2010-03-28 18:58:01 +00:00
{
2011-08-11 13:46:06 +00:00
# ifdef _WIN32
WIN32_FILE_ATTRIBUTE_DATA attributes = { 0 } ;
if ( GetFileAttributesEx ( GetWideChar ( szFilename ) , GetFileExInfoStandard , & attributes ) = = 0 )
return 0 ;
int64_t ft = ( static_cast < int64_t > ( attributes . ftLastWriteTime . dwHighDateTime ) < < ( sizeof ( attributes . ftLastWriteTime . dwLowDateTime ) * 8 ) ) | attributes . ftLastWriteTime . dwLowDateTime ;
ft - = 116444736000000000 ;
ft / = 10000000 ;
return ft ;
# else
2009-05-08 13:28:41 +00:00
struct stat stStats ;
if ( stat ( szFilename , & stStats ) ! = 0 ) return 0 ;
return stStats . st_mtime ;
2011-08-11 13:46:06 +00:00
# endif
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool EraseFile ( const char * szFilename )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
# ifdef _WIN32
2011-04-02 16:45:44 +00:00
SetFileAttributesW ( GetWideChar ( szFilename ) , FILE_ATTRIBUTE_NORMAL ) ;
2011-08-11 13:46:06 +00:00
if ( DeleteFileW ( GetWideChar ( szFilename ) ) = = 0 )
{
switch ( GetLastError ( ) )
{
case ERROR_PATH_NOT_FOUND :
case ERROR_FILE_NOT_FOUND :
// While deleting it didn't work, the file doesn't exist (anymore).
// Pretend everything is fine.
return true ;
default :
// Some other error left us unable to delete the file.
return false ;
}
}
return true ;
# else
2009-05-08 13:28:41 +00:00
// either unlink or remove could be used. Well, stick to ANSI C where possible.
if ( remove ( szFilename ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( errno = = ENOENT )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Hah, here the wrapper actually makes sense:
// The engine only cares about the file not being there after this call.
return true ;
}
2010-03-28 18:58:01 +00:00
return false ;
2009-05-08 13:28:41 +00:00
}
2010-03-28 18:58:01 +00:00
return true ;
2011-08-11 13:46:06 +00:00
# endif
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
# ifndef _WIN32
bool CopyFile ( const char * szSource , const char * szTarget , bool FailIfExists )
2010-03-28 18:58:01 +00:00
{
2012-03-05 00:33:02 +00:00
int fds = open ( szSource , O_RDONLY | O_CLOEXEC ) ;
2009-05-08 13:28:41 +00:00
if ( ! fds ) return false ;
struct stat info ; fstat ( fds , & info ) ;
2012-03-05 00:33:02 +00:00
int fdt = open ( szTarget , O_CLOEXEC | O_WRONLY | O_CREAT | ( FailIfExists ? O_EXCL : O_TRUNC ) , info . st_mode ) ;
2009-05-08 13:28:41 +00:00
if ( ! fdt )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
close ( fds ) ;
return false ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
char buffer [ 1024 ] ; ssize_t l ;
2010-01-25 04:00:59 +00:00
while ( ( l = read ( fds , buffer , sizeof ( buffer ) ) ) > 0 )
if ( write ( fdt , buffer , l ) < l )
2010-03-28 18:58:01 +00:00
{
l = - 1 ;
break ;
}
2009-05-08 13:28:41 +00:00
close ( fds ) ;
close ( fdt ) ;
// On error, return false
return l ! = - 1 ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool RenameFile ( const char * szFilename , const char * szNewFilename )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( rename ( szFilename , szNewFilename ) < 0 )
2010-03-28 18:58:01 +00:00
{
2011-04-02 16:45:44 +00:00
if ( errno ! = EXDEV ) return false ;
2009-05-08 13:28:41 +00:00
if ( CopyFile ( szFilename , szNewFilename , false ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
return EraseFile ( szFilename ) ;
}
2010-03-28 18:58:01 +00:00
return false ;
2009-05-08 13:28:41 +00:00
}
2010-03-28 18:58:01 +00:00
return true ;
}
2011-04-02 16:45:44 +00:00
# else
# undef CopyFile
bool CopyFile ( const char * szSource , const char * szTarget , bool FailIfExists )
{
2011-08-14 16:16:19 +00:00
return ! ! CopyFileW ( GetWideChar ( szSource ) , GetWideChar ( szTarget ) , FailIfExists ) ;
2011-04-02 16:45:44 +00:00
}
bool RenameFile ( const char * szFilename , const char * szNewFilename )
{
2011-08-14 16:16:19 +00:00
return ! ! MoveFileExW ( GetWideChar ( szFilename ) , GetWideChar ( szNewFilename ) , MOVEFILE_COPY_ALLOWED ) ;
2011-04-02 16:45:44 +00:00
}
# endif
2009-05-08 13:28:41 +00:00
bool MakeOriginalFilename ( char * szFilename )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// safety
if ( ! szFilename ) return false ;
# ifdef _WIN32
// root-directory?
2010-04-21 19:12:49 +00:00
if ( Inside ( SLen ( szFilename ) , 2u , 3u ) ) if ( szFilename [ 1 ] = = ' : ' )
2009-05-08 13:28:41 +00:00
{
2010-03-28 18:58:01 +00:00
szFilename [ 2 ] = ' \\ ' ; szFilename [ 3 ] = 0 ;
2011-04-02 16:45:44 +00:00
if ( GetDriveTypeW ( GetWideChar ( szFilename ) ) = = DRIVE_NO_ROOT_DIR ) return false ;
2010-03-28 18:58:01 +00:00
return true ;
2009-05-08 13:28:41 +00:00
}
2011-08-11 13:46:06 +00:00
struct _wfinddata_t fdt ; long shnd ;
if ( ( shnd = _wfindfirst ( GetWideChar ( szFilename ) , & fdt ) ) < 0 ) return false ;
2009-05-08 13:28:41 +00:00
_findclose ( shnd ) ;
2011-08-11 13:46:06 +00:00
StdStrBuf name ( fdt . name ) ;
SCopy ( GetFilename ( name . getData ( ) ) , GetFilename ( szFilename ) , _MAX_FNAME ) ;
2009-05-08 13:28:41 +00:00
# else
2010-03-28 18:58:01 +00:00
if ( SCharPos ( ' * ' , szFilename ) ! = - 1 )
{
2009-05-08 13:28:41 +00:00
fputs ( " Warning: MakeOriginalFilename with \" " , stderr ) ;
fputs ( szFilename , stderr ) ;
fputs ( " \" ! \n " , stderr ) ;
}
# endif
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
/* Directories */
const char * GetWorkingDirectory ( )
2010-03-28 18:58:01 +00:00
{
2011-08-11 13:46:06 +00:00
# ifdef _WIN32
static char * buffer = 0 ;
if ( buffer ) StdBuf : : DeletePointer ( buffer ) ;
wchar_t * widebuf = 0 ;
DWORD widebufsz = GetCurrentDirectoryW ( 0 , 0 ) ;
widebuf = new wchar_t [ widebufsz ] ;
if ( GetCurrentDirectoryW ( widebufsz , widebuf ) = = 0 ) {
delete [ ] widebuf ;
return 0 ;
}
StdStrBuf path ( widebuf ) ;
delete [ ] widebuf ;
return buffer = path . GrabPointer ( ) ;
# else
2010-03-27 16:05:02 +00:00
static char buf [ _MAX_PATH + 1 ] ;
return getcwd ( buf , _MAX_PATH ) ;
2011-08-11 13:46:06 +00:00
# endif
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool SetWorkingDirectory ( const char * path )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
# ifdef _WIN32
2011-04-02 16:45:44 +00:00
return SetCurrentDirectoryW ( GetWideChar ( path ) ) ! = 0 ;
2009-05-08 13:28:41 +00:00
# else
2010-03-27 16:05:02 +00:00
return ( chdir ( path ) = = 0 ) ;
2009-05-08 13:28:41 +00:00
# endif
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2009-07-10 19:33:55 +00:00
bool CreatePath ( const std : : string & path )
{
assert ( ! path . empty ( ) ) ;
# ifdef _WIN32
2011-04-02 16:45:44 +00:00
if ( CreateDirectoryW ( GetWideChar ( path . c_str ( ) ) , NULL ) )
2009-06-06 15:20:17 +00:00
{
2009-07-11 18:03:12 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
else
{
2009-07-10 19:33:55 +00:00
DWORD err = GetLastError ( ) ;
2010-03-28 18:58:01 +00:00
switch ( err )
2009-06-06 15:20:17 +00:00
{
2009-07-10 19:33:55 +00:00
case ERROR_PATH_NOT_FOUND :
break ;
case ERROR_ALREADY_EXISTS :
return true ;
default :
// Something major has happened: Log
2010-03-28 18:58:01 +00:00
{
2011-04-02 16:45:44 +00:00
wchar_t * str ;
if ( FormatMessageW ( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS ,
NULL , err , 0 , ( LPWSTR ) & str , 0 , NULL ) )
2009-06-06 15:20:17 +00:00
{
2011-04-02 16:45:44 +00:00
LogF ( " CreateDirectory failed: %s " , StdStrBuf ( str ) . getData ( ) ) ;
2010-03-28 18:58:01 +00:00
LocalFree ( str ) ;
2009-06-06 15:20:17 +00:00
}
2010-03-28 18:58:01 +00:00
return false ;
}
2009-06-06 15:20:17 +00:00
}
2009-07-10 19:33:55 +00:00
}
# else
if ( ! mkdir ( path . c_str ( ) , S_IREAD | S_IWRITE | S_IEXEC ) )
return true ;
2010-03-28 18:58:01 +00:00
switch ( errno )
2009-07-10 19:33:55 +00:00
{
case ENOENT :
break ;
case EEXIST :
// FIXME: Check whether the path is blocked by a non-directory
return true ;
default :
return false ;
2009-06-06 15:20:17 +00:00
}
2009-05-08 13:28:41 +00:00
# endif
2009-07-10 19:33:55 +00:00
// Recursively create parent path
std : : string : : size_type slash = path . find_last_of ( DirectorySeparators ) ;
if ( slash = = 0 | | slash = = std : : string : : npos )
return false ;
return CreatePath ( path . substr ( 0 , slash ) ) & & CreatePath ( path ) ;
}
2009-05-08 13:28:41 +00:00
bool DirectoryExists ( const char * szFilename )
2010-03-28 18:58:01 +00:00
{
2009-09-23 02:09:13 +00:00
// Ignore trailing slash or backslash, except when we are probing the
// root directory '/'.
2009-05-08 13:28:41 +00:00
char bufFilename [ _MAX_PATH + 1 ] ;
if ( szFilename & & szFilename [ 0 ] )
2009-09-23 02:09:13 +00:00
{
unsigned int len = SLen ( szFilename ) ;
if ( len > 1 & & ( ( szFilename [ len - 1 ] = = ' \\ ' ) | | ( szFilename [ len - 1 ] = = ' / ' ) ) )
2009-05-08 13:28:41 +00:00
{
SCopy ( szFilename , bufFilename , _MAX_PATH ) ;
bufFilename [ SLen ( bufFilename ) - 1 ] = 0 ;
szFilename = bufFilename ;
}
2009-09-23 02:09:13 +00:00
}
2009-05-08 13:28:41 +00:00
// Check file attributes
# ifdef _WIN32
2011-08-11 13:46:06 +00:00
struct _wfinddata_t fdt ; int shnd ;
if ( ( shnd = _wfindfirst ( GetWideChar ( szFilename ) , & fdt ) ) < 0 ) return false ;
2009-05-08 13:28:41 +00:00
_findclose ( shnd ) ;
if ( fdt . attrib & _A_SUBDIR ) return true ;
# else
struct stat stStats ;
if ( stat ( szFilename , & stStats ) ! = 0 ) return 0 ;
return ( S_ISDIR ( stStats . st_mode ) ) ;
# endif
return false ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2010-03-28 18:58:01 +00:00
bool CopyDirectory ( const char * szSource , const char * szTarget , bool fResetAttributes )
{
2009-05-08 13:28:41 +00:00
// Source check
if ( ! szSource | | ! szTarget ) return false ;
if ( ! DirectoryExists ( szSource ) ) return false ;
// Do not process system navigation directories
if ( SEqual ( GetFilename ( szSource ) , " . " )
2010-03-28 18:58:01 +00:00
| | SEqual ( GetFilename ( szSource ) , " .. " ) )
2009-05-08 13:28:41 +00:00
return true ;
// Overwrite target
//if (ItemExists(szTarget))
if ( ! EraseItem ( szTarget ) ) return false ;
// Create target directory
bool status = true ;
2010-03-28 18:58:01 +00:00
# ifdef _WIN32
2011-08-11 13:46:06 +00:00
if ( _wmkdir ( GetWideChar ( szTarget ) ) ! = 0 ) return false ;
2009-05-08 13:28:41 +00:00
// Copy contents to target directory
char contents [ _MAX_PATH + 1 ] ;
SCopy ( szSource , contents ) ; AppendBackslash ( contents ) ;
SAppend ( " * " , contents ) ;
2011-08-11 13:46:06 +00:00
_wfinddata_t fdt ; int hfdt ;
if ( ( hfdt = _wfindfirst ( GetWideChar ( contents ) , & fdt ) ) > - 1 )
2010-03-28 18:58:01 +00:00
{
do
{
2009-05-08 13:28:41 +00:00
char itemsource [ _MAX_PATH + 1 ] , itemtarget [ _MAX_PATH + 1 ] ;
2011-08-11 13:46:06 +00:00
SCopy ( szSource , itemsource ) ; AppendBackslash ( itemsource ) ; SAppend ( StdStrBuf ( fdt . name ) . getData ( ) , itemsource ) ;
SCopy ( szTarget , itemtarget ) ; AppendBackslash ( itemtarget ) ; SAppend ( StdStrBuf ( fdt . name ) . getData ( ) , itemtarget ) ;
2009-05-08 13:28:41 +00:00
if ( ! CopyItem ( itemsource , itemtarget , fResetAttributes ) ) status = false ;
}
2011-08-11 13:46:06 +00:00
while ( _wfindnext ( hfdt , & fdt ) = = 0 ) ;
2009-05-08 13:28:41 +00:00
_findclose ( hfdt ) ;
}
2010-03-28 18:58:01 +00:00
# else
2009-05-08 13:28:41 +00:00
if ( mkdir ( szTarget , 0777 ) ! = 0 ) return false ;
DIR * d = opendir ( szSource ) ;
dirent * ent ;
char itemsource [ _MAX_PATH + 1 ] , itemtarget [ _MAX_PATH + 1 ] ;
2010-03-28 18:58:01 +00:00
while ( ( ent = readdir ( d ) ) )
{
2009-05-08 13:28:41 +00:00
SCopy ( szSource , itemsource ) ; AppendBackslash ( itemsource ) ; SAppend ( ent - > d_name , itemsource ) ;
SCopy ( szTarget , itemtarget ) ; AppendBackslash ( itemtarget ) ; SAppend ( ent - > d_name , itemtarget ) ;
if ( ! CopyItem ( itemsource , itemtarget , fResetAttributes ) ) status = false ;
}
closedir ( d ) ;
2010-03-28 18:58:01 +00:00
# endif
2009-05-08 13:28:41 +00:00
return status ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2010-03-28 18:58:01 +00:00
bool EraseDirectory ( const char * szDirName )
{
2009-05-08 13:28:41 +00:00
// Do not process system navigation directories
if ( SEqual ( GetFilename ( szDirName ) , " . " )
2010-03-28 18:58:01 +00:00
| | SEqual ( GetFilename ( szDirName ) , " .. " ) )
2009-05-08 13:28:41 +00:00
return true ;
char path [ _MAX_PATH + 1 ] ;
# ifdef _WIN32
// Get path to directory contents
SCopy ( szDirName , path ) ; SAppend ( " \\ *.* " , path ) ;
// Erase subdirectories and files
ForEachFile ( path , & EraseItem ) ;
# else
DIR * d = opendir ( szDirName ) ;
dirent * ent ;
2010-03-28 18:58:01 +00:00
while ( ( ent = readdir ( d ) ) )
{
2009-05-08 13:28:41 +00:00
SCopy ( szDirName , path ) ; AppendBackslash ( path ) ; SAppend ( ent - > d_name , path ) ;
if ( ! EraseItem ( path ) ) return false ;
}
closedir ( d ) ;
# endif
// Check working directory
2010-03-28 18:58:01 +00:00
if ( SEqual ( szDirName , GetWorkingDirectory ( ) ) )
{
2009-05-08 13:28:41 +00:00
// Will work only if szDirName is full path and correct case!
SCopy ( GetWorkingDirectory ( ) , path ) ;
int lbacks = SCharLastPos ( DirectorySeparator , path ) ;
2010-03-28 18:58:01 +00:00
if ( lbacks > - 1 )
{
2009-05-08 13:28:41 +00:00
path [ lbacks ] = 0 ; SetWorkingDirectory ( path ) ;
}
}
// Remove directory
//chmod(szDirName,200);
# ifdef _WIN32
2011-04-02 16:45:44 +00:00
return ! ! RemoveDirectoryW ( GetWideChar ( szDirName ) ) ;
2009-05-08 13:28:41 +00:00
# else
return ( rmdir ( szDirName ) = = 0 | | errno = = ENOENT ) ;
# endif
}
/* Items */
/*int ItemAttributes(const char *szItemName)
2010-03-28 18:58:01 +00:00
{
return FileAttributes ( szItemName ) ;
} */
2009-05-08 13:28:41 +00:00
bool RenameItem ( const char * szItemName , const char * szNewItemName )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// FIXME: What if the directory would have to be copied?
return RenameFile ( szItemName , szNewItemName ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool EraseItem ( const char * szItemName )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
if ( ! EraseFile ( szItemName ) ) return EraseDirectory ( szItemName ) ;
else return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool CreateItem ( const char * szItemname )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Overwrite any old item
EraseItem ( szItemname ) ;
// Create dummy item
2010-03-27 16:05:02 +00:00
FILE * fhnd ;
2011-08-11 13:46:06 +00:00
# ifdef _WIN32
if ( ! ( fhnd = _wfopen ( GetWideChar ( szItemname ) , L " wb " ) ) ) return false ;
# else
2010-03-27 16:05:02 +00:00
if ( ! ( fhnd = fopen ( szItemname , " wb " ) ) ) return false ;
2011-08-11 13:46:06 +00:00
# endif
2010-03-27 16:05:02 +00:00
fclose ( fhnd ) ;
2009-05-08 13:28:41 +00:00
// Success
return true ;
2010-03-28 18:58:01 +00:00
}
2011-11-02 20:34:04 +00:00
2009-05-08 13:28:41 +00:00
bool CopyItem ( const char * szSource , const char * szTarget , bool fResetAttributes )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Check for identical source and target
if ( ItemIdentical ( szSource , szTarget ) ) return true ;
// Copy directory
if ( DirectoryExists ( szSource ) )
return CopyDirectory ( szSource , szTarget , fResetAttributes ) ;
// Copy file
if ( ! CopyFile ( szSource , szTarget , false ) ) return false ;
// Reset any attributes if desired
# ifdef _WIN32
2011-04-02 16:45:44 +00:00
if ( fResetAttributes ) if ( ! SetFileAttributesW ( GetWideChar ( szTarget ) , FILE_ATTRIBUTE_NORMAL ) ) return false ;
2009-05-08 13:28:41 +00:00
# else
if ( fResetAttributes ) if ( chmod ( szTarget , S_IRWXU ) ) return false ;
# endif
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool MoveItem ( const char * szSource , const char * szTarget )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( ItemIdentical ( szSource , szTarget ) ) return true ;
return RenameFile ( szSource , szTarget ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool ItemIdentical ( const char * szFilename1 , const char * szFilename2 )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
char szFullFile1 [ _MAX_PATH + 1 ] , szFullFile2 [ _MAX_PATH + 1 ] ;
RealPath ( szFilename1 , szFullFile1 ) ; RealPath ( szFilename2 , szFullFile2 ) ;
# ifdef _WIN32
if ( SEqualNoCase ( szFullFile1 , szFullFile2 ) ) return true ;
# else
if ( SEqual ( szFullFile1 , szFullFile2 ) ) return true ;
# endif
return false ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
//------------------------- Multi File Processing --------------------------------------------------------------------------------------------------------
2010-01-25 15:54:38 +00:00
struct DirectoryIteratorP
{
DirectoryIteratorP ( ) : ref ( 1 ) { }
DirectoryIterator : : FileList files ;
std : : string directory ;
int ref ;
} ;
DirectoryIterator : : DirectoryIterator ( )
2010-03-28 18:58:01 +00:00
: p ( new DirectoryIteratorP ) , iter ( p - > files . end ( ) )
2010-01-25 15:54:38 +00:00
{ }
DirectoryIterator : : DirectoryIterator ( const DirectoryIterator & other )
2011-03-30 19:11:37 +00:00
: p ( other . p ) , iter ( other . iter )
2010-01-25 15:54:38 +00:00
{
+ + p - > ref ;
}
2011-03-30 19:04:42 +00:00
DirectoryIterator & DirectoryIterator : : operator = ( const DirectoryIterator & other )
{
p = other . p ; iter = other . iter ;
+ + p - > ref ;
return * this ;
}
2010-01-25 15:54:38 +00:00
DirectoryIterator : : ~ DirectoryIterator ( )
{
if ( - - p - > ref = = 0 )
delete p ;
}
2009-05-08 13:28:41 +00:00
2010-01-25 15:54:38 +00:00
void DirectoryIterator : : Reset ( )
{
iter = p - > files . begin ( ) ;
2009-05-08 13:28:41 +00:00
}
2010-01-25 15:54:38 +00:00
void DirectoryIterator : : Reset ( const char * dirname )
{
if ( p - > directory = = dirname )
{
// Skip reinitialisation and just reset the iterator
iter = p - > files . begin ( ) ;
return ;
2009-05-08 13:28:41 +00:00
}
2010-01-25 15:54:38 +00:00
if ( p - > ref > 1 )
{
// Detach from shared memory
- - p - > ref ;
p = new DirectoryIteratorP ;
2009-05-08 13:28:41 +00:00
}
2010-01-25 15:54:38 +00:00
p - > files . clear ( ) ;
iter = p - > files . end ( ) ;
Read ( dirname ) ;
2009-05-08 13:28:41 +00:00
}
2010-01-25 15:54:38 +00:00
DirectoryIterator : : DirectoryIterator ( const char * dirname )
2010-03-28 18:58:01 +00:00
: p ( new DirectoryIteratorP ) , iter ( p - > files . end ( ) )
2010-01-25 15:54:38 +00:00
{
Read ( dirname ) ;
2009-05-08 13:28:41 +00:00
}
2010-01-25 15:54:38 +00:00
void DirectoryIterator : : Read ( const char * dirname )
{
assert ( dirname & & * dirname ) ;
assert ( p - > files . empty ( ) ) ;
std : : string search_path ( dirname ) ;
search_path . push_back ( DirectorySeparator ) ;
# ifdef WIN32
2011-04-02 16:45:44 +00:00
WIN32_FIND_DATAW file = { 0 } ;
HANDLE fh = FindFirstFileW ( GetWideChar ( ( search_path + ' * ' ) . c_str ( ) ) , & file ) ;
2010-01-25 15:54:38 +00:00
if ( fh = = INVALID_HANDLE_VALUE )
{
switch ( GetLastError ( ) )
{
2012-01-28 17:15:51 +00:00
case ERROR_PATH_NOT_FOUND :
2010-01-25 15:54:38 +00:00
case ERROR_FILE_NOT_FOUND :
// This is okay, either the directory doesn't exist or there are no files
return ;
default :
// Something else broke
2011-10-28 23:16:13 +00:00
Log ( " DirectoryIterator::Read(const char*): Unable to read file system " ) ;
return ;
2010-01-25 15:54:38 +00:00
}
2009-05-08 13:28:41 +00:00
}
2010-01-25 15:54:38 +00:00
// Insert files into list
do
{
// ...unless they're . or ..
if ( file . cFileName [ 0 ] = = ' . ' & & ( file . cFileName [ 1 ] = = ' \0 ' | | ( file . cFileName [ 1 ] = = ' . ' & & file . cFileName [ 2 ] = = ' \0 ' ) ) )
continue ;
2011-04-02 16:45:44 +00:00
p - > files . push_back ( StdStrBuf ( file . cFileName ) . getData ( ) ) ;
2010-03-28 18:58:01 +00:00
}
2011-04-02 16:45:44 +00:00
while ( FindNextFileW ( fh , & file ) ) ;
2010-01-25 15:54:38 +00:00
FindClose ( fh ) ;
2009-05-08 13:28:41 +00:00
# else
2010-01-25 15:54:38 +00:00
DIR * fh = opendir ( dirname ) ;
if ( fh = = NULL )
{
switch ( errno )
{
case ENOENT :
case ENOTDIR :
// Okay, so there's no files here.
return ;
default :
// Something else broke
2011-10-28 23:16:13 +00:00
Log ( " DirectoryIterator::Read(const char*): Unable to read file system " ) ;
return ;
2010-01-25 15:54:38 +00:00
}
2009-05-08 13:28:41 +00:00
}
2010-01-25 15:54:38 +00:00
dirent * file ;
// Insert files into list
while ( ( file = readdir ( fh ) ) ! = NULL )
{
// ...unless they're . or ..
if ( file - > d_name [ 0 ] = = ' . ' & & ( file - > d_name [ 1 ] = = ' \0 ' | | ( file - > d_name [ 1 ] = = ' . ' & & file - > d_name [ 2 ] = = ' \0 ' ) ) )
continue ;
2010-01-25 19:17:29 +00:00
p - > files . push_back ( file - > d_name ) ;
2010-01-25 15:54:38 +00:00
}
closedir ( fh ) ;
# endif
// Sort list
std : : sort ( p - > files . begin ( ) , p - > files . end ( ) ) ;
for ( FileList : : iterator it = p - > files . begin ( ) ; it ! = p - > files . end ( ) ; + + it )
it - > insert ( 0 , search_path ) ; // prepend path to all file entries
iter = p - > files . begin ( ) ;
p - > directory = dirname ;
2009-05-08 13:28:41 +00:00
}
2010-01-25 15:54:38 +00:00
DirectoryIterator & DirectoryIterator : : operator + + ( )
{
2010-03-28 18:58:01 +00:00
if ( iter ! = p - > files . end ( ) )
2010-01-25 15:54:38 +00:00
+ + iter ;
2009-05-08 13:28:41 +00:00
return * this ;
}
2010-01-25 15:54:38 +00:00
const char * DirectoryIterator : : operator * ( ) const
{
if ( iter = = p - > files . end ( ) )
return NULL ;
return iter - > c_str ( ) ;
}
DirectoryIterator DirectoryIterator : : operator + + ( int )
{
DirectoryIterator tmp ( * this ) ;
+ + * this ;
return tmp ;
2009-05-08 13:28:41 +00:00
}
2010-03-28 18:58:01 +00:00
int ForEachFile ( const char * szDirName , bool ( * fnCallback ) ( const char * ) )
{
2009-05-08 13:28:41 +00:00
if ( ! szDirName | | ! fnCallback )
return 0 ;
char szFilename [ _MAX_PATH + 1 ] ;
SCopy ( szDirName , szFilename ) ;
bool fHasWildcard = ( SCharPos ( ' * ' , szFilename ) > = 0 ) ;
if ( ! fHasWildcard ) // parameter without wildcard: Append "/*.*" or "\*.*"
AppendBackslash ( szFilename ) ;
int iFileCount = 0 ;
# ifdef _WIN32
2011-08-11 13:46:06 +00:00
struct _wfinddata_t fdt ; int fdthnd ;
2009-05-08 13:28:41 +00:00
if ( ! fHasWildcard ) // parameter without wildcard: Append "/*.*" or "\*.*"
SAppend ( " * " , szFilename , _MAX_PATH ) ;
2011-08-11 13:46:06 +00:00
if ( ( fdthnd = _wfindfirst ( GetWideChar ( szFilename ) , & fdt ) ) < 0 )
2009-05-08 13:28:41 +00:00
return 0 ;
2010-03-28 18:58:01 +00:00
do
{
2011-08-11 13:46:06 +00:00
if ( ! wcscmp ( fdt . name , L " . " ) | | ! wcscmp ( fdt . name , L " .. " ) ) continue ;
StdStrBuf name ( fdt . name ) ;
SCopy ( name . getData ( ) , GetFilename ( szFilename ) ) ;
2009-05-08 13:28:41 +00:00
if ( ( * fnCallback ) ( szFilename ) )
iFileCount + + ;
2010-03-28 18:58:01 +00:00
}
2011-08-11 13:46:06 +00:00
while ( _wfindnext ( fdthnd , & fdt ) = = 0 ) ;
2009-05-08 13:28:41 +00:00
_findclose ( fdthnd ) ;
# else
2009-05-11 17:47:28 +00:00
if ( fHasWildcard ) fprintf ( stderr , " Warning: ForEachFile with * (%s) \n " , szDirName ) ;
2009-05-08 13:28:41 +00:00
DIR * d = opendir ( szDirName ) ;
2009-05-08 19:06:50 +00:00
if ( ! d ) return 0 ;
2009-05-08 13:28:41 +00:00
dirent * ent ;
2010-03-28 18:58:01 +00:00
while ( ( ent = readdir ( d ) ) )
{
2009-05-08 13:28:41 +00:00
SCopy ( ent - > d_name , GetFilename ( szFilename ) ) ;
if ( ( * fnCallback ) ( szFilename ) )
iFileCount + + ;
}
closedir ( d ) ;
# endif
return iFileCount ;
}