Jump to content

  • Log In with Google      Sign In   
  • Create Account


PhysicsFS help needed to read a directories files

  • You cannot reply to this topic
6 replies to this topic

#1 MARS_999   Members   -  Reputation: 1236

Like
0Likes
Like

Posted 05 July 2014 - 04:50 PM

I am not following how one can use PhysicsFS to parse a directory for it's files and other directories... 

 

e.g. 

I want to parse my games map directory or texture directory how can I do this... I don't see a function to call to read the the directory.

 

Thanks



Sponsor:

#2 Servant of the Lord   Crossbones+   -  Reputation: 17027

Like
1Likes
Like

Posted 05 July 2014 - 05:29 PM

I'm not sure how to do that in PhysFS, but if it helps at all, boost::filesystem does that fairly easily.
 
Here's my own convenience functions that I use:

//Elsewhere: typedef std::vector<std::string> StringList;

enum SubFoldersEnum {IncludeSubFolders, ExcludeSubFolders};

/*
	Returns a list of every file in the folder and (if desired) the files in each sub-folder.
	If 'timeThreshold' is specified, only files that have been written to *after* that threshold are returned.
	If 'fileFilterFunc' is specified, this filters out all file names (not the entire path) that don't pass the filter.
	If 'folderFilterFunc' is specified, entire subdirectories are filtered out.
	If 'pathPrefix' is specified, this determines what prefixes the returned paths.
	Suggestions for 'pathPrefix' are: Nothing ("FolderA"), "./" ("./FolderA") for relative paths, or passing in baseFolder for absolute paths.

	Example:
		"./File1.ext"
		"./File2.ext"
		"./FolderB/File3.ext"
		"./FolderB/File4.ext"
		"./FolderB/Folder2/File5.ext"
		"./File6.ext"
*/
StringList GetFilesInDirectory(const std::string &baseFolder, SubFoldersEnum subFoldersEnum, const std::string &pathPrefix, std::time_t timeThreshold)
{
	//Call the original function, but with filters that accept everything.
	return GetFilesInDirectory(baseFolder, IsAnything, IsAnything, subFoldersEnum, pathPrefix, timeThreshold);
}

StringList GetFilesInDirectory(const std::string &baseFolder, StringValidatorFunc fileFilterFunc, SubFoldersEnum subFoldersEnum, const std::string &pathPrefix, std::time_t timeThreshold)
{
	//Call the original function, but with a directory filter that accepts everything.
	return GetFilesInDirectory(baseFolder, fileFilterFunc, IsAnything, subFoldersEnum, pathPrefix, timeThreshold);
}

StringList GetFilesInDirectory(const std::string &baseFolder, StringValidatorFunc fileFilterFunc, StringValidatorFunc folderFilterFunc,
							   SubFoldersEnum subFoldersEnum, const std::string &pathPrefix, std::time_t timeThreshold)
{
	StringList listOfFiles;
	if(!DirectoryExists(baseFolder))
		return listOfFiles;

	boost::filesystem::directory_iterator directoryIterator(baseFolder);
	boost::filesystem::directory_iterator endOfDirectory; //An unitialized iterator is the end iterator.

	//Loop through everything in this directory.
	for(; directoryIterator != endOfDirectory; directoryIterator++)
	{
		//Make sure the item found is a file and not a folder.
		if(boost::filesystem::is_regular_file(directoryIterator->path()))
		{
			//Get the name of the folder.
			std::string filename = GetFilenameFromPath(directoryIterator->path().generic_string());

			//Check if the filename passes the filter.
			if(fileFilterFunc(filename))
			{
				//Check if it was written to after 'timeThreshold'.
				if(timeThreshold == 0 || timeThreshold < boost::filesystem::last_write_time(directoryIterator->path()))
				{
					//Add it to our list.
					listOfFiles.push_back(ConvertWinPathToUnix(pathPrefix + '/' + filename));
				}
			}
		}
		else if(boost::filesystem::is_directory(directoryIterator->path()))
		{
			//Check to make sure we want to crawl subfolders.
			if(subFoldersEnum == IncludeSubFolders)
			{
				//Get the name of the folder.
				std::string directoryName = GetFinalDirectoryFromPath(directoryIterator->path().generic_string());

				//Check if the directory name passes the filter.
				if(folderFilterFunc(directoryName))
				{
					//Get all subfolders and add them to the list.
					listOfFiles += GetFilesInDirectory(baseFolder + "/" + directoryName, fileFilterFunc, folderFilterFunc, IncludeSubFolders, (pathPrefix + '/' + directoryName + '/'), timeThreshold);
				}
			}
		}
	}

	return listOfFiles;
}

