Move platform-dependent code into it's own directory
This commit is contained in:
200
src/Platform/Dummy/File.c
Normal file
200
src/Platform/Dummy/File.c
Normal file
@@ -0,0 +1,200 @@
|
||||
#include <BH/IO.h>
|
||||
|
||||
typedef struct BH_File
|
||||
{
|
||||
int implement;
|
||||
int me;
|
||||
} BH_File;
|
||||
|
||||
|
||||
static int BH_FileInfo(BH_File *file,
|
||||
size_t *size,
|
||||
const char **name);
|
||||
|
||||
|
||||
static int BH_FileInit(BH_File *file,
|
||||
const char *path);
|
||||
|
||||
|
||||
static int BH_FileDestroy(BH_File *file);
|
||||
|
||||
|
||||
static int BH_FileOpen(BH_File *file,
|
||||
int *mode);
|
||||
|
||||
|
||||
static int BH_FileClose(BH_File *file);
|
||||
|
||||
|
||||
static int BH_FileRead(BH_File *file,
|
||||
char *data,
|
||||
size_t *size);
|
||||
|
||||
|
||||
static int BH_FileWrite(BH_File *file,
|
||||
const char *data,
|
||||
size_t *size);
|
||||
|
||||
|
||||
static int BH_FilePeek(BH_File* file,
|
||||
char *data,
|
||||
size_t *size);
|
||||
|
||||
|
||||
static int BH_FileFlush(BH_File *file);
|
||||
|
||||
|
||||
static int BH_FileSeek(BH_File *file,
|
||||
int64_t *pos,
|
||||
int *dir);
|
||||
|
||||
|
||||
static int BH_FileTell(BH_File *file,
|
||||
int64_t *pos);
|
||||
|
||||
|
||||
static int BH_FileSize(BH_File *file,
|
||||
int64_t *size);
|
||||
|
||||
|
||||
static int BH_FileFlags(BH_File *file);
|
||||
|
||||
|
||||
static int BH_FileClear(BH_File *file);
|
||||
|
||||
|
||||
static int BH_FileInfo(BH_File *file,
|
||||
size_t *size,
|
||||
const char **name)
|
||||
{
|
||||
static const char classname[] = BH_FILE_CLASSNAME;
|
||||
|
||||
if (size)
|
||||
*size = sizeof(*file);
|
||||
if (name)
|
||||
*name = classname;
|
||||
|
||||
return BH_NOIMPL;
|
||||
}
|
||||
|
||||
|
||||
static int BH_FileInit(BH_File *file,
|
||||
const char *path)
|
||||
{
|
||||
return BH_NOIMPL;
|
||||
}
|
||||
|
||||
|
||||
static int BH_FileDestroy(BH_File *file)
|
||||
{
|
||||
return BH_NOIMPL;
|
||||
}
|
||||
|
||||
|
||||
static int BH_FileOpen(BH_File *file,
|
||||
int *mode)
|
||||
{
|
||||
return BH_NOIMPL;
|
||||
}
|
||||
|
||||
|
||||
static int BH_FileClose(BH_File *file)
|
||||
{
|
||||
return BH_NOIMPL;
|
||||
}
|
||||
|
||||
|
||||
static int BH_FileRead(BH_File *file,
|
||||
char *data,
|
||||
size_t *size)
|
||||
{
|
||||
return BH_NOIMPL;
|
||||
}
|
||||
|
||||
|
||||
static int BH_FileWrite(BH_File *file,
|
||||
const char *data,
|
||||
size_t *size)
|
||||
{
|
||||
return BH_NOIMPL;
|
||||
}
|
||||
|
||||
|
||||
static int BH_FilePeek(BH_File *file,
|
||||
char *data,
|
||||
size_t *size)
|
||||
{
|
||||
return BH_NOIMPL;
|
||||
}
|
||||
|
||||
|
||||
static int BH_FileFlush(BH_File *file)
|
||||
{
|
||||
return BH_NOIMPL;
|
||||
}
|
||||
|
||||
|
||||
static int BH_FileSeek(BH_File *file,
|
||||
int64_t *pos,
|
||||
int *dir)
|
||||
{
|
||||
return BH_NOIMPL;
|
||||
}
|
||||
|
||||
|
||||
static int BH_FileTell(BH_File *file,
|
||||
int64_t *pos)
|
||||
{
|
||||
return BH_NOIMPL;
|
||||
}
|
||||
|
||||
|
||||
static int BH_FileSize(BH_File *file,
|
||||
int64_t *size)
|
||||
{
|
||||
return BH_NOIMPL;
|
||||
}
|
||||
|
||||
|
||||
static int BH_FileFlags(BH_File *file)
|
||||
{
|
||||
return BH_IO_FLAG_ERROR;
|
||||
}
|
||||
|
||||
|
||||
static int BH_FileClear(BH_File *file)
|
||||
{
|
||||
return BH_NOIMPL;
|
||||
}
|
||||
|
||||
|
||||
static int BH_FileCallback(BH_File *file,
|
||||
int type,
|
||||
void *arg1,
|
||||
void *arg2)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case BH_IO_INFO_CB: return BH_FileInfo(file, (size_t *)arg1, (const char **)arg2);
|
||||
case BH_IO_INIT_CB: return BH_FileInit(file, (const char *)arg1);
|
||||
case BH_IO_DESTROY_CB: return BH_FileDestroy(file);
|
||||
case BH_IO_OPEN_CB: return BH_FileOpen(file, (int *)arg1);
|
||||
case BH_IO_CLOSE_CB: return BH_FileClose(file);
|
||||
case BH_IO_READ_CB: return BH_FileRead(file, (char *)arg1, (size_t *)arg2);
|
||||
case BH_IO_WRITE_CB: return BH_FileWrite(file, (const char *)arg1, (size_t *)arg2);
|
||||
case BH_IO_PEEK_CB: return BH_FilePeek(file, (char *)arg1, (size_t *)arg2);
|
||||
case BH_IO_FLUSH_CB: return BH_FileFlush(file);
|
||||
case BH_IO_SEEK_CB: return BH_FileSeek(file, (int64_t *)arg1, (int *)arg2);
|
||||
case BH_IO_TELL_CB: return BH_FileTell(file, (int64_t *)arg1);
|
||||
case BH_IO_SIZE_CB: return BH_FileSize(file, (int64_t *)arg1);
|
||||
case BH_IO_FLAGS_CB: return BH_FileFlags(file);
|
||||
case BH_IO_CLEAR_CB: return BH_FileClear(file);
|
||||
default: return BH_NOIMPL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BH_IO *BH_FileNew(const char *path)
|
||||
{
|
||||
return BH_IONew((BH_IOCallback)BH_FileCallback, (void *)path);
|
||||
}
|
||||
406
src/Platform/Posix/File.c
Normal file
406
src/Platform/Posix/File.c
Normal file
@@ -0,0 +1,406 @@
|
||||
#include <BH/IO.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
typedef struct BH_File
|
||||
{
|
||||
char *path;
|
||||
int mode;
|
||||
int flags;
|
||||
int handle;
|
||||
} BH_File;
|
||||
|
||||
|
||||
static int BH_FileInfo(BH_File *file,
|
||||
size_t *size,
|
||||
const char **name);
|
||||
|
||||
|
||||
static int BH_FileInit(BH_File *file,
|
||||
const char *path);
|
||||
|
||||
|
||||
static int BH_FileDestroy(BH_File *file);
|
||||
|
||||
|
||||
static int BH_FileOpen(BH_File *file,
|
||||
int *mode);
|
||||
|
||||
|
||||
static int BH_FileClose(BH_File *file);
|
||||
|
||||
|
||||
static int BH_FileRead(BH_File *file,
|
||||
char *data,
|
||||
size_t *size);
|
||||
|
||||
|
||||
static int BH_FileWrite(BH_File *file,
|
||||
const char *data,
|
||||
size_t *size);
|
||||
|
||||
|
||||
static int BH_FilePeek(BH_File* file,
|
||||
char *data,
|
||||
size_t *size);
|
||||
|
||||
|
||||
static int BH_FileFlush(BH_File *file);
|
||||
|
||||
|
||||
static int BH_FileSeek(BH_File *file,
|
||||
int64_t *pos,
|
||||
int *dir);
|
||||
|
||||
|
||||
static int BH_FileTell(BH_File *file,
|
||||
int64_t *pos);
|
||||
|
||||
|
||||
static int BH_FileSize(BH_File *file,
|
||||
int64_t *size);
|
||||
|
||||
|
||||
static int BH_FileFlags(BH_File *file);
|
||||
|
||||
|
||||
static int BH_FileClear(BH_File *file);
|
||||
|
||||
|
||||
static int BH_FileInfo(BH_File *file,
|
||||
size_t *size,
|
||||
const char **name)
|
||||
{
|
||||
static const char classname[] = BH_FILE_CLASSNAME;
|
||||
|
||||
if (size)
|
||||
*size = sizeof(*file);
|
||||
if (name)
|
||||
*name = classname;
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
|
||||
static int BH_FileInit(BH_File *file,
|
||||
const char *path)
|
||||
{
|
||||
/* Check if path is valid */
|
||||
if (!path)
|
||||
return BH_ERROR;
|
||||
|
||||
/* Duplicate path string and initialize the file struct */
|
||||
file->path = strdup(path);
|
||||
file->mode = 0;
|
||||
file->handle = -1;
|
||||
file->flags = 0;
|
||||
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
|
||||
static int BH_FileDestroy(BH_File *file)
|
||||
{
|
||||
/* Close the file handle on destruction */
|
||||
if (file->handle != -1)
|
||||
BH_FileClose(file);
|
||||
|
||||
/* Free path string */
|
||||
free(file->path);
|
||||
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
|
||||
static int BH_FileOpenFlags(int mode)
|
||||
{
|
||||
int flags = 0;
|
||||
|
||||
/* Determine read/write flags */
|
||||
if ((mode & BH_IO_READWRITE) == BH_IO_READWRITE)
|
||||
flags |= O_RDWR;
|
||||
else if (mode & BH_IO_WRITE)
|
||||
flags |= O_WRONLY;
|
||||
else if (mode & BH_IO_READ)
|
||||
flags |= O_RDONLY;
|
||||
else
|
||||
return -1;
|
||||
|
||||
/* Check if existing file should be opened */
|
||||
if (!(mode & BH_IO_EXIST))
|
||||
{
|
||||
flags |= O_CREAT;
|
||||
|
||||
/* Check if file should be created */
|
||||
if (mode & BH_IO_CREATE)
|
||||
flags |= O_EXCL;
|
||||
}
|
||||
|
||||
/* Check if file should be opened in append mode */
|
||||
if (mode & BH_IO_APPEND)
|
||||
flags |= O_APPEND;
|
||||
|
||||
/* Check if file should be truncated */
|
||||
if (mode & BH_IO_TRUNCATE)
|
||||
flags |= O_TRUNC;
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
|
||||
static int BH_FileOpen(BH_File *file,
|
||||
int *mode)
|
||||
{
|
||||
static const mode_t open_mode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
|
||||
int flags;
|
||||
|
||||
/* If file is already opened - report error */
|
||||
if (file->handle != -1)
|
||||
return BH_ERROR;
|
||||
|
||||
/* Determine file open flags */
|
||||
flags = BH_FileOpenFlags(*mode);
|
||||
if (flags == -1)
|
||||
return BH_ERROR;
|
||||
|
||||
/* Open the file */
|
||||
file->handle = open(file->path, flags, open_mode);
|
||||
if (file->handle == -1)
|
||||
return BH_ERROR;
|
||||
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
|
||||
static int BH_FileClose(BH_File *file)
|
||||
{
|
||||
/* If file is closed - report error */
|
||||
if (file->handle == -1)
|
||||
return BH_ERROR;
|
||||
|
||||
/* Close and reset the file handle */
|
||||
close(file->handle);
|
||||
file->handle = -1;
|
||||
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
|
||||
static int BH_FileRead(BH_File *file,
|
||||
char *data,
|
||||
size_t *size)
|
||||
{
|
||||
ssize_t readed;
|
||||
|
||||
/* Check if file is open */
|
||||
if (file->handle == -1)
|
||||
goto error;
|
||||
|
||||
/* Read data from the file */
|
||||
readed = read(file->handle, data, *size);
|
||||
if (readed < 0)
|
||||
goto error;
|
||||
|
||||
/* Check for EOF condition */
|
||||
if (readed > 0)
|
||||
file->flags &= ~BH_IO_FLAG_EOF;
|
||||
else
|
||||
file->flags |= BH_IO_FLAG_EOF;
|
||||
|
||||
*size = readed;
|
||||
return BH_OK;
|
||||
|
||||
error:
|
||||
file->flags |= BH_IO_FLAG_ERROR;
|
||||
return BH_ERROR;
|
||||
}
|
||||
|
||||
|
||||
static int BH_FileWrite(BH_File *file,
|
||||
const char *data,
|
||||
size_t *size)
|
||||
{
|
||||
ssize_t written;
|
||||
|
||||
/* Check if file is open */
|
||||
if (file->handle == -1)
|
||||
goto error;
|
||||
|
||||
/* Write data to the file */
|
||||
written = write(file->handle, data, *size);
|
||||
if (written < 0)
|
||||
goto error;
|
||||
|
||||
/* Check for EOF condition */
|
||||
if (!written)
|
||||
file->flags |= BH_IO_FLAG_EOF;
|
||||
else
|
||||
file->flags &= ~BH_IO_FLAG_EOF;
|
||||
|
||||
*size = written;
|
||||
return BH_OK;
|
||||
|
||||
error:
|
||||
file->flags |= BH_IO_FLAG_ERROR;
|
||||
return BH_ERROR;
|
||||
}
|
||||
|
||||
|
||||
static int BH_FilePeek(BH_File *file,
|
||||
char *data,
|
||||
size_t *size)
|
||||
{
|
||||
int64_t position;
|
||||
int direction;
|
||||
|
||||
/* Check if file is open */
|
||||
if (file->handle == -1)
|
||||
goto error;
|
||||
|
||||
/* Read data from the file */
|
||||
if (BH_FileRead(file, data, size))
|
||||
goto error;
|
||||
|
||||
/* Backtrack by the read amount */
|
||||
position = -((int64_t)*size);
|
||||
direction = BH_IO_SEEK_CUR;
|
||||
if (BH_FileSeek(file, &position, &direction))
|
||||
goto error;
|
||||
|
||||
return BH_OK;
|
||||
|
||||
error:
|
||||
file->flags |= BH_IO_FLAG_ERROR;
|
||||
return BH_ERROR;
|
||||
}
|
||||
|
||||
|
||||
static int BH_FileFlush(BH_File *file)
|
||||
{
|
||||
/* Check if file is open */
|
||||
if (file->handle == -1)
|
||||
{
|
||||
file->flags |= BH_IO_FLAG_ERROR;
|
||||
return BH_ERROR;
|
||||
}
|
||||
|
||||
/* Flush the buffers */
|
||||
fsync(file->handle);
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
|
||||
static int BH_FileSeek(BH_File *file,
|
||||
int64_t *pos,
|
||||
int *dir)
|
||||
{
|
||||
/* Check if file is open */
|
||||
if (file->handle == -1)
|
||||
goto error;
|
||||
|
||||
/* Seek to the specified position */
|
||||
if (lseek(file->handle, *pos, *dir) == -1)
|
||||
goto error;
|
||||
|
||||
return BH_OK;
|
||||
|
||||
error:
|
||||
file->flags |= BH_IO_FLAG_ERROR;
|
||||
return BH_ERROR;
|
||||
}
|
||||
|
||||
|
||||
static int BH_FileTell(BH_File *file,
|
||||
int64_t *pos)
|
||||
{
|
||||
/* Check if file is open */
|
||||
if (file->handle == -1)
|
||||
goto error;
|
||||
|
||||
/* Get current offset in the file */
|
||||
if ((*pos = lseek(file->handle, 0, SEEK_CUR)) == -1)
|
||||
goto error;
|
||||
|
||||
return BH_OK;
|
||||
|
||||
error:
|
||||
file->flags |= BH_IO_FLAG_ERROR;
|
||||
return BH_ERROR;
|
||||
}
|
||||
|
||||
|
||||
static int BH_FileSize(BH_File *file,
|
||||
int64_t *size)
|
||||
{
|
||||
struct stat sb;
|
||||
|
||||
/* Check if file is open */
|
||||
if (file->handle == -1)
|
||||
goto error;
|
||||
|
||||
/* Get file size from the OS */
|
||||
if (fstat(file->handle, &sb))
|
||||
goto error;
|
||||
|
||||
*size = sb.st_size;
|
||||
return BH_OK;
|
||||
|
||||
error:
|
||||
file->flags |= BH_IO_FLAG_ERROR;
|
||||
return BH_ERROR;
|
||||
}
|
||||
|
||||
|
||||
static int BH_FileFlags(BH_File *file)
|
||||
{
|
||||
/* If file handle is valid - append IO_OPEN flag */
|
||||
if (file->handle != -1)
|
||||
return file->flags | BH_IO_FLAG_OPEN;
|
||||
|
||||
return file->flags;
|
||||
}
|
||||
|
||||
|
||||
static int BH_FileClear(BH_File *file)
|
||||
{
|
||||
/* Clear IO_ERROR flag */
|
||||
file->flags &= ~BH_IO_FLAG_ERROR;
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
|
||||
static int BH_FileCallback(BH_File *file,
|
||||
int type,
|
||||
void *arg1,
|
||||
void *arg2)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case BH_IO_INFO_CB: return BH_FileInfo(file, (size_t *)arg1, (const char **)arg2);
|
||||
case BH_IO_INIT_CB: return BH_FileInit(file, (const char *)arg1);
|
||||
case BH_IO_DESTROY_CB: return BH_FileDestroy(file);
|
||||
case BH_IO_OPEN_CB: return BH_FileOpen(file, (int *)arg1);
|
||||
case BH_IO_CLOSE_CB: return BH_FileClose(file);
|
||||
case BH_IO_READ_CB: return BH_FileRead(file, (char *)arg1, (size_t *)arg2);
|
||||
case BH_IO_WRITE_CB: return BH_FileWrite(file, (const char *)arg1, (size_t *)arg2);
|
||||
case BH_IO_PEEK_CB: return BH_FilePeek(file, (char *)arg1, (size_t *)arg2);
|
||||
case BH_IO_FLUSH_CB: return BH_FileFlush(file);
|
||||
case BH_IO_SEEK_CB: return BH_FileSeek(file, (int64_t *)arg1, (int *)arg2);
|
||||
case BH_IO_TELL_CB: return BH_FileTell(file, (int64_t *)arg1);
|
||||
case BH_IO_SIZE_CB: return BH_FileSize(file, (int64_t *)arg1);
|
||||
case BH_IO_FLAGS_CB: return BH_FileFlags(file);
|
||||
case BH_IO_CLEAR_CB: return BH_FileClear(file);
|
||||
default: return BH_NOIMPL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BH_IO *BH_FileNew(const char *path)
|
||||
{
|
||||
return BH_IONew((BH_IOCallback)BH_FileCallback, (void *)path);
|
||||
}
|
||||
405
src/Platform/Win32/File.c
Normal file
405
src/Platform/Win32/File.c
Normal file
@@ -0,0 +1,405 @@
|
||||
#include <BH/IO.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <windows.h>
|
||||
|
||||
|
||||
typedef struct BH_File
|
||||
{
|
||||
char *path;
|
||||
int mode;
|
||||
int flags;
|
||||
HANDLE handle;
|
||||
} BH_File;
|
||||
|
||||
|
||||
static int BH_FileInfo(BH_File *file,
|
||||
size_t *size,
|
||||
const char **name);
|
||||
|
||||
|
||||
static int BH_FileInit(BH_File *file,
|
||||
const char *path);
|
||||
|
||||
|
||||
static int BH_FileDestroy(BH_File *file);
|
||||
|
||||
|
||||
static int BH_FileOpen(BH_File *file,
|
||||
int *mode);
|
||||
|
||||
|
||||
static int BH_FileClose(BH_File *file);
|
||||
|
||||
|
||||
static int BH_FileRead(BH_File *file,
|
||||
char *data,
|
||||
size_t *size);
|
||||
|
||||
|
||||
static int BH_FileWrite(BH_File *file,
|
||||
const char *data,
|
||||
size_t *size);
|
||||
|
||||
|
||||
static int BH_FilePeek(BH_File* file,
|
||||
char *data,
|
||||
size_t *size);
|
||||
|
||||
|
||||
static int BH_FileFlush(BH_File *file);
|
||||
|
||||
|
||||
static int BH_FileSeek(BH_File *file,
|
||||
int64_t *pos,
|
||||
int *dir);
|
||||
|
||||
|
||||
static int BH_FileTell(BH_File *file,
|
||||
int64_t *pos);
|
||||
|
||||
|
||||
static int BH_FileSize(BH_File *file,
|
||||
int64_t *size);
|
||||
|
||||
|
||||
static int BH_FileFlags(BH_File *file);
|
||||
|
||||
|
||||
static int BH_FileClear(BH_File *file);
|
||||
|
||||
|
||||
static int BH_FileInfo(BH_File *file,
|
||||
size_t *size,
|
||||
const char **name)
|
||||
{
|
||||
static const char classname[] = BH_FILE_CLASSNAME;
|
||||
|
||||
if (size)
|
||||
*size = sizeof(*file);
|
||||
if (name)
|
||||
*name = classname;
|
||||
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
|
||||
static int BH_FileInit(BH_File *file,
|
||||
const char *path)
|
||||
{
|
||||
/* Check if path is valid */
|
||||
if (!path)
|
||||
return BH_ERROR;
|
||||
|
||||
/* Duplicate path string and initialize the file struct */
|
||||
file->path = strdup(path);
|
||||
file->mode = 0;
|
||||
file->handle = INVALID_HANDLE_VALUE;
|
||||
file->flags = 0;
|
||||
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
|
||||
static int BH_FileDestroy(BH_File *file)
|
||||
{
|
||||
/* Close the file handle on destruction */
|
||||
if (file->handle != INVALID_HANDLE_VALUE)
|
||||
BH_FileClose(file);
|
||||
|
||||
/* Free path string */
|
||||
free(file->path);
|
||||
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
|
||||
static int BH_FileOpen(BH_File *file,
|
||||
int *mode)
|
||||
{
|
||||
DWORD access = 0, how = 0;
|
||||
|
||||
/* Check if file is already openned */
|
||||
if (file->handle != INVALID_HANDLE_VALUE)
|
||||
return BH_ERROR;
|
||||
|
||||
/* Determine read/write access flags */
|
||||
if (*mode & BH_IO_READ)
|
||||
access |= GENERIC_READ;
|
||||
if (*mode & BH_IO_WRITE)
|
||||
access |= GENERIC_WRITE;
|
||||
|
||||
if (!access)
|
||||
return BH_ERROR;
|
||||
|
||||
/* Determine open mode flags */
|
||||
if (*mode & BH_IO_TRUNCATE)
|
||||
{
|
||||
switch (*mode & (BH_IO_CREATE | BH_IO_EXIST))
|
||||
{
|
||||
case 0: how = CREATE_ALWAYS; break;
|
||||
case BH_IO_CREATE: how = CREATE_NEW; break;
|
||||
case BH_IO_EXIST: how = TRUNCATE_EXISTING; break;
|
||||
default: return BH_ERROR;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (*mode & (BH_IO_CREATE | BH_IO_EXIST))
|
||||
{
|
||||
case 0: how = OPEN_ALWAYS; break;
|
||||
case BH_IO_CREATE: how = CREATE_NEW; break;
|
||||
case BH_IO_EXIST: how = OPEN_EXISTING; break;
|
||||
default: return BH_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/* Save mode that we are in and open file */
|
||||
file->mode = *mode;
|
||||
file->handle = CreateFileA(file->path, access, FILE_SHARE_READ, NULL, how, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
|
||||
if (file->handle == INVALID_HANDLE_VALUE)
|
||||
return BH_ERROR;
|
||||
|
||||
/* Truncate file if needed */
|
||||
if (*mode & BH_IO_TRUNCATE)
|
||||
SetEndOfFile(file->handle);
|
||||
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
|
||||
static int BH_FileClose(BH_File *file)
|
||||
{
|
||||
/* If file is opened - close it */
|
||||
if (file->handle == INVALID_HANDLE_VALUE)
|
||||
return BH_ERROR;
|
||||
|
||||
/* Reset handle and mode values */
|
||||
CloseHandle(file->handle);
|
||||
file->handle = INVALID_HANDLE_VALUE;
|
||||
file->mode = 0;
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
|
||||
static int BH_FileRead(BH_File *file,
|
||||
char *data,
|
||||
size_t *size)
|
||||
{
|
||||
DWORD readed;
|
||||
|
||||
/* Check if file is opened */
|
||||
if (file->handle == INVALID_HANDLE_VALUE)
|
||||
goto error;
|
||||
|
||||
/* Read data from the file */
|
||||
if (!ReadFile(file->handle, data, (DWORD)*size, &readed, NULL))
|
||||
goto error;
|
||||
|
||||
/* Check if we reached end of file */
|
||||
if (!readed)
|
||||
file->flags |= BH_IO_FLAG_EOF;
|
||||
else
|
||||
file->flags &= ~BH_IO_FLAG_EOF;
|
||||
|
||||
*size = readed;
|
||||
return BH_OK;
|
||||
|
||||
error:
|
||||
file->flags |= BH_IO_FLAG_ERROR;
|
||||
return BH_ERROR;
|
||||
}
|
||||
|
||||
|
||||
static int BH_FileWrite(BH_File *file,
|
||||
const char *data,
|
||||
size_t *size)
|
||||
{
|
||||
DWORD written;
|
||||
|
||||
/* Check if file is opened */
|
||||
if (file->handle == INVALID_HANDLE_VALUE)
|
||||
goto error;
|
||||
|
||||
/* Adjust current position in the file to the end */
|
||||
if (file->mode & BH_IO_APPEND)
|
||||
{
|
||||
LARGE_INTEGER position;
|
||||
|
||||
position.QuadPart = 0;
|
||||
if (!SetFilePointerEx(file->handle, position, NULL, FILE_END))
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Write data to the file */
|
||||
if (!WriteFile(file->handle, data, (DWORD)*size, &written, NULL))
|
||||
goto error;
|
||||
|
||||
/* Check for end of file */
|
||||
if (!written)
|
||||
file->flags |= BH_IO_FLAG_EOF;
|
||||
else
|
||||
file->flags &= ~BH_IO_FLAG_EOF;
|
||||
|
||||
*size = written;
|
||||
return BH_OK;
|
||||
|
||||
error:
|
||||
file->flags |= BH_IO_FLAG_ERROR;
|
||||
return BH_ERROR;
|
||||
}
|
||||
|
||||
|
||||
static int BH_FilePeek(BH_File *file,
|
||||
char *data,
|
||||
size_t *size)
|
||||
{
|
||||
int64_t position;
|
||||
int direction;
|
||||
|
||||
/* Read data from the file */
|
||||
if (BH_FileRead(file, data, size))
|
||||
return BH_ERROR;
|
||||
|
||||
/* Backtrack by the read amount */
|
||||
position = -((int64_t)*size);
|
||||
direction = BH_IO_SEEK_CUR;
|
||||
if (BH_FileSeek(file, &position, &direction))
|
||||
return BH_ERROR;
|
||||
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
|
||||
static int BH_FileFlush(BH_File *file)
|
||||
{
|
||||
/* Check if file is opened */
|
||||
if (file->handle == INVALID_HANDLE_VALUE)
|
||||
goto error;
|
||||
|
||||
/* Flush OS buffers */
|
||||
FlushFileBuffers(file->handle);
|
||||
return BH_OK;
|
||||
|
||||
error:
|
||||
file->flags |= BH_IO_FLAG_ERROR;
|
||||
return BH_ERROR;
|
||||
}
|
||||
|
||||
|
||||
static int BH_FileSeek(BH_File *file,
|
||||
int64_t *pos,
|
||||
int *dir)
|
||||
{
|
||||
LARGE_INTEGER position;
|
||||
|
||||
/* Check if file is opened */
|
||||
if (file->handle == INVALID_HANDLE_VALUE)
|
||||
goto error;
|
||||
|
||||
/* Set read/write position in the file */
|
||||
position.QuadPart = *pos;
|
||||
if (!SetFilePointerEx(file->handle, position, NULL, *dir))
|
||||
goto error;
|
||||
|
||||
return BH_OK;
|
||||
|
||||
error:
|
||||
file->flags |= BH_IO_FLAG_ERROR;
|
||||
return BH_ERROR;
|
||||
}
|
||||
|
||||
|
||||
static int BH_FileTell(BH_File *file,
|
||||
int64_t *pos)
|
||||
{
|
||||
LARGE_INTEGER dummy, position;
|
||||
|
||||
/* Check if file is opened */
|
||||
if (file->handle == INVALID_HANDLE_VALUE)
|
||||
goto error;
|
||||
|
||||
/* Readback current position in the file */
|
||||
dummy.QuadPart = 0;
|
||||
if (!SetFilePointerEx(file->handle, dummy, &position, BH_IO_SEEK_CUR))
|
||||
goto error;
|
||||
|
||||
*pos = position.QuadPart;
|
||||
return BH_OK;
|
||||
|
||||
error:
|
||||
file->flags |= BH_IO_FLAG_ERROR;
|
||||
return BH_ERROR;
|
||||
}
|
||||
|
||||
|
||||
static int BH_FileSize(BH_File *file,
|
||||
int64_t *size)
|
||||
{
|
||||
LARGE_INTEGER dummy;
|
||||
|
||||
/* Check if file is opened */
|
||||
if (file->handle == INVALID_HANDLE_VALUE)
|
||||
goto error;
|
||||
|
||||
/* Get current file size */
|
||||
if (!GetFileSizeEx(file->handle, &dummy))
|
||||
goto error;
|
||||
|
||||
*size = dummy.QuadPart;
|
||||
return BH_OK;
|
||||
|
||||
error:
|
||||
file->flags |= BH_IO_FLAG_ERROR;
|
||||
return BH_ERROR;
|
||||
}
|
||||
|
||||
|
||||
static int BH_FileFlags(BH_File *file)
|
||||
{
|
||||
/* If file handle is valid - append IO_OPEN flag */
|
||||
if (file->handle != INVALID_HANDLE_VALUE)
|
||||
return file->flags | BH_IO_FLAG_OPEN;
|
||||
return file->flags;
|
||||
}
|
||||
|
||||
|
||||
static int BH_FileClear(BH_File *file)
|
||||
{
|
||||
/* Clear IO_ERROR flag */
|
||||
file->flags &= ~BH_IO_FLAG_ERROR;
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
|
||||
static int BH_FileCallback(BH_File *file,
|
||||
int type,
|
||||
void *arg1,
|
||||
void *arg2)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case BH_IO_INFO_CB: return BH_FileInfo(file, (size_t *)arg1, (const char **)arg2);
|
||||
case BH_IO_INIT_CB: return BH_FileInit(file, (const char *)arg1);
|
||||
case BH_IO_DESTROY_CB: return BH_FileDestroy(file);
|
||||
case BH_IO_OPEN_CB: return BH_FileOpen(file, (int *)arg1);
|
||||
case BH_IO_CLOSE_CB: return BH_FileClose(file);
|
||||
case BH_IO_READ_CB: return BH_FileRead(file, (char *)arg1, (size_t *)arg2);
|
||||
case BH_IO_WRITE_CB: return BH_FileWrite(file, (const char *)arg1, (size_t *)arg2);
|
||||
case BH_IO_PEEK_CB: return BH_FilePeek(file, (char *)arg1, (size_t *)arg2);
|
||||
case BH_IO_FLUSH_CB: return BH_FileFlush(file);
|
||||
case BH_IO_SEEK_CB: return BH_FileSeek(file, (int64_t *)arg1, (int *)arg2);
|
||||
case BH_IO_TELL_CB: return BH_FileTell(file, (int64_t *)arg1);
|
||||
case BH_IO_SIZE_CB: return BH_FileSize(file, (int64_t *)arg1);
|
||||
case BH_IO_FLAGS_CB: return BH_FileFlags(file);
|
||||
case BH_IO_CLEAR_CB: return BH_FileClear(file);
|
||||
default: return BH_NOIMPL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BH_IO *BH_FileNew(const char *path)
|
||||
{
|
||||
return BH_IONew((BH_IOCallback)BH_FileCallback, (void *)path);
|
||||
}
|
||||
Reference in New Issue
Block a user