forked from Mirrors/openclonk
Implemented fixed ordering in DirectoryIterator
This should alleviate loading order differences from different OSes somewhat. Since the iterator currently employs a lexicographic ordering, there are probably still problems when one player has their packages unpacked, while another one has theirs packed. This should go away once we employ a sane format for game packages.stable-5.2
parent
b8ba66ed5b
commit
be39732a8f
|
@ -31,12 +31,12 @@
|
|||
#include <C4InputValidation.h>
|
||||
#include <C4Config.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#ifdef _WIN32
|
||||
#include <sys/utime.h>
|
||||
#include <shellapi.h>
|
||||
#else
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <utime.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
@ -570,23 +570,10 @@ C4GroupEntry::~C4GroupEntry()
|
|||
delete [] bpMemBuf;
|
||||
}
|
||||
}
|
||||
#ifdef _WIN32
|
||||
void C4GroupEntry::Set(const DirectoryIterator &iter, const char *szPath)
|
||||
{
|
||||
ZeroMem(this,sizeof(C4GroupEntry));
|
||||
SCopy(iter.fdt.name,FileName,_MAX_FNAME);
|
||||
Size=iter.fdt.size;
|
||||
Time=iter.fdt.time_create;
|
||||
//SCopy(szPath,DiskPath,_MAX_PATH-1); AppendBackslash(DiskPath); SAppend(FileName,DiskPath,_MAX_PATH);
|
||||
SCopy(*iter, DiskPath, _MAX_PATH-1);
|
||||
Status=C4GRES_OnDisk;
|
||||
Packed=false;
|
||||
ChildGroup=false; //FileGroupCheck(DiskPath);
|
||||
// Notice folder entries are not checked for ChildGroup status.
|
||||
// This would cause extreme performance loss and be good for
|
||||
// use in entry list display only.
|
||||
}
|
||||
#else
|
||||
|
||||
#ifdef WIN32
|
||||
#define stat _stat
|
||||
#endif
|
||||
void C4GroupEntry::Set(const DirectoryIterator &iter, const char * path)
|
||||
{
|
||||
ZeroMem(this,sizeof(C4GroupEntry));
|
||||
|
@ -608,7 +595,7 @@ void C4GroupEntry::Set(const DirectoryIterator &iter, const char * path)
|
|||
// This would cause extreme performance loss and be good for
|
||||
// use in entry list display only.
|
||||
}
|
||||
#endif
|
||||
|
||||
C4Group::C4Group()
|
||||
{
|
||||
Init();
|
||||
|
|
|
@ -811,112 +811,141 @@ bool ItemIdentical(const char *szFilename1, const char *szFilename2)
|
|||
|
||||
//------------------------- Multi File Processing --------------------------------------------------------------------------------------------------------
|
||||
|
||||
#ifdef _WIN32
|
||||
struct DirectoryIteratorP
|
||||
{
|
||||
DirectoryIteratorP() : ref(1) {}
|
||||
DirectoryIterator::FileList files;
|
||||
std::string directory;
|
||||
int ref;
|
||||
};
|
||||
|
||||
DirectoryIterator::DirectoryIterator (): fdthnd(0) { *filename=0; }
|
||||
DirectoryIterator::DirectoryIterator (const DirectoryIterator &): fdthnd(0) { *filename=0; }
|
||||
|
||||
void DirectoryIterator::Reset () {
|
||||
if (fdthnd) {
|
||||
_findclose(fdthnd);
|
||||
fdthnd = 0;
|
||||
}
|
||||
filename[0] = 0;
|
||||
DirectoryIterator::DirectoryIterator()
|
||||
: p(new DirectoryIteratorP), iter(p->files.end())
|
||||
{}
|
||||
DirectoryIterator::DirectoryIterator(const DirectoryIterator &other)
|
||||
: p(other.p), iter(p->files.begin())
|
||||
{
|
||||
++p->ref;
|
||||
}
|
||||
DirectoryIterator::~DirectoryIterator()
|
||||
{
|
||||
if (--p->ref == 0)
|
||||
delete p;
|
||||
}
|
||||
|
||||
void DirectoryIterator::Reset (const char * dirname) {
|
||||
if (fdthnd) {
|
||||
_findclose(fdthnd);
|
||||
void DirectoryIterator::Reset ()
|
||||
{
|
||||
iter = p->files.begin();
|
||||
}
|
||||
|
||||
void DirectoryIterator::Reset (const char * dirname)
|
||||
{
|
||||
if (p->directory == dirname)
|
||||
{
|
||||
// Skip reinitialisation and just reset the iterator
|
||||
iter = p->files.begin();
|
||||
return;
|
||||
}
|
||||
if (!dirname[0]) dirname = ".";
|
||||
SCopy(dirname,filename);
|
||||
AppendBackslash(filename);
|
||||
SAppend("*",filename,_MAX_PATH);
|
||||
if ((fdthnd = _findfirst(filename, &fdt)) < 0) {
|
||||
filename[0] = 0;
|
||||
} else {
|
||||
if (fdt.name[0] == '.' && (fdt.name[1] == '.' || fdt.name[1] == 0)) {
|
||||
operator++(); return;
|
||||
if (p->ref > 1)
|
||||
{
|
||||
// Detach from shared memory
|
||||
--p->ref;
|
||||
p = new DirectoryIteratorP;
|
||||
}
|
||||
p->files.clear();
|
||||
iter = p->files.end();
|
||||
Read(dirname);
|
||||
}
|
||||
|
||||
DirectoryIterator::DirectoryIterator (const char * dirname)
|
||||
: p(new DirectoryIteratorP), iter(p->files.end())
|
||||
{
|
||||
Read(dirname);
|
||||
}
|
||||
|
||||
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
|
||||
WIN32_FIND_DATA file = {0};
|
||||
HANDLE fh = FindFirstFile((search_path + '*').c_str(), &file);
|
||||
if (fh == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
switch (GetLastError())
|
||||
{
|
||||
case ERROR_FILE_NOT_FOUND:
|
||||
// This is okay, either the directory doesn't exist or there are no files
|
||||
return;
|
||||
default:
|
||||
// Something else broke
|
||||
throw std::runtime_error("DirectoryIterator::Read(const char*): Unable to read file system");
|
||||
}
|
||||
SCopy(fdt.name,GetFilename(filename));
|
||||
}
|
||||
}
|
||||
|
||||
DirectoryIterator::DirectoryIterator (const char * dirname) {
|
||||
if (!dirname[0]) dirname = ".";
|
||||
SCopy(dirname,filename);
|
||||
AppendBackslash(filename);
|
||||
SAppend("*",filename,_MAX_PATH);
|
||||
if ((fdthnd = _findfirst(filename, &fdt)) < 0) {
|
||||
filename[0] = 0;
|
||||
} else {
|
||||
if (fdt.name[0] == '.' && (fdt.name[1] == '.' || fdt.name[1] == 0)) {
|
||||
operator++(); return;
|
||||
}
|
||||
SCopy(fdt.name,GetFilename(filename));
|
||||
}
|
||||
}
|
||||
|
||||
DirectoryIterator& DirectoryIterator::operator++() {
|
||||
if (_findnext(fdthnd,&fdt)==0) {
|
||||
if (fdt.name[0] == '.' && (fdt.name[1] == '.' || fdt.name[1] == 0))
|
||||
return operator++();
|
||||
SCopy(fdt.name,GetFilename(filename));
|
||||
} else {
|
||||
filename[0] = 0;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
DirectoryIterator::~DirectoryIterator () {
|
||||
if (fdthnd) _findclose(fdthnd);
|
||||
}
|
||||
// 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;
|
||||
p->files.push_back(file.cFileName);
|
||||
} while (FindNextFile(fh, &file));
|
||||
FindClose(fh);
|
||||
#else
|
||||
DirectoryIterator::DirectoryIterator (): d(0) { filename[0] = 0; }
|
||||
DirectoryIterator::DirectoryIterator (const DirectoryIterator &): d(0) { filename[0] = 0; }
|
||||
|
||||
void DirectoryIterator::Reset () {
|
||||
if (d) {
|
||||
closedir(d);
|
||||
d = 0;
|
||||
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
|
||||
throw std::runtime_error("DirectoryIterator::Read(const char*): Unable to read file system");
|
||||
}
|
||||
}
|
||||
filename[0] = 0;
|
||||
}
|
||||
void DirectoryIterator::Reset (const char * dirname) {
|
||||
if (d) {
|
||||
closedir(d);
|
||||
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;
|
||||
p->files.push_back(file.cFileName);
|
||||
}
|
||||
if (!dirname[0]) dirname = ".";
|
||||
SCopy(dirname,filename);
|
||||
AppendBackslash(filename);
|
||||
d = opendir(dirname);
|
||||
this->operator++();
|
||||
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;
|
||||
}
|
||||
|
||||
DirectoryIterator::DirectoryIterator (const char * dirname) {
|
||||
if (!dirname[0]) dirname = ".";
|
||||
SCopy(dirname,filename);
|
||||
AppendBackslash(filename);
|
||||
d = opendir(dirname);
|
||||
this->operator++();
|
||||
}
|
||||
DirectoryIterator& DirectoryIterator::operator++() {
|
||||
if (d && (ent = readdir(d))) {
|
||||
if (ent->d_name[0] == '.' && (ent->d_name[1] == '.' || ent->d_name[1] == 0))
|
||||
return operator++();
|
||||
SCopy(ent->d_name,GetFilename(filename));
|
||||
} else {
|
||||
filename[0] = 0;
|
||||
}
|
||||
DirectoryIterator& DirectoryIterator::operator++()
|
||||
{
|
||||
if (iter != p->files.end())
|
||||
++iter;
|
||||
return *this;
|
||||
}
|
||||
|
||||
DirectoryIterator::~DirectoryIterator () {
|
||||
if (d) closedir(d);
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
const char * DirectoryIterator::operator*() const { return filename[0] ? filename : false; }
|
||||
void DirectoryIterator::operator++(int) { operator++(); }
|
||||
|
||||
int ForEachFile(const char *szDirName, bool (*fnCallback)(const char *)) {
|
||||
if (!szDirName || !fnCallback)
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <io.h>
|
||||
|
@ -118,27 +119,27 @@ bool MoveItem(const char *szSource, const char *szTarget);
|
|||
//int ForEachFile(const char *szPath, int lAttrib, bool (*fnCallback)(const char *));
|
||||
int ForEachFile(const char *szDirName, bool (*fnCallback)(const char *));
|
||||
|
||||
class DirectoryIterator {
|
||||
struct DirectoryIteratorP;
|
||||
class DirectoryIterator
|
||||
{
|
||||
// Shallow copyable, ordered directory iterator
|
||||
public:
|
||||
DirectoryIterator(const char * dirname);
|
||||
DirectoryIterator();
|
||||
~DirectoryIterator();
|
||||
// Does not actually copy anything, but does prevent misuses from crashing (I hope)
|
||||
DirectoryIterator(const DirectoryIterator &);
|
||||
~DirectoryIterator();
|
||||
|
||||
const char * operator * () const;
|
||||
DirectoryIterator& operator ++ ();
|
||||
void operator ++ (int);
|
||||
DirectoryIterator operator ++ (int);
|
||||
void Reset(const char * dirname);
|
||||
void Reset();
|
||||
protected:
|
||||
char filename[_MAX_PATH+1];
|
||||
#ifdef _WIN32
|
||||
struct _finddata_t fdt; int fdthnd;
|
||||
friend class C4GroupEntry;
|
||||
#else
|
||||
DIR * d;
|
||||
dirent * ent;
|
||||
#endif
|
||||
private:
|
||||
void Read(const char *dirname);
|
||||
friend struct DirectoryIteratorP;
|
||||
typedef std::vector<std::string> FileList;
|
||||
DirectoryIteratorP *p;
|
||||
FileList::iterator iter;
|
||||
};
|
||||
|
||||
#endif // STDFILE_INCLUDED
|
||||
|
|
Loading…
Reference in New Issue