- fixed: The directory scanner for reading a directory into the WAD file system and ScanDirectory were not Unicode capable on Windows.

Both now use the Unicode capable I_Find* interface instead of duplicating all its functionality in multiple platform dependent incarnations.
This commit is contained in:
Christoph Oelckers 2020-01-12 08:18:00 +01:00
parent 91589d9799
commit 9e13d3c60d
4 changed files with 86 additions and 211 deletions

View file

@ -35,15 +35,11 @@
#include <sys/stat.h> #include <sys/stat.h>
#ifdef _WIN32
#include <io.h>
#else
#include <fts.h>
#endif
#include "resourcefile.h" #include "resourcefile.h"
#include "cmdlib.h" #include "cmdlib.h"
#include "doomtype.h" #include "doomtype.h"
#include "i_system.h"
@ -71,12 +67,13 @@ struct FDirectoryLump : public FResourceLump
class FDirectory : public FResourceFile class FDirectory : public FResourceFile
{ {
TArray<FDirectoryLump> Lumps; TArray<FDirectoryLump> Lumps;
const bool nosubdir;
int AddDirectory(const char *dirpath); int AddDirectory(const char *dirpath);
void AddEntry(const char *fullpath, int size); void AddEntry(const char *fullpath, int size);
public: public:
FDirectory(const char * dirname); FDirectory(const char * dirname, bool nosubdirflag = false);
bool Open(bool quiet); bool Open(bool quiet);
virtual FResourceLump *GetLump(int no) { return ((unsigned)no < NumLumps)? &Lumps[no] : NULL; } virtual FResourceLump *GetLump(int no) { return ((unsigned)no < NumLumps)? &Lumps[no] : NULL; }
}; };
@ -89,8 +86,8 @@ public:
// //
//========================================================================== //==========================================================================
FDirectory::FDirectory(const char * directory) FDirectory::FDirectory(const char * directory, bool nosubdirflag)
: FResourceFile(NULL) : FResourceFile(NULL), nosubdir(nosubdirflag)
{ {
FString dirname; FString dirname;
@ -100,16 +97,15 @@ FDirectory::FDirectory(const char * directory)
// Todo for Linux: Resolve the path before using it // Todo for Linux: Resolve the path before using it
#endif #endif
dirname = directory; dirname = directory;
#ifdef _WIN32 #ifdef _WIN32
free((void *)directory); free((void *)directory);
#endif #endif
FixPathSeperator(dirname); dirname.Substitute("\\", "/");
if (dirname[dirname.Len()-1] != '/') dirname += '/'; if (dirname[dirname.Len()-1] != '/') dirname += '/';
FileName = dirname; FileName = dirname;
} }
#ifdef _WIN32
//========================================================================== //==========================================================================
// //
// Windows version // Windows version
@ -118,15 +114,15 @@ FDirectory::FDirectory(const char * directory)
int FDirectory::AddDirectory(const char *dirpath) int FDirectory::AddDirectory(const char *dirpath)
{ {
struct _finddata_t fileinfo; void * handle;
intptr_t handle;
FString dirmatch;
int count = 0; int count = 0;
dirmatch = dirpath; FString dirmatch = dirpath;
findstate_t find;
dirmatch += '*'; dirmatch += '*';
if ((handle = _findfirst(dirmatch, &fileinfo)) == -1) handle = I_FindFirst(dirmatch.GetChars(), &find);
if (handle == ((void *)(-1)))
{ {
Printf("Could not scan '%s': %s\n", dirpath, strerror(errno)); Printf("Could not scan '%s': %s\n", dirpath, strerror(errno));
} }
@ -134,113 +130,50 @@ int FDirectory::AddDirectory(const char *dirpath)
{ {
do do
{ {
if (fileinfo.attrib & _A_HIDDEN) // I_FindName only returns the file's name and not its full path
auto attr = I_FindAttr(&find);
if (attr & FA_HIDDEN)
{ {
// Skip hidden files and directories. (Prevents SVN bookkeeping // Skip hidden files and directories. (Prevents SVN bookkeeping
// info from being included.) // info from being included.)
continue; continue;
} }
if (fileinfo.attrib & _A_SUBDIR) FString fi = I_FindName(&find);
if (attr & FA_DIREC)
{ {
if (nosubdir || (fi[0] == '.' &&
if (fileinfo.name[0] == '.' && (fi[1] == '\0' ||
(fileinfo.name[1] == '\0' || (fi[1] == '.' && fi[2] == '\0'))))
(fileinfo.name[1] == '.' && fileinfo.name[2] == '\0')))
{ {
// Do not record . and .. directories. // Do not record . and .. directories.
continue; continue;
} }
FString newdir = dirpath; FString newdir = dirpath;
newdir << fileinfo.name << '/'; newdir << fi << '/';
count += AddDirectory(newdir); count += AddDirectory(newdir);
} }
else else
{ {
if (strstr(fileinfo.name, ".orig") || strstr(fileinfo.name, ".bak")) if (strstr(fi, ".orig") || strstr(fi, ".bak"))
{ {
// We shouldn't add backup files to the lump directory // We shouldn't add backup files to the file system
continue; continue;
} }
size_t size = 0;
AddEntry(FString(dirpath) + fileinfo.name, fileinfo.size); FString fn = FString(dirpath) + fi;
count++; if (GetFileInfo(fn, &size, nullptr))
{
AddEntry(fn, size);
count++;
}
} }
} while (_findnext(handle, &fileinfo) == 0);
_findclose(handle); } while (I_FindNext (handle, &find) == 0);
I_FindClose (handle);
} }
return count; return count;
} }
#else
//==========================================================================
//
// add_dirs
// 4.4BSD version
//
//==========================================================================
int FDirectory::AddDirectory(const char *dirpath)
{
char *argv [2] = { NULL, NULL };
argv[0] = new char[strlen(dirpath)+1];
strcpy(argv[0], dirpath);
FTS *fts;
FTSENT *ent;
int count = 0;
fts = fts_open(argv, FTS_LOGICAL, NULL);
if (fts == NULL)
{
Printf("Failed to start directory traversal: %s\n", strerror(errno));
return 0;
}
const size_t namepos = strlen(FileName);
FString pathfix;
while ((ent = fts_read(fts)) != NULL)
{
if (ent->fts_info == FTS_D && ent->fts_name[0] == '.')
{
// Skip hidden directories. (Prevents SVN bookkeeping
// info from being included.)
fts_set(fts, ent, FTS_SKIP);
}
if (ent->fts_info == FTS_D && ent->fts_level == 0)
{
continue;
}
if (ent->fts_info != FTS_F)
{
// We're only interested in remembering files.
continue;
}
// Some implementations add an extra separator between
// root of the hierarchy and entity's path.
// It needs to be removed in order to resolve
// lumps' relative paths properly.
const char* path = ent->fts_path;
if ('/' == path[namepos])
{
pathfix = FString(path, namepos);
pathfix.AppendCStrPart(&path[namepos + 1], ent->fts_pathlen - namepos - 1);
path = pathfix.GetChars();
}
AddEntry(path, ent->fts_statp->st_size);
count++;
}
fts_close(fts);
delete[] argv[0];
return count;
}
#endif
//========================================================================== //==========================================================================
// //
// //

