#define WIN32_LEAN_AND_MEAN #include "../CgeFs.h" #include #include #include #include #ifndef MAX_PATH #define MAX_PATH 260 #endif struct CgeFsDir { HANDLE handle; WIN32_FIND_DATAW findData; int hasEntry; }; static int utf8ToWchar(const char *utf8, wchar_t *out, int size) { int len; if (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; 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]; 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; }