- 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>
#ifdef _WIN32
#include <io.h>
#else
#include <fts.h>
#endif
#include "resourcefile.h"
#include "cmdlib.h"
#include "doomtype.h"
#include "i_system.h"
@ -71,12 +67,13 @@ struct FDirectoryLump : public FResourceLump
class FDirectory : public FResourceFile
{
TArray<FDirectoryLump> Lumps;
const bool nosubdir;
int AddDirectory(const char *dirpath);
void AddEntry(const char *fullpath, int size);
public:
FDirectory(const char * dirname);
FDirectory(const char * dirname, bool nosubdirflag = false);
bool Open(bool quiet);
virtual FResourceLump *GetLump(int no) { return ((unsigned)no < NumLumps)? &Lumps[no] : NULL; }
};
@ -89,8 +86,8 @@ public:
//
//==========================================================================
FDirectory::FDirectory(const char * directory)
: FResourceFile(NULL)
FDirectory::FDirectory(const char * directory, bool nosubdirflag)
: FResourceFile(NULL), nosubdir(nosubdirflag)
{
FString dirname;
@ -100,16 +97,15 @@ FDirectory::FDirectory(const char * directory)
// Todo for Linux: Resolve the path before using it
#endif
dirname = directory;
#ifdef _WIN32
free((void *)directory);
#endif
FixPathSeperator(dirname);
#ifdef _WIN32
free((void *)directory);
#endif
dirname.Substitute("\\", "/");
if (dirname[dirname.Len()-1] != '/') dirname += '/';
FileName = dirname;
}
#ifdef _WIN32
//==========================================================================
//
// Windows version
@ -118,15 +114,15 @@ FDirectory::FDirectory(const char * directory)
int FDirectory::AddDirectory(const char *dirpath)
{
struct _finddata_t fileinfo;
intptr_t handle;
FString dirmatch;
void * handle;
int count = 0;
dirmatch = dirpath;
FString dirmatch = dirpath;
findstate_t find;
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));
}
@ -134,113 +130,50 @@ int FDirectory::AddDirectory(const char *dirpath)
{
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
// info from being included.)
continue;
}
if (fileinfo.attrib & _A_SUBDIR)
FString fi = I_FindName(&find);
if (attr & FA_DIREC)
{
if (fileinfo.name[0] == '.' &&
(fileinfo.name[1] == '\0' ||
(fileinfo.name[1] == '.' && fileinfo.name[2] == '\0')))
if (nosubdir || (fi[0] == '.' &&
(fi[1] == '\0' ||
(fi[1] == '.' && fi[2] == '\0'))))
{
// Do not record . and .. directories.
continue;
}
FString newdir = dirpath;
newdir << fileinfo.name << '/';
newdir << fi << '/';
count += AddDirectory(newdir);
}
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;
}
AddEntry(FString(dirpath) + fileinfo.name, fileinfo.size);
count++;
size_t size = 0;
FString fn = FString(dirpath) + fi;
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;
}
#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];
auto data = Wads.OpenLumpReader(lumpnum);
if (!data.isOpen())
return nullptr;
for (size_t i = 0; i < countof(CreateInfo); i++)
{

View file

@ -35,6 +35,7 @@
#endif
#endif
#include "cmdlib.h"
#include "i_system.h"
#include <sys/types.h>
#include <sys/stat.h>
@ -192,13 +193,41 @@ bool DirEntryExists(const char *pathname, bool *isdir)
#else
// Windows must use the wide version of stat to preserve non-standard paths.
auto wstr = WideString(pathname);
struct _stat64i32 info;
bool res = _wstat64i32(wstr.c_str(), &info) == 0;
struct _stat64 info;
bool res = _wstat64(wstr.c_str(), &info) == 0;
#endif
if (isdir) *isdir = !!(info.st_mode & S_IFDIR);
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
@ -269,7 +298,7 @@ FString ExtractFileBase (const char *path, bool include_extension)
src--;
// 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[1] == ':')
@ -828,8 +857,6 @@ FString NicePath(const char *path)
}
#ifdef _WIN32
//==========================================================================
//
// ScanDirectory
@ -838,13 +865,13 @@ FString NicePath(const char *path)
bool ScanDirectory(TArray<FFileList> &list, const char *dirpath)
{
struct _finddata_t fileinfo;
intptr_t handle;
findstate_t find;
FString dirmatch;
dirmatch << dirpath << "*";
if ((handle = _findfirst(dirmatch, &fileinfo)) == -1)
auto handle = I_FindFirst(dirmatch.GetChars(), &find);
if (handle == ((void*)(-1)))
{
return false;
}
@ -852,25 +879,27 @@ bool ScanDirectory(TArray<FFileList> &list, const char *dirpath)
{
do
{
if (fileinfo.attrib & _A_HIDDEN)
auto attr = I_FindAttr(&find);
if (attr & FA_HIDDEN)
{
// Skip hidden files and directories. (Prevents SVN bookkeeping
// info from being included.)
continue;
}
auto fn = I_FindName(&find);
if (fileinfo.attrib & _A_SUBDIR)
if (attr & FA_DIREC)
{
if (fileinfo.name[0] == '.' &&
(fileinfo.name[1] == '\0' ||
(fileinfo.name[1] == '.' && fileinfo.name[2] == '\0')))
if (fn[0] == '.' &&
(fn[1] == '\0' ||
(fn[1] == '.' && fn[2] == '\0')))
{
// Do not record . and .. directories.
continue;
}
FFileList *fl = &list[list.Reserve(1)];
fl->Filename << dirpath << fileinfo.name;
FFileList* fl = &list[list.Reserve(1)];
fl->Filename << dirpath << fn;
fl->isDirectory = true;
FString newdir = fl->Filename;
newdir << "/";
@ -878,107 +907,17 @@ bool ScanDirectory(TArray<FFileList> &list, const char *dirpath)
}
else
{
FFileList *fl = &list[list.Reserve(1)];
fl->Filename << dirpath << fileinfo.name;
FFileList* fl = &list[list.Reserve(1)];
fl->Filename << dirpath << fn;
fl->isDirectory = false;
}
}
while (_findnext(handle, &fileinfo) == 0);
_findclose(handle);
while (I_FindNext(handle, &find) == 0);
I_FindClose(handle);
}
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 DirExists(const char *filename);
bool DirEntryExists (const char *pathname, bool *isdir = nullptr);
bool GetFileInfo(const char* pathname, size_t* size, time_t* time);
extern FString progdir;