'StringValidatorFunc' is a function pointer (actually, a std::function<bool(const std::string&)>) that can take a string a return either true or false if it accepts the string. I use this for filtering files. Often I pass it my SV_WildcardMatch() functor, to easily filter out something like {"*.jpg", "*.jpeg", "*.png"} - I can also post the code for that, if you desire. It's a slightly modified version of this algorithm.

 

I have a similar function called GetFoldersInDirectory(). It returns folder names instead of file names.


It's perfectly fine to abbreviate my username to 'Servant' rather than copy+pasting it all the time.

[Fly with me on Twitter] [Google+] [My broken website]

All glory be to the Man at the right hand... On David's throne the King will reign, and the Government will rest upon His shoulders. All the earth will see the salvation of God.                                                                                                                                                       [Need free cloud storage? I personally like DropBox]

Of Stranger Flames - [indie turn-based rpg set in a para-historical French colony] | Indie RPG development journal


#3 FRex   Members   -  Reputation: 224

Like
4Likes
Like

Posted 05 July 2014 - 06:08 PM

There is a function that returns a list you have to free later:

https://icculus.org/physfs/docs/html/physfs_8h.html#a0f4ae950c2dae0735a91263ddd20fbf4

 

There is also a callback version just below that you provide your own data and function to.



#4 MARS_999   Members   -  Reputation: 1236

Like
0Likes
Like

Posted 05 July 2014 - 06:27 PM

There is a function that returns a list you have to free later:

https://icculus.org/physfs/docs/html/physfs_8h.html#a0f4ae950c2dae0735a91263ddd20fbf4

 

There is also a callback version just below that you provide your own data and function to.

 

I am not following this directory path requirements... I put this in and get nothing

 

 
char* path = "C:/Programming/Work/SDL/Debug/";
cmd_enumerate(path);
 

static int cmd_enumerate(char *args)
{
char **rc;
 
if (*args == '\"')
{
args++;
args[strlen(args) - 1] = '\0';
} /* if */
 
rc = PHYSFS_enumerateFiles(args);
 
if (rc == NULL)
printf("Failure. reason: %s.\n", PHYSFS_getLastError());
else
{
int file_count;
char **i;
for (i = rc, file_count = 0; *i != NULL; i++, file_count++)
printf("%s\n", *i);
 
printf("\n total (%d) files.\n", file_count);
PHYSFS_freeList(rc);
} /* else */
 
return(1);
} /* cmd_enumerate */



#5 FRex   Members   -  Reputation: 224

Like
0Likes
Like

Posted 05 July 2014 - 06:34 PM

PhysFS is virtual filesystem inspired by id tech ones, so first you mount the directories you want and then you have one, own filesystem that can look at few places or archives as if they are one.

The mounting, search path, write path and platform independent and dependent paths are all explained well on main page:

https://icculus.org/physfs/docs/html/index.html


Edited by FRex, 05 July 2014 - 06:34 PM.


#6 MARS_999   Members   -  Reputation: 1236

Like
0Likes
Like

Posted 05 July 2014 - 07:07 PM

I'm not sure how to do that in PhysFS, but if it helps at all, boost::filesystem does that fairly easily.
 
Here's my own convenience functions that I use:

//Elsewhere: typedef std::vector<std::string> StringList;

enum SubFoldersEnum {IncludeSubFolders, ExcludeSubFolders};

/*
	Returns a list of every file in the folder and (if desired) the files in each sub-folder.
	If 'timeThreshold' is specified, only files that have been written to *after* that threshold are returned.
	If 'fileFilterFunc' is specified, this filters out all file names (not the entire path) that don't pass the filter.
	If 'folderFilterFunc' is specified, entire subdirectories are filtered out.
	If 'pathPrefix' is specified, this determines what prefixes the returned paths.
	Suggestions for 'pathPrefix' are: Nothing ("FolderA"), "./" ("./FolderA") for relative paths, or passing in baseFolder for absolute paths.

	Example:
		"./File1.ext"
		"./File2.ext"
		"./FolderB/File3.ext"
		"./FolderB/File4.ext"
		"./FolderB/Folder2/File5.ext"
		"./File6.ext"
*/
StringList GetFilesInDirectory(const std::string &baseFolder, SubFoldersEnum subFoldersEnum, const std::string &pathPrefix, std::time_t timeThreshold)
{
	//Call the original function, but with filters that accept everything.
	return GetFilesInDirectory(baseFolder, IsAnything, IsAnything, subFoldersEnum, pathPrefix, timeThreshold);
}

