2024-06-03 22:11:05 +03:00
|
|
|
#include <bh/internal/file.h>
|
|
|
|
|
|
|
|
|
|
static const bh_io_table_t bh_file_table = {
|
|
|
|
|
(int (*)(struct bh_io_s *, int)) bh_file_open_base,
|
|
|
|
|
(void (*)(struct bh_io_s *)) bh_file_close_base,
|
|
|
|
|
(int (*)(struct bh_io_s *)) bh_file_is_open_base,
|
|
|
|
|
(size_t (*)(struct bh_io_s *, char *, size_t)) bh_file_read_base,
|
|
|
|
|
(size_t (*)(struct bh_io_s *, const char *, size_t)) bh_file_write_base,
|
|
|
|
|
(void (*)(struct bh_io_s *)) bh_file_flush_base,
|
|
|
|
|
(int (*)(struct bh_io_s *, bh_off_t, int)) bh_file_seek_base,
|
|
|
|
|
(bh_off_t (*)(struct bh_io_s *)) bh_file_size_base,
|
|
|
|
|
(bh_off_t (*)(struct bh_io_s *)) bh_file_tell_base,
|
|
|
|
|
(bh_off_t (*)(struct bh_io_s *)) bh_file_available_base,
|
|
|
|
|
(void (*)(struct bh_io_s *)) bh_file_clear_base,
|
|
|
|
|
(void (*)(struct bh_io_s *)) bh_file_destroy
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
bh_file_t *bh_file_new(const char *path)
|
|
|
|
|
{
|
|
|
|
|
bh_file_t *result;
|
|
|
|
|
|
|
|
|
|
result = malloc(sizeof(*result));
|
|
|
|
|
if (result && bh_file_init(result, path))
|
|
|
|
|
{
|
|
|
|
|
free(result);
|
|
|
|
|
result = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void bh_file_free(bh_file_t *file)
|
|
|
|
|
{
|
|
|
|
|
bh_file_destroy(file);
|
|
|
|
|
free(file);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int bh_file_init(bh_file_t *file,
|
|
|
|
|
const char *path)
|
|
|
|
|
{
|
|
|
|
|
if (!path)
|
|
|
|
|
return BH_INVALID;
|
|
|
|
|
|
|
|
|
|
file->handle = INVALID_HANDLE_VALUE;
|
|
|
|
|
file->mode = 0;
|
|
|
|
|
file->path = strdup(path);
|
|
|
|
|
file->base.table = &bh_file_table;
|
|
|
|
|
|
|
|
|
|
return BH_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int bh_file_open_base(bh_file_t *file,
|
|
|
|
|
int mode)
|
|
|
|
|
{
|
|
|
|
|
DWORD access = 0, how = 0;
|
|
|
|
|
|
|
|
|
|
if (mode & BH_IO_READ)
|
|
|
|
|
access |= GENERIC_READ;
|
|
|
|
|
if (mode & BH_IO_WRITE)
|
|
|
|
|
access |= GENERIC_WRITE;
|
|
|
|
|
|
|
|
|
|
switch (mode & BH_IO_MASK)
|
|
|
|
|
{
|
|
|
|
|
case BH_IO_OPEN: how = OPEN_EXISTING; break;
|
|
|
|
|
case BH_IO_CREATE: how = CREATE_ALWAYS; break;
|
|
|
|
|
case BH_IO_APPEND: how = OPEN_ALWAYS; break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
case BH_IO_TRUNCATE:
|
|
|
|
|
return BH_NO_IMPL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
file->mode = mode;
|
|
|
|
|
file->handle = CreateFileA(file->path, access, FILE_SHARE_READ, NULL, how, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
|
|
|
|
|
|
|
|
if (file->handle == INVALID_HANDLE_VALUE)
|
|
|
|
|
{
|
|
|
|
|
/* Error handling */
|
|
|
|
|
switch (GetLastError())
|
|
|
|
|
{
|
|
|
|
|
case ERROR_FILE_EXISTS: return BH_FOUND;
|
|
|
|
|
case ERROR_FILE_NOT_FOUND: return BH_NOT_FOUND;
|
|
|
|
|
default: return BH_ERROR;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return BH_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void bh_file_close_base(bh_file_t *file)
|
|
|
|
|
{
|
|
|
|
|
if (file->handle != INVALID_HANDLE_VALUE)
|
|
|
|
|
CloseHandle(file->handle);
|
|
|
|
|
|
|
|
|
|
file->handle = INVALID_HANDLE_VALUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int bh_file_is_open_base(bh_file_t *file)
|
|
|
|
|
{
|
|
|
|
|
return file->handle != INVALID_HANDLE_VALUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void bh_file_destroy(bh_file_t *file)
|
|
|
|
|
{
|
|
|
|
|
bh_file_close(file);
|
|
|
|
|
free(file->path);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t bh_file_read_base(bh_file_t *file,
|
|
|
|
|
char *data,
|
|
|
|
|
size_t size)
|
|
|
|
|
{
|
|
|
|
|
DWORD readed;
|
|
|
|
|
|
|
|
|
|
if (!ReadFile(file->handle, data, (DWORD)size, &readed, NULL))
|
|
|
|
|
{
|
|
|
|
|
file->base.flags |= BH_IO_ERROR;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!readed)
|
|
|
|
|
file->base.flags |= BH_IO_EOF;
|
|
|
|
|
else
|
|
|
|
|
file->base.flags &= ~BH_IO_EOF;
|
|
|
|
|
|
|
|
|
|
return readed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t bh_file_write_base(bh_file_t *file,
|
|
|
|
|
const char *data,
|
|
|
|
|
size_t size)
|
|
|
|
|
{
|
|
|
|
|
DWORD written;
|
|
|
|
|
|
|
|
|
|
if ((file->mode & BH_IO_MASK) == BH_IO_APPEND)
|
|
|
|
|
bh_file_seek(file, 0, BH_IO_END);
|
|
|
|
|
|
|
|
|
|
if (!WriteFile(file->handle, data, (DWORD)size, &written, NULL))
|
|
|
|
|
{
|
|
|
|
|
file->base.flags |= BH_IO_ERROR;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!written)
|
|
|
|
|
file->base.flags |= BH_IO_EOF;
|
|
|
|
|
else
|
|
|
|
|
file->base.flags &= ~BH_IO_EOF;
|
|
|
|
|
|
|
|
|
|
return written;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void bh_file_flush_base(bh_file_t *file)
|
|
|
|
|
{
|
|
|
|
|
FlushFileBuffers(file->handle);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int bh_file_seek_base(bh_file_t *file,
|
|
|
|
|
bh_off_t pos,
|
|
|
|
|
int dir)
|
|
|
|
|
{
|
|
|
|
|
LARGE_INTEGER position;
|
|
|
|
|
|
|
|
|
|
position.QuadPart = pos;
|
|
|
|
|
if (SetFilePointerEx(file->handle, position, NULL, dir))
|
|
|
|
|
return BH_OK;
|
|
|
|
|
|
|
|
|
|
return BH_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bh_off_t bh_file_size_base(bh_file_t *file)
|
|
|
|
|
{
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bh_off_t bh_file_tell_base(bh_file_t *file)
|
|
|
|
|
{
|
|
|
|
|
LARGE_INTEGER dummy, position;
|
|
|
|
|
|
|
|
|
|
dummy.QuadPart = 0;
|
|
|
|
|
|
|
|
|
|
if (SetFilePointerEx(file->handle, dummy, &position, BH_IO_CURRENT))
|
|
|
|
|
return position.QuadPart;
|
|
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bh_off_t bh_file_available_base(bh_file_t *file)
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void bh_file_clear_base(bh_file_t *file)
|
|
|
|
|
{
|
|
|
|
|
file->base.flags &= ~BH_IO_ERROR;
|
|
|
|
|
}
|