new EnumDirEnts call; replaces previous implementation in BaseEntityCollection.cpp that didn't handle subdirectories
This was SVN commit r2057.
This commit is contained in:
parent
ba636ca96c
commit
a1981970e5
@ -2,6 +2,7 @@
|
||||
|
||||
#include "VFSUtil.h"
|
||||
#include "lib/res/vfs.h"
|
||||
#include "lib/res/vfs_path.h"
|
||||
|
||||
#include "CLogger.h"
|
||||
#define LOG_CATEGORY "vfs"
|
||||
@ -38,3 +39,83 @@ bool VFSUtil::FindFiles (CStr& dirname, const char* filter, FileList& files)
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
// call <cb> for each file in the <start_path> directory;
|
||||
// if <recursive>, files in subdirectories are also returned.
|
||||
//
|
||||
// note: EnumFileCB path and ent are only valid during the callback.
|
||||
int VFSUtil::EnumDirEnts(const CStr start_path, const char* user_filter,
|
||||
bool recursive, EnumDirEntsCB cb, void* context)
|
||||
{
|
||||
// note: currently no need to return subdirectories,
|
||||
// but enabling it isn't hard.
|
||||
|
||||
char filter_buf[VFS_MAX_PATH];
|
||||
const char* filter = user_filter;
|
||||
bool want_dir = true;
|
||||
if(user_filter)
|
||||
{
|
||||
if(user_filter[0] != '/')
|
||||
want_dir = false;
|
||||
|
||||
// we need subdirectories and the caller hasn't already requested them
|
||||
if(recursive && !want_dir)
|
||||
{
|
||||
snprintf(filter_buf, sizeof(filter_buf), "/|%s", user_filter);
|
||||
filter = filter_buf;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// note: FIFO queue instead of recursion is much more efficient
|
||||
// (less stack usage; avoids seeks by reading all entries in a
|
||||
// directory consecutively)
|
||||
|
||||
std::deque<const CStr> dir_queue;
|
||||
dir_queue.push_back(start_path);
|
||||
|
||||
// for each directory:
|
||||
do
|
||||
{
|
||||
// get current directory path from queue
|
||||
// note: can't refer to the queue contents - those are invalidated
|
||||
// as soon as a directory is pushed onto it.
|
||||
char path[VFS_MAX_PATH];
|
||||
path_append(path, dir_queue.front().c_str(), "");
|
||||
// vfs_open_dir checks this, so ignore failure
|
||||
const size_t path_len = strlen(path);
|
||||
dir_queue.pop_front();
|
||||
|
||||
Handle hdir = vfs_open_dir(path);
|
||||
if(hdir <= 0)
|
||||
{
|
||||
debug_warn("EnumFiles: vfs_open_dir failed");
|
||||
continue;
|
||||
}
|
||||
|
||||
// for each entry (file, subdir) in directory:
|
||||
vfsDirEnt ent;
|
||||
while(vfs_next_dirent(hdir, &ent, filter) == 0)
|
||||
{
|
||||
// build complete path (vfsDirEnt only stores entry name)
|
||||
strcpy_s(path+path_len, VFS_MAX_PATH-path_len, ent.name);
|
||||
|
||||
if(VFS_ENT_IS_DIR(ent))
|
||||
{
|
||||
if(recursive)
|
||||
dir_queue.push_back(path);
|
||||
|
||||
if(want_dir)
|
||||
cb(path, &ent, context);
|
||||
}
|
||||
else
|
||||
cb(path, &ent, context);
|
||||
}
|
||||
|
||||
vfs_close_dir(hdir);
|
||||
}
|
||||
while(!dir_queue.empty());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,17 +1,28 @@
|
||||
#include "ps/CStr.h"
|
||||
#include "res/vfs.h"
|
||||
|
||||
namespace VFSUtil
|
||||
{
|
||||
typedef std::vector<CStr> FileList;
|
||||
|
||||
// Puts the list of files inside 'dirname' matching 'filter' into 'files'.
|
||||
// 'dirname' shouldn't end with a slash.
|
||||
// 'filter' is as in vfs_next_dirent:
|
||||
// - 0: any file;
|
||||
// - "/": any subdirectory
|
||||
// - anything else: pattern for name (may include '?' and '*' wildcards)
|
||||
// 'files' is initially cleared, and undefined on failure.
|
||||
// On failure, logs an error and returns false.
|
||||
bool FindFiles(CStr& dirname, const char* filter, FileList& files);
|
||||
typedef std::vector<CStr> FileList;
|
||||
|
||||
};
|
||||
// Puts the list of files inside 'dirname' matching 'filter' into 'files'.
|
||||
// 'dirname' shouldn't end with a slash.
|
||||
// 'filter': see vfs_next_dirent
|
||||
// 'files' is initially cleared, and undefined on failure.
|
||||
// On failure, logs an error and returns false.
|
||||
extern bool FindFiles(CStr& dirname, const char* filter, FileList& files);
|
||||
|
||||
|
||||
// called by EnumFiles for each file in a directory (optionally
|
||||
// its subdirectories as well), passing user-specified context.
|
||||
// note: path and ent parameters are only valid during the callback.
|
||||
typedef void (*EnumDirEntsCB)(const char* path, const vfsDirEnt* ent,
|
||||
void* context);
|
||||
|
||||
// call <cb> for each file in the <start_path> directory;
|
||||
// if <recursive>, files in subdirectories are also returned.
|
||||
extern int EnumDirEnts(const CStr path, const char* filter, bool recursive,
|
||||
EnumDirEntsCB cb, void* context);
|
||||
|
||||
}; // namespace VFSUtil
|
||||
|
@ -4,48 +4,34 @@
|
||||
#include "ObjectManager.h"
|
||||
#include "Model.h"
|
||||
#include "CLogger.h"
|
||||
#include "res/res.h"
|
||||
#include "VFSUtil.h"
|
||||
|
||||
#define LOG_CATEGORY "entity"
|
||||
|
||||
void CBaseEntityCollection::loadTemplates()
|
||||
|
||||
void CBaseEntityCollection::LoadFile( const char* path )
|
||||
{
|
||||
Handle handle;
|
||||
vfsDirEnt type;
|
||||
|
||||
CStr basepath = "entities/";
|
||||
CStr pathname;
|
||||
|
||||
// Iterate through all subdirectories
|
||||
|
||||
Handle maindir = vfs_open_dir( basepath );
|
||||
|
||||
if( maindir > 0 )
|
||||
CBaseEntity* newTemplate = new CBaseEntity();
|
||||
if( newTemplate->loadXML( path ) )
|
||||
{
|
||||
LoadDirectory( maindir, basepath );
|
||||
while( !vfs_next_dirent( maindir, &type, "/" ) )
|
||||
{
|
||||
pathname = basepath + type.name;
|
||||
|
||||
handle = vfs_open_dir( pathname );
|
||||
|
||||
pathname += "/";
|
||||
|
||||
if( handle > 0 )
|
||||
{
|
||||
LoadDirectory( handle, pathname );
|
||||
vfs_close_dir( handle );
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(ERROR, LOG_CATEGORY, "CBaseEntityCollection::loadTemplates(): Failed to enumerate entity template directory");
|
||||
return;
|
||||
}
|
||||
}
|
||||
vfs_close_dir( maindir );
|
||||
m_templates.push_back( newTemplate );
|
||||
LOG(NORMAL, LOG_CATEGORY, "CBaseEntityCollection::loadTemplates(): Loaded template \"%s\"", path);
|
||||
}
|
||||
else
|
||||
LOG(ERROR, LOG_CATEGORY, "CBaseEntityCollection::loadTemplates(): Unable to open directory entities/");
|
||||
LOG(ERROR, LOG_CATEGORY, "CBaseEntityCollection::loadTemplates(): Couldn't load template \"%s\"", path);
|
||||
}
|
||||
|
||||
static void LoadFileThunk( const char* path, const vfsDirEnt* ent, void* context )
|
||||
{
|
||||
CBaseEntityCollection* this_ = (CBaseEntityCollection*)context;
|
||||
this_->LoadFile(path);
|
||||
}
|
||||
|
||||
void CBaseEntityCollection::loadTemplates()
|
||||
{
|
||||
// Load all files in entities/ and its subdirectories.
|
||||
THROW_ERR( VFSUtil::EnumDirEnts( "entities/", "*.xml", true, LoadFileThunk, this ) );
|
||||
|
||||
|
||||
// Fix up parent links in the templates.
|
||||
|
||||
@ -91,27 +77,6 @@ void CBaseEntityCollection::loadTemplates()
|
||||
}
|
||||
}
|
||||
|
||||
void CBaseEntityCollection::LoadDirectory( Handle directory, CStr pathname )
|
||||
{
|
||||
vfsDirEnt file;
|
||||
while( !vfs_next_dirent( directory, &file, "*.xml") )
|
||||
{
|
||||
CBaseEntity* newTemplate = new CBaseEntity();
|
||||
if( newTemplate->loadXML( pathname + file.name ) )
|
||||
{
|
||||
addTemplate( newTemplate );
|
||||
LOG(NORMAL, LOG_CATEGORY, "CBaseEntityCollection::loadTemplates(): Loaded template \"%s%s\"", pathname.c_str(), file.name);
|
||||
}
|
||||
else
|
||||
LOG(ERROR, LOG_CATEGORY, "CBaseEntityCollection::loadTemplates(): Couldn't load template \"%s%s\"", pathname.c_str(), file.name);
|
||||
}
|
||||
}
|
||||
|
||||
void CBaseEntityCollection::addTemplate( CBaseEntity* temp )
|
||||
{
|
||||
m_templates.push_back( temp );
|
||||
}
|
||||
|
||||
CBaseEntity* CBaseEntityCollection::getTemplate( CStrW name )
|
||||
{
|
||||
for( u16 t = 0; t < m_templates.size(); t++ )
|
||||
|
@ -33,8 +33,7 @@ public:
|
||||
~CBaseEntityCollection();
|
||||
CBaseEntity* getTemplate( CStrW entityType );
|
||||
void loadTemplates();
|
||||
void LoadDirectory( Handle directory, CStr pathname );
|
||||
void addTemplate( CBaseEntity* temp );
|
||||
void LoadFile( const char* path );
|
||||
CBaseEntity* getTemplateByActor( CStrW actorName );
|
||||
|
||||
// Create a list of the names of all templates, for display in ScEd's
|
||||
|
Loading…
Reference in New Issue
Block a user