#include 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; /* Allocate and initialize file object */ result = malloc(sizeof(*result)); if (result && bh_file_init(result, path)) { /* Something went wrong - free the file object */ free(result); result = NULL; } return result; } void bh_file_free(bh_file_t *file) { /* Destroy file object and free allocated memory */ bh_file_destroy(file); free(file); } int bh_file_init(bh_file_t *file, const char *path) { /* Check if path is not empty */ if (!path) return BH_INVALID; /* Fill file structure information */ file->handle = INVALID_HANDLE_VALUE; file->mode = BH_IO_NONE; file->path = strdup(path); file->base.table = &bh_file_table; return BH_OK; } void bh_file_destroy(bh_file_t *file) { /* Close the file and free allocated memory */ bh_file_close(file); free(file->path); } int bh_file_open_base(bh_file_t *file, int mode) { DWORD access = 0, how = 0; /* Check if file is already openned */ if (file->handle != INVALID_HANDLE_VALUE) return BH_OK; /* Determine read/write access flags */ if (mode & BH_IO_READ) access |= GENERIC_READ; if (mode & BH_IO_WRITE) access |= GENERIC_WRITE; /* Determine open mode flags */ switch (mode & (BH_IO_CREATE | BH_IO_OPEN)) { case 0: how = OPEN_ALWAYS; break; case BH_IO_CREATE: how = CREATE_NEW; break; case BH_IO_OPEN: how = OPEN_EXISTING; break; } /* 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) { /* Error handling */ switch (GetLastError()) { case ERROR_FILE_EXISTS: return BH_FOUND; case ERROR_FILE_NOT_FOUND: return BH_NOT_FOUND; default: return BH_ERROR; } } /* Truncate file if needed */ if (mode & BH_IO_TRUNCATE) SetEndOfFile(file->handle); return BH_OK; } void bh_file_close_base(bh_file_t *file) { /* If file is opened - close it */ if (file->handle != INVALID_HANDLE_VALUE) CloseHandle(file->handle); /* Reset handle and mode values */ file->handle = INVALID_HANDLE_VALUE; file->mode = BH_IO_NONE; } int bh_file_is_open_base(bh_file_t *file) { /* If handle is not INVALID_HANDLE_VALUE - file is open */ return file->handle != INVALID_HANDLE_VALUE; } size_t bh_file_read_base(bh_file_t *file, char *data, size_t size) { DWORD readed; /* Check if file is opened */ if (file->handle == INVALID_HANDLE_VALUE) { file->base.flags |= BH_IO_ERROR; return 0; } /* Read data from the file */ if (!ReadFile(file->handle, data, (DWORD)size, &readed, NULL)) { file->base.flags |= BH_IO_ERROR; return 0; } /* Check if we reached end of file */ if (!readed) file->base.flags |= BH_IO_EOF; else file->base.flags &= ~BH_IO_EOF; /* Return readed bytes */ return readed; } size_t bh_file_write_base(bh_file_t *file, const char *data, size_t size) { DWORD written; /* Check if file is opened */ if (file->handle == INVALID_HANDLE_VALUE) { file->base.flags |= BH_IO_ERROR; return 0; } /* Adjust current position in the file to the end */ if (file->mode & BH_IO_APPEND) bh_file_seek(file, 0, BH_IO_END); /* Write data to the file */ if (!WriteFile(file->handle, data, (DWORD)size, &written, NULL)) { file->base.flags |= BH_IO_ERROR; return 0; } /* Check for end of file */ if (!written) file->base.flags |= BH_IO_EOF; else file->base.flags &= ~BH_IO_EOF; /* Write amount of bytes written */ return written; } void bh_file_flush_base(bh_file_t *file) { /* Check if file is opened */ if (file->handle == INVALID_HANDLE_VALUE) { file->base.flags |= BH_IO_ERROR; return; } /* Flush OS buffers */ FlushFileBuffers(file->handle); } int bh_file_seek_base(bh_file_t *file, bh_off_t pos, int dir) { LARGE_INTEGER position; /* Check if file is opened */ if (file->handle == INVALID_HANDLE_VALUE) { file->base.flags |= BH_IO_ERROR; return BH_ERROR; } /* Set read/write position in the file */ 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) { LARGE_INTEGER size; /* Check if file is opened */ if (file->handle == INVALID_HANDLE_VALUE) { file->base.flags |= BH_IO_ERROR; return -1; } /* Get current file size */ if (GetFileSizeEx(file->handle, &size)) return size.QuadPart; return -1; } bh_off_t bh_file_tell_base(bh_file_t *file) { LARGE_INTEGER dummy, position; /* Check if file is opened */ if (file->handle == INVALID_HANDLE_VALUE) { file->base.flags |= BH_IO_ERROR; return -1; } /* Readback current position in the file */ 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) { /* Get available bytes for reading */ return bh_file_size_base(file) - bh_file_tell_base(file); } void bh_file_clear_base(bh_file_t *file) { file->base.flags &= ~BH_IO_ERROR; }