This commit is contained in:
180
win32/Dir.c
Normal file
180
win32/Dir.c
Normal file
@@ -0,0 +1,180 @@
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include "../CgeFs.h"
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef MAX_PATH
|
||||
#define MAX_PATH 260
|
||||
#endif
|
||||
|
||||
typedef struct CgeFsDir {
|
||||
HANDLE handle;
|
||||
WIN32_FIND_DATAW findData;
|
||||
int hasEntry;
|
||||
} CgeFsDir;
|
||||
|
||||
static int utf8ToWchar(const char *utf8, wchar_t *out, int size) {
|
||||
int len;
|
||||
|
||||
if (!utf8 || !out || size <= 0)
|
||||
return 0;
|
||||
|
||||
len = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, out, size);
|
||||
if (len <= 0 || len > size) {
|
||||
out[0] = L'\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void wcharToUtf8(const wchar_t *w, char *out, int size) {
|
||||
int len;
|
||||
|
||||
if (!w || !out || size <= 0) {
|
||||
out[0] = '\0';
|
||||
}
|
||||
|
||||
len = WideCharToMultiByte(CP_UTF8, 0, w, -1, out, size, NULL, NULL);
|
||||
if (len <= 0 || len > size)
|
||||
out[0] = '\0';
|
||||
}
|
||||
|
||||
static int mapWinError(DWORD value) {
|
||||
switch (value) {
|
||||
case ERROR_FILE_NOT_FOUND:
|
||||
case ERROR_PATH_NOT_FOUND:
|
||||
return CGE_FS_ENOENT;
|
||||
|
||||
case ERROR_ACCESS_DENIED:
|
||||
return CGE_FS_EACCES;
|
||||
|
||||
case ERROR_DIRECTORY:
|
||||
return CGE_FS_ENOTDIR;
|
||||
|
||||
default:
|
||||
return CGE_FS_EUNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t fileTimeToUint64(const FILETIME *ft) {
|
||||
ULARGE_INTEGER u;
|
||||
u.LowPart = ft->dwLowDateTime;
|
||||
u.HighPart = ft->dwHighDateTime;
|
||||
return u.QuadPart / 10000000ULL - 11644473600ULL;
|
||||
}
|
||||
|
||||
CgeFsDir *CgeFsOpen(const char *path, int *result) {
|
||||
wchar_t findPathW[MAX_PATH];
|
||||
char findPathA[MAX_PATH * 4];
|
||||
size_t size;
|
||||
CgeFsDir *d;
|
||||
|
||||
snprintf(findPathA, sizeof(findPathA), "%s\\*", path);
|
||||
|
||||
d = malloc(sizeof(*d));
|
||||
if (!d) {
|
||||
if (result)
|
||||
*result = CGE_FS_EUNKNOWN;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
d->handle = INVALID_HANDLE_VALUE;
|
||||
d->hasEntry = 0;
|
||||
|
||||
if (!utf8ToWchar(findPathA, findPathW, MAX_PATH)) {
|
||||
if (result)
|
||||
*result = CGE_FS_EUNKNOWN;
|
||||
free(d);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
d->handle = FindFirstFileW(findPathW, &d->findData);
|
||||
if (d->handle == INVALID_HANDLE_VALUE) {
|
||||
if (result)
|
||||
*result = mapWinError(GetLastError());
|
||||
free(d);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
d->hasEntry = 1;
|
||||
return d;
|
||||
}
|
||||
|
||||
int CgeFsNext(CgeFsDir *d, CgeFsInfo *info, int *result) {
|
||||
WIN32_FIND_DATAW *ent;
|
||||
char nameUtf8[CGE_FS_NAME_MAX];
|
||||
|
||||
while (d->hasEntry) {
|
||||
ent = &d->findData;
|
||||
d->hasEntry = 0;
|
||||
|
||||
if (!wcscmp(ent->cFileName, L".") || !wcscmp(ent->cFileName, L"..")) {
|
||||
if (FindNextFileW(d->handle, &d->findData) != 0)
|
||||
d->hasEntry = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
wcharToUtf8(ent->cFileName, nameUtf8, sizeof(nameUtf8));
|
||||
|
||||
strncpy(info->name, nameUtf8, CGE_FS_NAME_MAX - 1);
|
||||
info->name[CGE_FS_NAME_MAX - 1] = '\0';
|
||||
info->type = (ent->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? CGE_FS_DIR : CGE_FS_FILE;
|
||||
info->size = ((uint64_t)ent->nFileSizeHigh << 32) | ent->nFileSizeLow;
|
||||
info->mtime = (uint64_t)(fileTimeToUint64(&ent->ftLastWriteTime));
|
||||
|
||||
if (FindNextFileW(d->handle, &d->findData) != 0)
|
||||
d->hasEntry = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (result)
|
||||
*result = CGE_FS_EEOF;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CgeFsClose(CgeFsDir *d) {
|
||||
if (!d)
|
||||
return;
|
||||
|
||||
if (d->handle != INVALID_HANDLE_VALUE)
|
||||
FindClose(d->handle);
|
||||
free(d);
|
||||
}
|
||||
|
||||
int CgeFsCreateDir(const char *path, int *result) {
|
||||
wchar_t wpath[MAX_PATH];
|
||||
|
||||
if (!utf8ToWchar(path, wpath, MAX_PATH)) {
|
||||
if (result)
|
||||
*result = CGE_FS_EUNKNOWN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (CreateDirectoryW(wpath, NULL) == 0) {
|
||||
if (result)
|
||||
*result = mapWinError(GetLastError());
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CgeFsRemoveDir(const char *path, int *result) {
|
||||
wchar_t wpath[MAX_PATH];
|
||||
|
||||
if (!utf8ToWchar(path, wpath, MAX_PATH)) {
|
||||
if (result)
|
||||
*result = CGE_FS_EUNKNOWN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (RemoveDirectoryW(wpath) == 0) {
|
||||
if (result)
|
||||
*result = mapWinError(GetLastError());
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
Reference in New Issue
Block a user