fix fs_listdir and fs_listdir_fileinfo with unicode on windows

This commit is contained in:
Robert Müller 2021-08-23 12:49:15 +02:00
parent 75662b6c1a
commit 4a375242c5
8 changed files with 141 additions and 87 deletions

View file

@ -1987,19 +1987,38 @@ void net_unix_close(UNIXSOCKET sock)
}
#endif
int fs_listdir_info(const char *dir, FS_LISTDIR_INFO_CALLBACK cb, int type, void *user)
#if defined (CONF_FAMILY_WINDOWS)
static inline time_t filetime_to_unixtime(LPFILETIME filetime)
{
time_t t;
ULARGE_INTEGER li;
li.LowPart = filetime->dwLowDateTime;
li.HighPart = filetime->dwHighDateTime;
li.QuadPart /= 10000000; // 100ns to 1s
li.QuadPart -= 11644473600LL; // Windows epoch is in the past
t = li.QuadPart;
return t == li.QuadPart ? t : (time_t)-1;
}
#endif
void fs_listdir(const char *dir, FS_LISTDIR_CALLBACK cb, int type, void *user)
{
#if defined(CONF_FAMILY_WINDOWS)
WIN32_FIND_DATA finddata;
WIN32_FIND_DATAW finddata;
HANDLE handle;
char buffer[1024 * 2];
char buffer[IO_MAX_PATH_LENGTH];
char buffer2[IO_MAX_PATH_LENGTH];
WCHAR wBuffer[IO_MAX_PATH_LENGTH];
int length;
str_format(buffer, sizeof(buffer), "%s/*", dir);
MultiByteToWideChar(CP_UTF8, 0, buffer, IO_MAX_PATH_LENGTH, wBuffer, IO_MAX_PATH_LENGTH);
handle = FindFirstFileA(buffer, &finddata);
handle = FindFirstFileW(wBuffer, &finddata);
if(handle == INVALID_HANDLE_VALUE)
return 0;
return;
str_format(buffer, sizeof(buffer), "%s/", dir);
length = str_length(buffer);
@ -2007,87 +2026,105 @@ int fs_listdir_info(const char *dir, FS_LISTDIR_INFO_CALLBACK cb, int type, void
/* add all the entries */
do
{
str_copy(buffer + length, finddata.cFileName, (int)sizeof(buffer) - length);
if(cb(finddata.cFileName, fs_getmtime(buffer), fs_is_dir(buffer), type, user))
break;
} while(FindNextFileA(handle, &finddata));
FindClose(handle);
return 0;
#else
struct dirent *entry;
char buffer[1024 * 2];
int length;
DIR *d = opendir(dir);
if(!d)
return 0;
str_format(buffer, sizeof(buffer), "%s/", dir);
length = str_length(buffer);
while((entry = readdir(d)) != NULL)
{
str_copy(buffer + length, entry->d_name, (int)sizeof(buffer) - length);
if(cb(entry->d_name, fs_getmtime(buffer), fs_is_dir(buffer), type, user))
WideCharToMultiByte(CP_UTF8, 0, finddata.cFileName, -1, buffer2, IO_MAX_PATH_LENGTH, NULL, NULL);
str_copy(buffer+length, buffer2, (int)sizeof(buffer)-length);
if(cb(buffer2, fs_is_dir(buffer), type, user))
break;
}
/* close the directory and return */
closedir(d);
return 0;
#endif
}
int fs_listdir(const char *dir, FS_LISTDIR_CALLBACK cb, int type, void *user)
{
#if defined(CONF_FAMILY_WINDOWS)
WIN32_FIND_DATA finddata;
HANDLE handle;
char buffer[1024 * 2];
int length;
str_format(buffer, sizeof(buffer), "%s/*", dir);
handle = FindFirstFileA(buffer, &finddata);
if(handle == INVALID_HANDLE_VALUE)
return 0;
str_format(buffer, sizeof(buffer), "%s/", dir);
length = str_length(buffer);
/* add all the entries */
do
{
str_copy(buffer + length, finddata.cFileName, (int)sizeof(buffer) - length);
if(cb(finddata.cFileName, fs_is_dir(buffer), type, user))
break;
} while(FindNextFileA(handle, &finddata));
while(FindNextFileW(handle, &finddata));
FindClose(handle);
return 0;
#else
struct dirent *entry;
char buffer[1024 * 2];
char buffer[IO_MAX_PATH_LENGTH];
int length;
DIR *d = opendir(dir);
if(!d)
return 0;
return;
str_format(buffer, sizeof(buffer), "%s/", dir);
length = str_length(buffer);
while((entry = readdir(d)) != NULL)
{
str_copy(buffer + length, entry->d_name, (int)sizeof(buffer) - length);
str_copy(buffer+length, entry->d_name, (int)sizeof(buffer)-length);
if(cb(entry->d_name, fs_is_dir(buffer), type, user))
break;
}
/* close the directory and return */
closedir(d);
return 0;
#endif
}
void fs_listdir_fileinfo(const char *dir, FS_LISTDIR_CALLBACK_FILEINFO cb, int type, void *user)
{
#if defined(CONF_FAMILY_WINDOWS)
WIN32_FIND_DATAW finddata;
HANDLE handle;
char buffer[IO_MAX_PATH_LENGTH];
char buffer2[IO_MAX_PATH_LENGTH];
WCHAR wBuffer[IO_MAX_PATH_LENGTH];
int length;
str_format(buffer, sizeof(buffer), "%s/*", dir);
MultiByteToWideChar(CP_UTF8, 0, buffer, IO_MAX_PATH_LENGTH, wBuffer, IO_MAX_PATH_LENGTH);
handle = FindFirstFileW(wBuffer, &finddata);
if(handle == INVALID_HANDLE_VALUE)
return;
str_format(buffer, sizeof(buffer), "%s/", dir);
length = str_length(buffer);
/* add all the entries */
do
{
WideCharToMultiByte(CP_UTF8, 0, finddata.cFileName, -1, buffer2, IO_MAX_PATH_LENGTH, NULL, NULL);
str_copy(buffer+length, buffer2, (int)sizeof(buffer)-length);
CFsFileInfo info;
info.m_pName = buffer2;
info.m_TimeCreated = filetime_to_unixtime(&finddata.ftCreationTime);
info.m_TimeModified = filetime_to_unixtime(&finddata.ftLastWriteTime);
if(cb(&info, fs_is_dir(buffer), type, user))
break;
}
while(FindNextFileW(handle, &finddata));
FindClose(handle);
#else
struct dirent *entry;
time_t created = -1, modified = -1;
char buffer[IO_MAX_PATH_LENGTH];
int length;
DIR *d = opendir(dir);
if(!d)
return;
str_format(buffer, sizeof(buffer), "%s/", dir);
length = str_length(buffer);
while((entry = readdir(d)) != NULL)
{
CFsFileInfo info;
str_copy(buffer+length, entry->d_name, (int)sizeof(buffer)-length);
fs_file_time(buffer, &created, &modified);
info.m_pName = entry->d_name;
info.m_TimeCreated = created;
info.m_TimeModified = modified;
if(cb(&info, fs_is_dir(buffer), type, user))
break;
}
/* close the directory and return */
closedir(d);
#endif
}

View file

@ -174,7 +174,9 @@ enum
IOSEEK_START = 0,
IOSEEK_CUR = 1,
IOSEEK_END = 2
IOSEEK_END = 2,
IO_MAX_PATH_LENGTH = 512,
};
typedef struct IOINTERNAL *IOHANDLE;
@ -1597,14 +1599,29 @@ void str_escape(char **dst, const char *src, const char *end);
cb - Callback function to call for each entry
type - Type of the directory
user - Pointer to give to the callback
Returns:
Always returns 0.
*/
typedef int (*FS_LISTDIR_CALLBACK)(const char *name, int is_dir, int dir_type, void *user);
typedef int (*FS_LISTDIR_INFO_CALLBACK)(const char *name, time_t date, int is_dir, int dir_type, void *user);
int fs_listdir(const char *dir, FS_LISTDIR_CALLBACK cb, int type, void *user);
int fs_listdir_info(const char *dir, FS_LISTDIR_INFO_CALLBACK cb, int type, void *user);
void fs_listdir(const char *dir, FS_LISTDIR_CALLBACK cb, int type, void *user);
typedef struct
{
const char *m_pName;
time_t m_TimeCreated; // seconds since UNIX Epoch
time_t m_TimeModified; // seconds since UNIX Epoch
} CFsFileInfo;
/*
Function: fs_listdir_fileinfo
Lists the files in a directory and gets additional file information
Parameters:
dir - Directory to list
cb - Callback function to call for each entry
type - Type of the directory
user - Pointer to give to the callback
*/
typedef int (*FS_LISTDIR_CALLBACK_FILEINFO)(const CFsFileInfo *info, int is_dir, int dir_type, void *user);
void fs_listdir_fileinfo(const char *dir, FS_LISTDIR_CALLBACK_FILEINFO cb, int type, void *user);
/*
Function: fs_makedir

View file

@ -300,19 +300,19 @@ public:
// no binary directory found, use $PATH on Posix, $PWD on Windows
}
virtual void ListDirectoryInfo(int Type, const char *pPath, FS_LISTDIR_INFO_CALLBACK pfnCallback, void *pUser)
virtual void ListDirectoryInfo(int Type, const char *pPath, FS_LISTDIR_CALLBACK_FILEINFO pfnCallback, void *pUser)
{
char aBuffer[MAX_PATH_LENGTH];
if(Type == TYPE_ALL)
{
// list all available directories
for(int i = 0; i < m_NumPaths; ++i)
fs_listdir_info(GetPath(i, pPath, aBuffer, sizeof(aBuffer)), pfnCallback, i, pUser);
fs_listdir_fileinfo(GetPath(i, pPath, aBuffer, sizeof(aBuffer)), pfnCallback, i, pUser);
}
else if(Type >= 0 && Type < m_NumPaths)
{
// list wanted directory
fs_listdir_info(GetPath(Type, pPath, aBuffer, sizeof(aBuffer)), pfnCallback, Type, pUser);
fs_listdir_fileinfo(GetPath(Type, pPath, aBuffer, sizeof(aBuffer)), pfnCallback, Type, pUser);
}
}

View file

@ -27,7 +27,7 @@ public:
};
virtual void ListDirectory(int Type, const char *pPath, FS_LISTDIR_CALLBACK pfnCallback, void *pUser) = 0;
virtual void ListDirectoryInfo(int Type, const char *pPath, FS_LISTDIR_INFO_CALLBACK pfnCallback, void *pUser) = 0;
virtual void ListDirectoryInfo(int Type, const char *pPath, FS_LISTDIR_CALLBACK_FILEINFO pfnCallback, void *pUser) = 0;
virtual IOHANDLE OpenFile(const char *pFilename, int Flags, int Type, char *pBuffer = 0, int BufferSize = 0) = 0;
virtual bool FindFile(const char *pFilename, const char *pPath, int Type, char *pBuffer, int BufferSize) = 0;
virtual bool RemoveFile(const char *pFilename, int Type) = 0;

View file

@ -442,7 +442,7 @@ protected:
void DemolistOnUpdate(bool Reset);
//void DemolistPopulate();
static int DemolistFetchCallback(const char *pName, time_t Date, int IsDir, int StorageType, void *pUser);
static int DemolistFetchCallback(const CFsFileInfo *pInfo, int IsDir, int StorageType, void *pUser);
// friends
struct CFriendItem

View file

@ -740,28 +740,28 @@ int CMenus::UiLogicGetCurrentClickedItem()
return -1;
}
int CMenus::DemolistFetchCallback(const char *pName, time_t Date, int IsDir, int StorageType, void *pUser)
int CMenus::DemolistFetchCallback(const CFsFileInfo *pInfo, int IsDir, int StorageType, void *pUser)
{
CMenus *pSelf = (CMenus *)pUser;
if(str_comp(pName, ".") == 0 || (str_comp(pName, "..") == 0 && str_comp(pSelf->m_aCurrentDemoFolder, "demos") == 0) || (!IsDir && !str_endswith(pName, ".demo")))
if(str_comp(pInfo->m_pName, ".") == 0 || (str_comp(pInfo->m_pName, "..") == 0 && str_comp(pSelf->m_aCurrentDemoFolder, "demos") == 0) || (!IsDir && !str_endswith(pInfo->m_pName, ".demo")))
{
return 0;
}
CDemoItem Item;
str_copy(Item.m_aFilename, pName, sizeof(Item.m_aFilename));
str_copy(Item.m_aFilename, pInfo->m_pName, sizeof(Item.m_aFilename));
if(IsDir)
{
str_format(Item.m_aName, sizeof(Item.m_aName), "%s/", pName);
str_format(Item.m_aName, sizeof(Item.m_aName), "%s/", pInfo->m_pName);
Item.m_InfosLoaded = false;
Item.m_Valid = false;
Item.m_Date = 0;
}
else
{
str_truncate(Item.m_aName, sizeof(Item.m_aName), pName, str_length(pName) - 5);
str_truncate(Item.m_aName, sizeof(Item.m_aName), pInfo->m_pName, str_length(pInfo->m_pName) - 5);
Item.m_InfosLoaded = false;
Item.m_Date = Date;
Item.m_Date = pInfo->m_TimeModified;
}
Item.m_IsDir = IsDir != 0;
Item.m_StorageType = StorageType;

View file

@ -175,15 +175,15 @@ void CRaceDemo::StopRecord(int Time)
m_RecordStopTick = -1;
}
int CRaceDemo::RaceDemolistFetchCallback(const char *pName, time_t Date, int IsDir, int StorageType, void *pUser)
int CRaceDemo::RaceDemolistFetchCallback(const CFsFileInfo *pInfo, int IsDir, int StorageType, void *pUser)
{
CDemoListParam *pParam = (CDemoListParam *)pUser;
int MapLen = str_length(pParam->pMap);
if(IsDir || !str_endswith(pName, ".demo") || !str_startswith(pName, pParam->pMap) || pName[MapLen] != '_')
if(IsDir || !str_endswith(pInfo->m_pName, ".demo") || !str_startswith(pInfo->m_pName, pParam->pMap) || pInfo->m_pName[MapLen] != '_')
return 0;
CDemoItem Item;
str_truncate(Item.m_aName, sizeof(Item.m_aName), pName, str_length(pName) - 5);
str_truncate(Item.m_aName, sizeof(Item.m_aName), pInfo->m_pName, str_length(pInfo->m_pName) - 5);
const char *pTime = Item.m_aName + MapLen + 1;
const char *pTEnd = pTime;

View file

@ -25,7 +25,7 @@ class CRaceDemo : public CComponent
int m_RecordStopTick;
int m_Time;
static int RaceDemolistFetchCallback(const char *pName, time_t Date, int IsDir, int StorageType, void *pUser);
static int RaceDemolistFetchCallback(const CFsFileInfo *pInfo, int IsDir, int StorageType, void *pUser);
void GetPath(char *pBuf, int Size, int Time = -1) const;