StringList GetFilesInDirectory(const std::string &baseFolder, StringValidatorFunc fileFilterFunc, SubFoldersEnum subFoldersEnum, const std::string &pathPrefix, std::time_t timeThreshold)
{
	//Call the original function, but with a directory filter that accepts everything.
	return GetFilesInDirectory(baseFolder, fileFilterFunc, IsAnything, subFoldersEnum, pathPrefix, timeThreshold);
}

StringList GetFilesInDirectory(const std::string &baseFolder, StringValidatorFunc fileFilterFunc, StringValidatorFunc folderFilterFunc,
							   SubFoldersEnum subFoldersEnum, const std::string &pathPrefix, std::time_t timeThreshold)
{
	StringList listOfFiles;
	if(!DirectoryExists(baseFolder))
		return listOfFiles;

	boost::filesystem::directory_iterator directoryIterator(baseFolder);
	boost::filesystem::directory_iterator endOfDirectory; //An unitialized iterator is the end iterator.

	//Loop through everything in this directory.
	for(; directoryIterator != endOfDirectory; directoryIterator++)
	{
		//Make sure the item found is a file and not a folder.
		if(boost::filesystem::is_regular_file(directoryIterator->path()))
		{
			//Get the name of the folder.
			std::string filename = GetFilenameFromPath(directoryIterator->path().generic_string());

			//Check if the filename passes the filter.
			if(fileFilterFunc(filename))
			{
				//Check if it was written to after 'timeThreshold'.
				if(timeThreshold == 0 || timeThreshold < boost::filesystem::last_write_time(directoryIterator->path()))
				{
					//Add it to our list.
					listOfFiles.push_back(ConvertWinPathToUnix(pathPrefix + '/' + filename));
				}
			}
		}
		else if(boost::filesystem::is_directory(directoryIterator->path()))
		{
			//Check to make sure we want to crawl subfolders.
			if(subFoldersEnum == IncludeSubFolders)
			{
				//Get the name of the folder.
				std::string directoryName = GetFinalDirectoryFromPath(directoryIterator->path().generic_string());

				//Check if the directory name passes the filter.
				if(folderFilterFunc(directoryName))
				{
					//Get all subfolders and add them to the list.
					listOfFiles += GetFilesInDirectory(baseFolder + "/" + directoryName, fileFilterFunc, folderFilterFunc, IncludeSubFolders, (pathPrefix + '/' + directoryName + '/'), timeThreshold);
				}
			}
		}
	}

	return listOfFiles;
}

'StringValidatorFunc' is a function pointer (actually, a std::function<bool(const std::string&)>) that can take a string a return either true or false if it accepts the string. I use this for filtering files. Often I pass it my SV_WildcardMatch() functor, to easily filter out something like {"*.jpg", "*.jpeg", "*.png"} - I can also post the code for that, if you desire. It's a slightly modified version of this algorithm.

 

I have a similar function called GetFoldersInDirectory(). It returns folder names instead of file names.

yes please post it completely, I have a feeling I am going to need it and have to use boost. I didn't want to but SDL doesn't have anything to read a directories contents...

 

thanks!!!



#7 Servant of the Lord   Crossbones+   -  Reputation: 17027

Like
3Likes
Like

Posted 05 July 2014 - 08:34 PM

Here's the convenience functions I wrapped around boost.filesystem (sometimes just a renaming of the function wink.png):

FileManagement.cpp | FileManagement.h

 

boost.filesystem has a boost::filepath and boost::directory class that it'd be better to use, but just incase you're interested, here's my hand-rolled functions for std::string.

PathFormatting.cpp | PathFormatting.h

 

CharValidators.cpp | CharValidators.h

StringValidators.cpp | StringValidators.h

WildcardMatch.cpp | WildcardMatch.h

 

Glancing over these files, there are a few areas where they include another header from my codebase, so you'll get some compile errors - but it should be very easy to work around that - they aren't at all badly integrated.


It's perfectly fine to abbreviate my username to 'Servant' rather than copy+pasting it all the time.

[Fly with me on Twitter] [Google+] [My broken website]

All glory be to the Man at the right hand... On David's throne the King will reign, and the Government will rest upon His shoulders. All the earth will see the salvation of God.                                                                                                                                                       [Need free cloud storage? I personally like DropBox]

Of Stranger Flames - [indie turn-based rpg set in a para-historical French colony] | Indie RPG development journal






PARTNERS