View file

@ -371,6 +371,8 @@ FImageSource * FImageSource::GetImage(int lumpnum, ETextureType usetype)
if (ImageForLump[lumpnum] != nullptr) return ImageForLump[lumpnum]; if (ImageForLump[lumpnum] != nullptr) return ImageForLump[lumpnum];
auto data = Wads.OpenLumpReader(lumpnum); auto data = Wads.OpenLumpReader(lumpnum);
if (!data.isOpen())
return nullptr;
for (size_t i = 0; i < countof(CreateInfo); i++) for (size_t i = 0; i < countof(CreateInfo); i++)
{ {

View file

@ -35,6 +35,7 @@
#endif #endif
#endif #endif
#include "cmdlib.h" #include "cmdlib.h"
#include "i_system.h"
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
@ -192,13 +193,41 @@ bool DirEntryExists(const char *pathname, bool *isdir)
#else #else
// Windows must use the wide version of stat to preserve non-standard paths. // Windows must use the wide version of stat to preserve non-standard paths.
auto wstr = WideString(pathname); auto wstr = WideString(pathname);
struct _stat64i32 info; struct _stat64 info;
bool res = _wstat64i32(wstr.c_str(), &info) == 0; bool res = _wstat64(wstr.c_str(), &info) == 0;
#endif #endif
if (isdir) *isdir = !!(info.st_mode & S_IFDIR); if (isdir) *isdir = !!(info.st_mode & S_IFDIR);
return res; return res;
} }
//==========================================================================
//
// DirEntryExists
//
// Returns true if the given path exists, be it a directory or a file.
//
//==========================================================================
bool GetFileInfo(const char* pathname, size_t *size, time_t *time)
{
if (pathname == NULL || *pathname == 0)
return false;
#ifndef _WIN32
struct stat info;
bool res = stat(pathname, &info) == 0;
#else
// Windows must use the wide version of stat to preserve non-standard paths.
auto wstr = WideString(pathname);
struct _stat64 info;
bool res = _wstat64(wstr.c_str(), &info) == 0;
#endif
if (!res || (info.st_mode & S_IFDIR)) return false;
if (size) *size = info.st_size;
if (time) *time = info.st_mtime;
return res;
}
//========================================================================== //==========================================================================
// //
// DefaultExtension -- FString version // DefaultExtension -- FString version
@ -269,7 +298,7 @@ FString ExtractFileBase (const char *path, bool include_extension)
src--; src--;
// Check for files with drive specification but no path // Check for files with drive specification but no path
#if defined(_WIN32) || defined(DOS) #if defined(_WIN32)
if (src == path && src[0] != 0) if (src == path && src[0] != 0)
{ {
if (src[1] == ':') if (src[1] == ':')
@ -828,8 +857,6 @@ FString NicePath(const char *path)
} }
#ifdef _WIN32
//========================================================================== //==========================================================================
// //
// ScanDirectory // ScanDirectory
@ -838,13 +865,13 @@ FString NicePath(const char *path)
bool ScanDirectory(TArray<FFileList> &list, const char *dirpath) bool ScanDirectory(TArray<FFileList> &list, const char *dirpath)
{ {
struct _finddata_t fileinfo; findstate_t find;
intptr_t handle;
FString dirmatch; FString dirmatch;
dirmatch << dirpath << "*"; dirmatch << dirpath << "*";
if ((handle = _findfirst(dirmatch, &fileinfo)) == -1) auto handle = I_FindFirst(dirmatch.GetChars(), &find);
if (handle == ((void*)(-1)))
{ {
return false; return false;
} }
@ -852,25 +879,27 @@ bool ScanDirectory(TArray<FFileList> &list, const char *dirpath)
{ {
do do
{ {
if (fileinfo.attrib & _A_HIDDEN) auto attr = I_FindAttr(&find);
if (attr & FA_HIDDEN)
{ {
// Skip hidden files and directories. (Prevents SVN bookkeeping // Skip hidden files and directories. (Prevents SVN bookkeeping
// info from being included.) // info from being included.)
continue; continue;
} }
auto fn = I_FindName(&find);
if (fileinfo.attrib & _A_SUBDIR) if (attr & FA_DIREC)
{ {
if (fileinfo.name[0] == '.' && if (fn[0] == '.' &&
(fileinfo.name[1] == '\0' || (fn[1] == '\0' ||
(fileinfo.name[1] == '.' && fileinfo.name[2] == '\0'))) (fn[1] == '.' && fn[2] == '\0')))
{ {
// Do not record . and .. directories. // Do not record . and .. directories.
continue; continue;
} }
FFileList *fl = &list[list.Reserve(1)]; FFileList* fl = &list[list.Reserve(1)];
fl->Filename << dirpath << fileinfo.name; fl->Filename << dirpath << fn;
fl->isDirectory = true; fl->isDirectory = true;
FString newdir = fl->Filename; FString newdir = fl->Filename;
newdir << "/"; newdir << "/";
@ -878,107 +907,17 @@ bool ScanDirectory(TArray<FFileList> &list, const char *dirpath)
} }
else else
{ {
FFileList *fl = &list[list.Reserve(1)]; FFileList* fl = &list[list.Reserve(1)];
fl->Filename << dirpath << fileinfo.name; fl->Filename << dirpath << fn;
fl->isDirectory = false; fl->isDirectory = false;
} }
} }
while (_findnext(handle, &fileinfo) == 0); while (I_FindNext(handle, &find) == 0);
_findclose(handle); I_FindClose(handle);
} }
return true; return true;
} }
#elif defined(__sun) || defined(__linux__)
//==========================================================================
//
// ScanDirectory
// Solaris version
//
// Given NULL-terminated array of directory paths, create trees for them.
//
//==========================================================================
bool ScanDirectory(TArray<FFileList> &list, const char *dirpath)
{
DIR *directory = opendir(dirpath);
if(directory == NULL)
return false;
struct dirent *file;
while((file = readdir(directory)) != NULL)
{
if(file->d_name[0] == '.') //File is hidden or ./.. directory so ignore it.
continue;
FFileList *fl = &list[list.Reserve(1)];
fl->Filename << dirpath << file->d_name;
fl->isDirectory = DirExists(fl->Filename);
if(fl->isDirectory)
{
FString newdir = fl->Filename;
newdir += "/";
ScanDirectory(list, newdir);
continue;
}
}
closedir(directory);
return true;
}
#else
//==========================================================================
//
// ScanDirectory
// 4.4BSD version
//
//==========================================================================
bool ScanDirectory(TArray<FFileList> &list, const char *dirpath)
{
char * const argv[] = {new char[strlen(dirpath)+1], NULL };
memcpy(argv[0], dirpath, strlen(dirpath)+1);
FTS *fts;
FTSENT *ent;
fts = fts_open(argv, FTS_LOGICAL, NULL);
if (fts == NULL)
{
delete[] argv[0];
return false;
}
while ((ent = fts_read(fts)) != NULL)
{
if (ent->fts_info == FTS_D && ent->fts_name[0] == '.')
{
// Skip hidden directories. (Prevents SVN bookkeeping
// info from being included.)
fts_set(fts, ent, FTS_SKIP);
}
if (ent->fts_info == FTS_D && ent->fts_level == 0)
{
FFileList *fl = &list[list.Reserve(1)];
fl->Filename = ent->fts_path;
fl->isDirectory = true;
}
if (ent->fts_info == FTS_F)
{
// We're only interested in remembering files.
FFileList *fl = &list[list.Reserve(1)];
fl->Filename = ent->fts_path;
fl->isDirectory = false;
}
}
fts_close(fts);
delete[] argv[0];
return true;
}
#endif
//========================================================================== //==========================================================================
// //

View file

@ -30,6 +30,7 @@ typedef struct _GUID
bool FileExists (const char *filename); bool FileExists (const char *filename);
bool DirExists(const char *filename); bool DirExists(const char *filename);
bool DirEntryExists (const char *pathname, bool *isdir = nullptr); bool DirEntryExists (const char *pathname, bool *isdir = nullptr);
bool GetFileInfo(const char* pathname, size_t* size, time_t* time);
extern FString progdir; extern FString progdir;