Files
itgmania212121/stepmania/src/RageUtil_FileDB.cpp
T

369 lines
9.2 KiB
C++
Raw Normal View History

2003-07-03 02:41:27 +00:00
#include "global.h"
#include "RageUtil_FileDB.h"
#include "RageUtil.h"
#include "RageLog.h"
2003-07-22 07:47:27 +00:00
#include "arch/arch.h"
2003-07-03 02:41:27 +00:00
/* Search for "beginning*containing*ending". */
void FileSet::GetFilesMatching(const CString &beginning, const CString &containing, const CString &ending, vector<CString> &out, bool bOnlyDirs) const
{
2003-10-19 22:20:56 +00:00
/* "files" is a case-insensitive mapping, by filename. Use lower_bound to figure
* out where to start. */
2003-12-06 05:50:02 +00:00
set<File>::const_iterator i = files.lower_bound( File(beginning) );
2003-07-03 02:41:27 +00:00
for( ; i != files.end(); ++i)
{
if(bOnlyDirs && !i->dir) continue;
2003-10-19 22:20:56 +00:00
/* Check beginning. Once we hit a filename that no longer matches beginning,
* we're past all possible matches in the sort, so stop. */
if(beginning.size() > i->name.size()) break; /* can't start with it */
2003-12-06 05:50:02 +00:00
if(strnicmp(i->name, beginning, beginning.size())) break; /* doesn't start with it */
2003-07-03 02:41:27 +00:00
/* Position the end starts on: */
int end_pos = int(i->name.size())-int(ending.size());
/* Check end. */
if(end_pos < 0) continue; /* can't end with it */
2003-12-06 05:50:02 +00:00
if( stricmp(i->name.c_str()+end_pos, ending) ) continue; /* doesn't end with it */
2003-07-03 02:41:27 +00:00
/* Check containing. Do this last, since it's the slowest (substring
* search instead of string match). */
if(containing.size())
{
unsigned pos = i->name.find(containing, beginning.size());
if(pos == i->name.npos) continue; /* doesn't contain it */
if(pos + containing.size() > unsigned(end_pos)) continue; /* found it but it overlaps with the end */
}
2003-12-06 05:50:02 +00:00
out.push_back( i->name );
2003-07-03 02:41:27 +00:00
}
}
void FileSet::GetFilesEqualTo(const CString &str, vector<CString> &out, bool bOnlyDirs) const
{
2003-12-06 05:50:02 +00:00
set<File>::const_iterator i = files.find( File(str) );
2003-07-03 02:41:27 +00:00
if(i == files.end())
return;
if(bOnlyDirs && !i->dir)
return;
2003-12-06 05:50:02 +00:00
out.push_back( i->name );
2003-07-03 02:41:27 +00:00
}
2003-12-06 06:17:21 +00:00
FileType FileSet::GetFileType(const CString &path ) const
2003-07-03 02:41:27 +00:00
{
2003-12-06 05:50:02 +00:00
set<File>::const_iterator i = files.find( File(path) );
2003-07-03 02:41:27 +00:00
if(i == files.end())
2003-12-06 06:17:21 +00:00
return TTYPE_NONE;
2003-07-03 02:41:27 +00:00
2003-12-06 06:17:21 +00:00
return i->dir? TTYPE_DIR:TTYPE_FILE;
2003-07-03 02:41:27 +00:00
}
2003-09-22 05:14:00 +00:00
int FileSet::GetFileSize(const CString &path) const
{
2003-12-06 05:50:02 +00:00
set<File>::const_iterator i = files.find( File(path) );
2003-09-22 05:14:00 +00:00
if(i == files.end())
return -1;
return i->size;
}
2003-09-23 00:09:10 +00:00
int FileSet::GetFileModTime(const CString &path) const
{
2003-12-06 05:50:02 +00:00
set<File>::const_iterator i = files.find( File(path) );
2003-09-23 00:09:10 +00:00
if(i == files.end())
return -1;
return i->mtime;
}
2003-07-03 02:41:27 +00:00
/* Given "foo/bar/baz/" or "foo/bar/baz", return "foo/bar/" and "baz". */
static void SplitPath( CString Path, CString &Dir, CString &Name )
{
2003-09-06 22:55:20 +00:00
/* Strip off any trailing slashes. */
if( Path.size() > 0 && Path.Right(1) == SLASH )
Path.erase( Path.size()-1 );
2003-07-03 02:41:27 +00:00
static Regex split("(.*/)([^/]+)");
2003-11-13 00:39:36 +00:00
2003-07-03 02:41:27 +00:00
CStringArray match;
if(split.Compare(Path, match)) {
/* At least one slash. */
Dir = match[0];
Name = match[1];
} else {
/* No slash. */
2003-07-22 07:47:27 +00:00
Dir = "." SLASH;
2003-07-03 02:41:27 +00:00
Name = Path;
}
}
2003-12-06 06:17:21 +00:00
FileType FilenameDB::GetFileType( const CString &sPath )
2003-07-03 02:41:27 +00:00
{
CString Dir, Name;
2003-12-06 06:17:21 +00:00
SplitPath( sPath, Dir, Name );
2003-12-06 05:50:02 +00:00
FileSet &fs = GetFileSet( Dir );
2003-12-06 06:17:21 +00:00
return fs.GetFileType( Name );
2003-07-03 02:41:27 +00:00
}
2003-09-22 05:14:00 +00:00
int FilenameDB::GetFileSize( const CString &sPath )
{
CString Dir, Name;
SplitPath(sPath, Dir, Name);
2003-12-06 05:50:02 +00:00
FileSet &fs = GetFileSet( Dir );
2003-09-22 05:14:00 +00:00
return fs.GetFileSize(Name);
}
2003-09-23 00:09:10 +00:00
int FilenameDB::GetFileModTime( const CString &sPath )
{
CString Dir, Name;
SplitPath(sPath, Dir, Name);
2003-12-06 05:50:02 +00:00
FileSet &fs = GetFileSet( Dir );
2003-09-23 00:09:10 +00:00
return fs.GetFileModTime(Name);
}
2003-07-03 02:41:27 +00:00
/* XXX: this won't work right for URIs, eg \\foo\bar */
bool FilenameDB::ResolvePath(CString &path)
{
if(path == ".") return true;
if(path == "") return true;
/* Split path into components. */
vector<CString> p;
split(path, SLASH, p, true);
/* If we have "/foo", then add a blank entry to the beginning to line things up. */
2003-09-05 20:07:36 +00:00
if( path.Left( strlen(SLASH) ) == SLASH )
p.insert( p.begin(), "" );
2003-07-03 02:41:27 +00:00
/* Resolve each component. Assume the first component is correct. XXX
* don't do that! "Songs/" vs "songs/" */
CString ret = p[0];
for(unsigned i = 1; i < p.size(); ++i)
{
2003-07-22 07:47:27 +00:00
ret += SLASH;
2003-07-03 02:41:27 +00:00
vector<CString> lst;
2003-09-05 20:07:36 +00:00
FileSet &fs = GetFileSet( ret );
2003-07-03 02:41:27 +00:00
fs.GetFilesEqualTo(p[i], lst, false);
/* If there were no matches, the path isn't found. */
if(lst.empty()) return false;
if( lst.size() > 1 && LOG )
2003-07-22 07:47:27 +00:00
LOG->Warn("Ambiguous filenames '%s' and '%s'",
2003-07-03 02:41:27 +00:00
lst[0].c_str(), lst[1].c_str());
ret += lst[0];
}
2003-07-22 07:47:27 +00:00
if(path.Right(1) == SLASH)
path = ret + SLASH;
2003-07-03 02:41:27 +00:00
else
path = ret;
return true;
}
void FilenameDB::GetFilesMatching(const CString &dir, const CString &beginning, const CString &containing, const CString &ending, vector<CString> &out, bool bOnlyDirs)
{
2003-12-06 05:50:02 +00:00
FileSet &fs = GetFileSet( dir );
2003-07-03 02:41:27 +00:00
fs.GetFilesMatching(beginning, containing, ending, out, bOnlyDirs);
}
void FilenameDB::GetFilesEqualTo(const CString &dir, const CString &fn, vector<CString> &out, bool bOnlyDirs)
{
2003-12-06 05:50:02 +00:00
FileSet &fs = GetFileSet( dir );
2003-07-03 02:41:27 +00:00
fs.GetFilesEqualTo(fn, out, bOnlyDirs);
}
void FilenameDB::GetFilesSimpleMatch(const CString &dir, const CString &fn, vector<CString> &out, bool bOnlyDirs)
{
/* Does this contain a wildcard? */
unsigned first_pos = fn.find_first_of('*');
if(first_pos == fn.npos)
{
/* No; just do a regular search. */
GetFilesEqualTo(dir, fn, out, bOnlyDirs);
} else {
unsigned second_pos = fn.find_first_of('*', first_pos+1);
if(second_pos == fn.npos)
{
/* Only one *: "A*B". */
2003-09-03 04:30:29 +00:00
/* XXX: "_blank.png*.png" shouldn't match the file "_blank.png". */
2003-07-03 02:41:27 +00:00
GetFilesMatching(dir, fn.substr(0, first_pos), "", fn.substr(first_pos+1), out, bOnlyDirs);
} else {
/* Two *s: "A*B*C". */
GetFilesMatching(dir,
fn.substr(0, first_pos),
fn.substr(first_pos+1, second_pos-first_pos-1),
fn.substr(second_pos+1), out, bOnlyDirs);
}
}
}
2003-12-06 05:50:02 +00:00
FileSet &FilenameDB::GetFileSet( CString dir )
2003-07-03 02:41:27 +00:00
{
/* Normalize the path. */
2003-07-22 07:47:27 +00:00
dir.Replace("\\", SLASH); /* foo\bar -> foo/bar */
dir.Replace("//", SLASH); /* foo//bar -> foo/bar */
2003-12-07 04:14:52 +00:00
2003-12-06 05:50:02 +00:00
CString lower = dir;
lower.MakeLower();
2003-07-03 02:41:27 +00:00
2003-12-06 08:22:03 +00:00
map<CString, FileSet *>::iterator i = dirs.find( lower );
2003-12-07 04:14:52 +00:00
if( ExpireSeconds != -1 && i != dirs.end() && i->second->age.PeekDeltaTime() >= ExpireSeconds )
2003-07-03 02:41:27 +00:00
{
2003-12-07 04:14:52 +00:00
delete i->second;
2003-12-07 06:15:08 +00:00
dirs.erase( i );
2003-12-07 04:14:52 +00:00
i = dirs.end();
2003-07-03 02:41:27 +00:00
}
2003-12-07 04:14:52 +00:00
if( i != dirs.end() )
return *i->second;
2003-07-03 02:41:27 +00:00
2003-12-07 04:14:52 +00:00
FileSet *ret = new FileSet;
PopulateFileSet( *ret, dir );
AddFileSet( dir, ret );
2003-07-03 02:41:27 +00:00
return *ret;
}
2003-12-07 04:14:52 +00:00
void FilenameDB::AddFileSet( CString sPath, FileSet *fs )
{
sPath.MakeLower();
2003-12-07 06:15:08 +00:00
map<CString, FileSet *>::iterator it = dirs.find( sPath );
if( it != dirs.end() )
delete it->second;
2003-12-07 04:14:52 +00:00
dirs[sPath] = fs;
}
2003-12-08 00:04:47 +00:00
/* Add the file or directory "sPath". sPath is a directory if it ends with
* a slash. */
void FilenameDB::AddFile( const CString &sPath, int size, int mtime, void *priv )
2003-12-08 00:04:47 +00:00
{
vector<CString> parts;
split( sPath, "/", parts, false );
CStringArray::const_iterator begin = parts.begin();
CStringArray::const_iterator end = parts.end();
bool IsDir = true;
if( sPath[sPath.size()-1] != '/' )
IsDir = false;
else
--end;
do
{
/* Combine all but the last part. */
CString dir = join( "/", begin, end-1 ) + "/";
const CString &fn = *(end-1);
FileSet &fs = GetFileSet( dir );
File f;
f.SetName( fn );
if( fs.files.find( f ) == fs.files.end() )
{
f.dir = IsDir;
if( !IsDir )
{
f.size = size;
f.mtime = mtime;
f.priv = priv;
}
2003-12-08 00:04:47 +00:00
fs.files.insert( f );
}
IsDir = true;
--end;
} while( begin != end );
}
2003-07-03 02:41:27 +00:00
void FilenameDB::FlushDirCache()
{
2003-12-06 05:50:02 +00:00
for( map<CString, FileSet *>::iterator i = dirs.begin(); i != dirs.end(); ++i )
2003-11-11 17:51:06 +00:00
delete i->second;
2003-07-03 02:41:27 +00:00
dirs.clear();
}
File *FilenameDB::GetFile( const CString &sPath )
{
CString Dir, Name;
SplitPath(sPath, Dir, Name);
FileSet &fs = GetFileSet( Dir );
set<File>::iterator i = fs.files.find( File(Name) );
if(i == fs.files.end())
return NULL;
return &*i;
}
2003-07-03 02:41:27 +00:00
2003-12-07 04:14:52 +00:00
void FilenameDB::GetDirListing( CString sPath, CStringArray &AddTo, bool bOnlyDirs, bool bReturnPathToo )
2003-07-03 02:41:27 +00:00
{
2003-07-22 07:47:27 +00:00
// LOG->Trace( "GetDirListing( %s )", sPath.c_str() );
2003-07-03 02:41:27 +00:00
/* If you want the CWD, use ".". */
ASSERT(!sPath.empty());
/* XXX: for case-insensitive resolving, we assume the first element is
* correct (we need a place to start from); so if sPath is relative,
* prepend "./" */
/* Strip off the last path element and use it as a mask. */
2003-07-22 07:47:27 +00:00
unsigned pos = sPath.find_last_of( SLASH );
2003-07-03 02:41:27 +00:00
CString fn;
if(pos != sPath.npos)
{
fn = sPath.substr(pos+1);
sPath = sPath.substr(0, pos+1);
}
/* If there was only one path element, or if the last element was empty,
* use "*". */
if(fn.size() == 0)
fn = "*";
unsigned start = AddTo.size();
2003-12-07 04:14:52 +00:00
GetFilesSimpleMatch(sPath, fn, AddTo, bOnlyDirs);
2003-07-03 02:41:27 +00:00
if(bReturnPathToo && start < AddTo.size())
{
2003-12-07 04:14:52 +00:00
ResolvePath(sPath);
2003-07-03 02:41:27 +00:00
while(start < AddTo.size())
{
AddTo[start] = sPath + AddTo[start];
start++;
}
}
}
2003-12-07 04:14:52 +00:00
bool ResolvePath(CString &path) { return true; } // XXX
2003-09-22 05:14:00 +00:00
2003-07-03 02:41:27 +00:00
2003-12-05 02:26:45 +00:00
#if 0
2003-12-06 06:17:21 +00:00
bool DoesFileExist( const CString &sPath ) { return FDB.GetFileType( sPath ) != TTYPE_NONE; }
bool IsAFile( const CString &sPath ) { return FDB.GetFileType( sPath ) == TTYPE_FILE; }
bool IsADirectory( const CString &sPath ) { return FDB.GetFileType( sPath ) == TTYPE_DIR; }
2003-09-23 00:09:10 +00:00
int GetFileModTime( const CString &sPath ) { return FDB.GetFileModTime(sPath); }
2003-09-22 05:14:00 +00:00
unsigned GetFileSizeInBytes( const CString &sPath )
{
int ret = FDB.GetFileSize(sPath);
2003-09-23 00:09:10 +00:00
// LOG->Trace("file '%s' size %i", sPath.c_str(), ret);
2003-09-22 05:14:00 +00:00
if( ret == -1 )
return 0;
return ret;
}
2003-12-05 02:26:45 +00:00
void GetDirListing( CString sPath, CStringArray &AddTo, bool bOnlyDirs, bool bReturnPathToo )
{
2003-12-07 04:14:52 +00:00
FDB.GetDirListing( sPath, AddTo, bOnlyDirs, bReturnPathToo );
2003-12-05 02:26:45 +00:00
}
2003-09-23 00:09:10 +00:00
#endif