This commit is contained in:
242
win32/File.c
Normal file
242
win32/File.c
Normal file
@@ -0,0 +1,242 @@
|
||||
#include "../CgeFile.h"
|
||||
#include <windows.h>
|
||||
|
||||
struct CgeFile {
|
||||
HANDLE handle;
|
||||
int flags;
|
||||
int mode;
|
||||
int lastError;
|
||||
};
|
||||
|
||||
static int errorCodeFromError(void) {
|
||||
DWORD error;
|
||||
|
||||
error = GetLastError();
|
||||
switch (error) {
|
||||
case ERROR_NOT_ENOUGH_MEMORY:
|
||||
return CGE_FILE_EOOM;
|
||||
|
||||
case ERROR_FILE_NOT_FOUND:
|
||||
case ERROR_PATH_NOT_FOUND:
|
||||
return CGE_FILE_ENOENT;
|
||||
|
||||
case ERROR_ACCESS_DENIED:
|
||||
return CGE_FILE_EACCES;
|
||||
|
||||
case ERROR_FILE_EXISTS:
|
||||
case ERROR_ALREADY_EXISTS:
|
||||
return CGE_FILE_EEXIST;
|
||||
|
||||
case ERROR_DIRECTORY:
|
||||
return CGE_FILE_EISDIR;
|
||||
|
||||
case ERROR_WRITE_PROTECT:
|
||||
return CGE_FILE_EROFS;
|
||||
|
||||
case ERROR_TOO_MANY_OPEN_FILES:
|
||||
return CGE_FILE_EMFILE;
|
||||
|
||||
case ERROR_INVALID_NAME:
|
||||
case ERROR_FILENAME_EXCED_RANGE:
|
||||
return CGE_FILE_ENAMETOOLONG;
|
||||
|
||||
case ERROR_DISK_FULL:
|
||||
case ERROR_HANDLE_DISK_FULL:
|
||||
return CGE_FILE_ENOSPC;
|
||||
|
||||
default:
|
||||
return CGE_FILE_EUNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
static int fileInit(CgeFile *file, const char *path, int mode) {
|
||||
DWORD access = 0, how = 0;
|
||||
|
||||
if (!path)
|
||||
return CGE_FILE_EINVAL;
|
||||
|
||||
if (mode & CGE_FILE_READ)
|
||||
access |= GENERIC_READ;
|
||||
if (mode & CGE_FILE_WRITE)
|
||||
access |= GENERIC_WRITE;
|
||||
|
||||
if (!access)
|
||||
return CGE_FILE_EINVAL;
|
||||
|
||||
if (mode & CGE_FILE_TRUNCATE) {
|
||||
switch (mode & (CGE_FILE_CREATE | CGE_FILE_EXIST)) {
|
||||
case 0: how = CREATE_ALWAYS; break;
|
||||
case CGE_FILE_CREATE: how = CREATE_NEW; break;
|
||||
case CGE_FILE_EXIST: how = TRUNCATE_EXISTING; break;
|
||||
default: return CGE_FILE_EINVAL;
|
||||
}
|
||||
} else {
|
||||
switch (mode & (CGE_FILE_CREATE | CGE_FILE_EXIST)) {
|
||||
case 0: how = OPEN_ALWAYS; break;
|
||||
case CGE_FILE_CREATE: how = CREATE_NEW; break;
|
||||
case CGE_FILE_EXIST: how = OPEN_EXISTING; break;
|
||||
default: return CGE_FILE_EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
file->flags = 0;
|
||||
file->mode = mode;
|
||||
file->handle = CreateFileA(path, access, FILE_SHARE_READ, NULL, how, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
|
||||
if (file->handle == INVALID_HANDLE_VALUE)
|
||||
return errorCodeFromError();
|
||||
|
||||
if (mode & CGE_FILE_TRUNCATE)
|
||||
SetEndOfFile(file->handle);
|
||||
|
||||
return CGE_FILE_EOK;
|
||||
}
|
||||
|
||||
CgeFile *CgeFileNew(const char *path, int mode, int *result) {
|
||||
CgeFile *file;
|
||||
int code = 0;
|
||||
|
||||
if ((file = malloc(sizeof(*file)))) {
|
||||
if ((code = fileInit(file, path, mode))) {
|
||||
free(file);
|
||||
file = NULL;
|
||||
}
|
||||
}
|
||||
if (result) *result = code;
|
||||
return file;
|
||||
}
|
||||
|
||||
void CgeFileFree(CgeFile *file) {
|
||||
CloseHandle(file->handle);
|
||||
free(file);
|
||||
}
|
||||
|
||||
int CgeFileRead(CgeFile *file, char *buffer, size_t size, size_t *actual) {
|
||||
DWORD readed;
|
||||
|
||||
if (file->flags & CGE_FILE_ERROR)
|
||||
return 0;
|
||||
|
||||
if (!ReadFile(file->handle, buffer, (DWORD)size, &readed, NULL))
|
||||
goto error;
|
||||
|
||||
if (!readed) file->flags |= CGE_FILE_EOF;
|
||||
else file->flags &= ~CGE_FILE_EOF;
|
||||
if (actual) *actual = readed;
|
||||
|
||||
return 1;
|
||||
|
||||
error:
|
||||
file->flags |= CGE_FILE_ERROR;
|
||||
file->lastError = errorCodeFromError();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CgeFileWrite(CgeFile *file, const char *buffer, size_t size,
|
||||
size_t *actual) {
|
||||
DWORD written;
|
||||
LARGE_INTEGER position;
|
||||
|
||||
if (file->flags & CGE_FILE_ERROR)
|
||||
return 0;
|
||||
|
||||
if (file->mode & CGE_FILE_APPEND) {
|
||||
position.QuadPart = 0;
|
||||
if (!SetFilePointerEx(file->handle, position, NULL, FILE_END))
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!WriteFile(file->handle, buffer, (DWORD)size, &written, NULL))
|
||||
goto error;
|
||||
|
||||
if (actual) *actual = written;
|
||||
|
||||
return 1;
|
||||
|
||||
error:
|
||||
file->flags |= CGE_FILE_ERROR;
|
||||
file->lastError = errorCodeFromError();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CgeFileTell(CgeFile *file, int64_t *offset) {
|
||||
LARGE_INTEGER dummy, position;
|
||||
|
||||
if (file->flags & CGE_FILE_ERROR)
|
||||
return 0;
|
||||
|
||||
dummy.QuadPart = 0;
|
||||
if (!SetFilePointerEx(file->handle, dummy, &position, FILE_CURRENT))
|
||||
goto error;
|
||||
|
||||
*offset = position.QuadPart;
|
||||
return 1;
|
||||
|
||||
error:
|
||||
file->flags |= CGE_FILE_ERROR;
|
||||
file->lastError = errorCodeFromError();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CgeFileSeek(CgeFile *file, int64_t offset, int whence) {
|
||||
LARGE_INTEGER position;
|
||||
|
||||
if (file->flags & CGE_FILE_ERROR)
|
||||
return 0;
|
||||
|
||||
position.QuadPart = offset;
|
||||
if (!SetFilePointerEx(file->handle, position, NULL, whence))
|
||||
goto error;
|
||||
|
||||
file->flags &= ~CGE_FILE_EOF;
|
||||
return 1;
|
||||
|
||||
error:
|
||||
file->flags |= CGE_FILE_ERROR;
|
||||
file->lastError = errorCodeFromError();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CgeFileFlush(CgeFile *file) {
|
||||
if (!FlushFileBuffers(file->handle))
|
||||
goto error;
|
||||
|
||||
return 1;
|
||||
|
||||
error:
|
||||
file->flags |= CGE_FILE_ERROR;
|
||||
file->lastError = errorCodeFromError();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CgeFileSize(CgeFile *file, int64_t *size) {
|
||||
LARGE_INTEGER dummy;
|
||||
|
||||
if (file->flags & CGE_FILE_ERROR)
|
||||
return 0;
|
||||
|
||||
if (!GetFileSizeEx(file->handle, &dummy))
|
||||
goto error;
|
||||
|
||||
*size = dummy.QuadPart;
|
||||
return 1;
|
||||
|
||||
error:
|
||||
file->flags |= CGE_FILE_ERROR;
|
||||
file->lastError = errorCodeFromError();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CgeFileFlags(CgeFile *file, int *flags) {
|
||||
*flags = file->flags;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CgeFileClear(CgeFile *file) {
|
||||
file->flags &= ~CGE_FILE_ERROR;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CgeFileErrorCode(CgeFile *file) {
|
||||
return file->lastError;
|
||||
}
|
||||
Reference in New Issue
Block a user