@ -267,9 +267,15 @@
# define MAX_AUTOMATION_EVENTS 16384 / / Maximum number of automation events to record
# define MAX_AUTOMATION_EVENTS 16384 / / Maximum number of automation events to record
# endif
# endif
# ifndef DIRECTORY_FILTER_TAG
# define DIRECTORY_FILTER_TAG "DIR" / / Name tag used to request directory inclusion on directory scan
# endif / / NOTE: Used in ScanDirectoryFiles(), ScanDirectoryFilesRecursively() and LoadDirectoryFilesEx()
# ifndef FILE_FILTER_TAG_ALL
# define FILE_FILTER_TAG_ALL "*.*" / / Filter to include all file types and directories on directory scan
# endif / / NOTE: Used in ScanDirectoryFiles(), LoadDirectoryFilesEx() and GetDirectoryFileCountEx()
# ifndef FILE_FILTER_TAG_FILE_ONLY
# define FILE_FILTER_TAG_FILE_ONLY "FILES*" / / Filter to include all file types on directory scan
# endif / / NOTE: Used in ScanDirectoryFiles(), LoadDirectoryFilesEx() and GetDirectoryFileCountEx()
# ifndef FILE_FILTER_TAG_DIR_ONLY
# define FILE_FILTER_TAG_DIR_ONLY "DIR*" / / Filter to include directories on directory scan
# endif / / NOTE: Used in ScanDirectoryFiles(), LoadDirectoryFilesEx() and GetDirectoryFileCountEx()
/ / Flags operation macros
/ / Flags operation macros
# define FLAG_SET(n, f) ((n) |= (f))
# define FLAG_SET(n, f) ((n) |= (f))
@ -505,8 +511,7 @@ extern void ClosePlatform(void); // Close platform
static void InitTimer ( void ) ; / / Initialize timer , hi - resolution if available ( required by InitPlatform ( ) )
static void InitTimer ( void ) ; / / Initialize timer , hi - resolution if available ( required by InitPlatform ( ) )
static void SetupViewport ( int width , int height ) ; / / Set viewport for a provided width and height
static void SetupViewport ( int width , int height ) ; / / Set viewport for a provided width and height
static void ScanDirectoryFiles ( const char * basePath , FilePathList * list , const char * filter ) ; / / Scan all files and directories in a base path
static void ScanDirectoryFilesRecursively ( const char * basePath , FilePathList * list , const char * filter ) ; / / Scan all files and directories recursively from a base path
static void ScanDirectoryFiles ( const char * basePath , FilePathList * list , const char * filter , unsigned int expectedFileCount , bool scanSubdirs ) ; / / Scan all files and directories in a base path
# if defined(SUPPORT_AUTOMATION_EVENTS)
# if defined(SUPPORT_AUTOMATION_EVENTS)
static void RecordAutomationEvent ( void ) ; / / Record frame events ( to internal events array )
static void RecordAutomationEvent ( void ) ; / / Record frame events ( to internal events array )
@ -2753,53 +2758,36 @@ const char *GetApplicationDirectory(void)
/ / No recursive scanning is done !
/ / No recursive scanning is done !
FilePathList LoadDirectoryFiles ( const char * dirPath )
FilePathList LoadDirectoryFiles ( const char * dirPath )
{
{
n">FilePathList files = { 0 } ;
unsigned int fileCounter = 0 ;
k">return LoadDirectoryFilesEx ( dirPath , FILE_FILTER_TAG_ALL , false ) ;
}
struct dirent * entity ;
DIR * dir = opendir ( dirPath ) ;
/ / Load directory filepaths with extension filtering and recursive directory scan
/ / WARNING : Directory is scanned twice , first time to get files count
FilePathList LoadDirectoryFilesEx ( const char * basePath , const char * filter , bool scanSubdirs )
{
FilePathList files = { 0 } ;
if ( dir ! = NULL ) / / It ' s a directory
if ( DirectoryExists ( basePath ) ) / / It ' s a directory
{
{
/ / SCAN 1 : Count files
/ / SCAN 1 : Count files
while ( ( entity = readdir ( dir ) ) ! = NULL )
{
/ / NOTE : We skip ' . ' ( current dir ) and ' . . ' ( parent dir ) filepaths
if ( ( strcmp ( entity - > d_name , " . " ) ! = 0 ) & & ( strcmp ( entity - > d_name , " .. " ) ! = 0 ) ) fileCounter + + ;
}
unsigned int fileCounter = GetDirectoryFileCountEx ( basePath , filter , scanSubdirs ) ;
/ / Memory allocation for dirFileCount
/ / Memory allocation for dirFileCount
files . capacity = fileCounter ;
files . paths = ( char * * ) RL_CALLOC ( files . capacity , sizeof ( char * ) ) ;
for ( unsigned int i = 0 ; i < files . capacity ; i + + ) files . paths [ i ] = ( char * ) RL_CALLOC ( MAX_FILEPATH_LENGTH , sizeof ( char ) ) ;
closedir ( dir ) ;
files . paths = ( char * * ) RL_CALLOC ( fileCounter , sizeof ( char * ) ) ;
for ( unsigned int i = 0 ; i < fileCounter ; i + + ) files . paths [ i ] = ( char * ) RL_CALLOC ( MAX_FILEPATH_LENGTH , sizeof ( char ) ) ;
/ / SCAN 2 : Read filepaths
/ / SCAN 2 : Read filepaths
/ / NOTE : Directory paths are also registered
ScanDirectoryFiles ( dir Path, & files , b">NULL ) ;
/ / WARNING : basePath is always prepended to scanned paths
ScanDirectoryFiles ( base Path, & files , ">filter , fileCounter , scanSubdirs ) ;
/ / Security check : read files . count should match fileCounter
/ / Security check : read files . count should match fileCounter
if ( files . count ! = files . capacity ) TRACELOG ( LOG_WARNING , " FILEIO: Read files count do not match capacity allocated " ) ;
if ( files . count ! = fileCounter )
{
TRACELOG ( LOG_WARNING , " FILEIO: Read files count (%u) does not match capacity allocated (%u) " , files . count , fileCounter ) ;
files . count = fileCounter ; / / Avoid memory leak when unloading this FilePathList
}
}
}
else TRACELOG ( LOG_WARNING , " FILEIO: Failed to open requested directory " ) ; / / Maybe it ' s a file . . .
return files ;
}
/ / Load directory filepaths with extension filtering and recursive directory scan
/ / NOTE : On recursive loading we do not pre - scan for file count , we use MAX_FILEPATH_CAPACITY
FilePathList LoadDirectoryFilesEx ( const char * basePath , const char * filter , bool scanSubdirs )
{
FilePathList files = { 0 } ;
files . capacity = MAX_FILEPATH_CAPACITY ;
files . paths = ( char * * ) RL_CALLOC ( files . capacity , sizeof ( char * ) ) ;
for ( unsigned int i = 0 ; i < files . capacity ; i + + ) files . paths [ i ] = ( char * ) RL_CALLOC ( MAX_FILEPATH_LENGTH , sizeof ( char ) ) ;
/ / WARNING : basePath is always prepended to scanned paths
if ( scanSubdirs ) ScanDirectoryFilesRecursively ( basePath , & files , filter ) ;
else ScanDirectoryFiles ( basePath , & files , filter ) ;
else TRACELOG ( LOG_WARNING , " FILEIO: Directory cannot be opened (%s) " , basePath) ; / / Maybe it ' s a file . . .
return files ;
return files ;
}
}
@ -2810,7 +2798,7 @@ void UnloadDirectoryFiles(FilePathList files)
{
{
if ( files . paths ! = NULL )
if ( files . paths ! = NULL )
{
{
for ( unsigned int i = 0 ; i < files . capacity ; i + + ) RL_FREE ( files . paths [ i ] ) ;
for ( unsigned int i = 0 ; i < files . count ; i + + ) RL_FREE ( files . paths [ i ] ) ;
RL_FREE ( files . paths ) ;
RL_FREE ( files . paths ) ;
}
}
@ -2966,6 +2954,59 @@ void UnloadDroppedFiles(FilePathList files)
}
}
}
}
/ / Get the file count in a directory
unsigned int GetDirectoryFileCount ( const char * dirPath )
{
return GetDirectoryFileCountEx ( dirPath , FILE_FILTER_TAG_ALL , false ) ;
}
/ / Get the file count in a directory with extension filtering and recursive directory scan . Use ' FILE_FILTER_TAG_DIR_ONLY ' in the filter string to include directories in the result
unsigned int GetDirectoryFileCountEx ( const char * basePath , const char * filter , bool scanSubdirs )
{
unsigned int fileCounter = 0 ;
/ / WARNING : Path can not be static or it will be reused between recursive function calls !
char path [ MAX_FILEPATH_LENGTH ] = { 0 } ;
memset ( path , 0 , MAX_FILEPATH_LENGTH ) ;
struct dirent * entity ;
DIR * dir = opendir ( basePath ) ;
if ( dir ! = NULL ) / / It ' s a directory
{
while ( ( entity = readdir ( dir ) ) ! = NULL )
{
/ / NOTE : We skip ' . ' ( current dir ) and ' . . ' ( parent dir ) filepaths
if ( ( strcmp ( entity - > d_name , " . " ) ! = 0 ) & & ( strcmp ( entity - > d_name , " .. " ) ! = 0 ) )
{
/ / Construct new path from our base path
# if defined(_WIN32)
int pathLength = snprintf ( path , MAX_FILEPATH_LENGTH - 1 , " %s \\ %s " , basePath , entity - > d_name ) ;
# else
int pathLength = snprintf ( path , MAX_FILEPATH_LENGTH - 1 , " %s/%s " , basePath , entity - > d_name ) ;
# endif
/ / Don ' t add to count if path too long
if ( ( pathLength < 0 ) | | ( pathLength > = MAX_FILEPATH_LENGTH ) )
{
TRACELOG ( LOG_WARNING , " FILEIO: Path longer than %d characters (%s...) " , MAX_FILEPATH_LENGTH , basePath ) ;
}
else if ( IsPathFile ( path ) )
{
if ( ( filter = = NULL ) | | ( strstr ( filter , FILE_FILTER_TAG_ALL ) ! = NULL ) | |
( strstr ( filter , FILE_FILTER_TAG_FILE_ONLY ) ! = NULL ) | | IsFileExtension ( path , filter ) ) fileCounter + + ;
}
else
{
if ( ( filter ! = NULL ) & & ( ( strstr ( filter , FILE_FILTER_TAG_ALL ) ! = NULL ) | | ( strstr ( filter , FILE_FILTER_TAG_DIR_ONLY ) ! = NULL ) ) ) fileCounter + + ;
if ( scanSubdirs ) fileCounter + = GetDirectoryFileCountEx ( path , filter , scanSubdirs ) ;
}
}
}
}
else TRACELOG ( LOG_WARNING , " FILEIO: Directory cannot be opened (%s) " , basePath) ; / / Maybe it ' s a file . . .
return fileCounter ;
}
/ / - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/ / - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/ / Module Functions Definition : Compression and Encoding
/ / Module Functions Definition : Compression and Encoding
/ / - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/ / - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -4229,66 +4270,7 @@ void SetupViewport(int width, int height)
/ / Scan all files and directories in a base path
/ / Scan all files and directories in a base path
/ / WARNING : files . paths [ ] must be previously allocated and
/ / WARNING : files . paths [ ] must be previously allocated and
/ / contain enough space to store all required paths
/ / contain enough space to store all required paths
static void ScanDirectoryFiles ( const char * basePath , FilePathList * files , const char * filter )
{
static char path [ MAX_FILEPATH_LENGTH ] = { 0 } ;
memset ( path , 0 , MAX_FILEPATH_LENGTH ) ;
struct dirent * dp = NULL ;
DIR * dir = opendir ( basePath ) ;
if ( dir ! = NULL )
{
while ( ( dp = readdir ( dir ) ) ! = NULL )
{
if ( ( strcmp ( dp - > d_name , " . " ) ! = 0 ) & &
( strcmp ( dp - > d_name , " .. " ) ! = 0 ) )
{
/ / Construct new path from our base path
# if defined(_WIN32)
int pathLength = snprintf ( path , MAX_FILEPATH_LENGTH - 1 , " %s \\ %s " , basePath , dp - > d_name ) ;
# else
int pathLength = snprintf ( path , MAX_FILEPATH_LENGTH - 1 , " %s/%s " , basePath , dp - > d_name ) ;
# endif
if ( ( pathLength < 0 ) | | ( pathLength > = MAX_FILEPATH_LENGTH ) )
{
TRACELOG ( LOG_WARNING , " FILEIO: Path longer than %d characters (%s...) " , MAX_FILEPATH_LENGTH , basePath ) ;
}
else if ( filter ! = NULL )
{
if ( IsPathFile ( path ) )
{
if ( IsFileExtension ( path , filter ) )
{
strncpy ( files - > paths [ files - > count ] , path , MAX_FILEPATH_LENGTH - 1 ) ;
files - > count + + ;
}
}
else
{
if ( strstr ( filter , DIRECTORY_FILTER_TAG ) ! = NULL )
{
strncpy ( files - > paths [ files - > count ] , path , MAX_FILEPATH_LENGTH - 1 ) ;
files - > count + + ;
}
}
}
else
{
strncpy ( files - > paths [ files - > count ] , path , MAX_FILEPATH_LENGTH - 1 ) ;
files - > count + + ;
}
}
}
closedir ( dir ) ;
}
else TRACELOG ( LOG_WARNING , " FILEIO: Directory cannot be opened (%s) " , basePath) ;
}
/ / Scan all files and directories recursively from a base path
static void ScanDirectoryFilesRecursively ( const char * basePath , FilePathList * files , const char * filter )
static void ScanDirectoryFiles ( const char * basePath , FilePathList * files , const char * filter , unsigned int expectedFileCount , bool scanSubdirs )
{
{
/ / WARNING : Path can not be static or it will be reused between recursive function calls !
/ / WARNING : Path can not be static or it will be reused between recursive function calls !
char path [ MAX_FILEPATH_LENGTH ] = { 0 } ;
char path [ MAX_FILEPATH_LENGTH ] = { 0 } ;
@ -4299,7 +4281,7 @@ static void ScanDirectoryFilesRecursively(const char *basePath, FilePathList *fi
if ( dir ! = NULL )
if ( dir ! = NULL )
{
{
while ( ( ( dp = readdir ( dir ) ) ! = NULL ) & & ( files - > count < files - > capacity ) )
while ( ( ( dp = readdir ( dir ) ) ! = NULL ) & & ( files - > count < expectedFileCount ) )
{
{
if ( ( strcmp ( dp - > d_name , " . " ) ! = 0 ) & & ( strcmp ( dp - > d_name , " .. " ) ! = 0 ) )
if ( ( strcmp ( dp - > d_name , " . " ) ! = 0 ) & & ( strcmp ( dp - > d_name , " .. " ) ! = 0 ) )
{
{
@ -4316,48 +4298,29 @@ static void ScanDirectoryFilesRecursively(const char *basePath, FilePathList *fi
}
}
else if ( IsPathFile ( path ) )
else if ( IsPathFile ( path ) )
{
{
if ( filter ! = NULL )
{
if ( IsFileExtension ( path , filter ) )
{
strncpy ( files - > paths [ files - > count ] , path , MAX_FILEPATH_LENGTH - 1 ) ;
files - > count + + ;
}
}
else
if ( ( filter = = NULL ) | | ( strstr ( filter , FILE_FILTER_TAG_ALL ) ! = NULL ) | |
( strstr ( filter , FILE_FILTER_TAG_FILE_ONLY ) ! = NULL ) | | IsFileExtension ( path , filter ) )
{
{
strncpy ( files - > paths [ files - > count ] , path , MAX_FILEPATH_LENGTH - 1 ) ;
strncpy ( files - > paths [ files - > count ] , path , MAX_FILEPATH_LENGTH - 1 ) ;
files - > count + + ;
files - > count + + ;
}
}
if ( files - > count > = files - > capacity )
{
TRACELOG ( LOG_WARNING , " FILEIO: Maximum filepath scan capacity reached (%i files) " , files - > capacity ) ;
break ;
}
}
}
else
else
{
{
if ( ( filter ! = NULL ) & & ( strstr ( filter , DIRECTORY_FILTER_TAG ) ! = NULL ) )
if ( ( filter ! = NULL ) & & ( ( strstr ( filter , FILE_FILTER_TAG_DIR_ONLY ) ! = NULL ) | | ( strstr ( filter , FILE_FILTER_TAG_ALL ) ! = NULL ) ) )
{
{
strncpy ( files - > paths [ files - > count ] , path , MAX_FILEPATH_LENGTH - 1 ) ;
strncpy ( files - > paths [ files - > count ] , path , MAX_FILEPATH_LENGTH - 1 ) ;
files - > count + + ;
files - > count + + ;
}
}
if ( files - > count > = files - > capacity )
{
TRACELOG ( LOG_WARNING , " FILEIO: Maximum filepath scan capacity reached (%i files) " , files - > capacity ) ;
break ;
}
ScanDirectoryFilesRecursively ( path , files , filter ) ;
if ( scanSubdirs ) ScanDirectoryFiles ( path , files , filter , expectedFileCount , scanSubdirs ) ;
}
}
}
}
}
}
closedir ( dir ) ;
closedir ( dir ) ;
}
}
else TRACELOG ( LOG_WARNING , " FILEIO: Directory cannot be opened (%s) " , basePath) ;
else TRACELOG ( LOG_WARNING , " FILEIO: Directory cannot be opened (%s) " , basePath) ; / / Maybe it ' s a file . . .
}
}
# if defined(SUPPORT_AUTOMATION_EVENTS)
# if defined(SUPPORT_AUTOMATION_EVENTS)