diff options
| -rw-r--r-- | CMakeLists.txt | 2 | ||||
| -rw-r--r-- | doc/Examples/PakReader.c | 8 | ||||
| -rw-r--r-- | doc/Examples/Utf8Test.c | 16 | ||||
| -rw-r--r-- | doc/HowTo/PakReader.md | 27 | ||||
| -rw-r--r-- | doc/HowTo/Utf8Test.md | 45 | ||||
| -rw-r--r-- | include/BH/Common.h | 3 | ||||
| -rw-r--r-- | include/BH/IO.h | 284 | ||||
| -rw-r--r-- | src/Buffer.c | 304 | ||||
| -rw-r--r-- | src/Bytes.c | 217 | ||||
| -rw-r--r-- | src/IO.c | 249 | ||||
| -rw-r--r-- | src/Platform/Dummy/File.c | 201 | ||||
| -rw-r--r-- | src/Platform/Posix/File.c | 354 | ||||
| -rw-r--r-- | src/Platform/Win32/File.c | 370 | ||||
| -rw-r--r-- | test/src/TestBuffer.c | 126 | ||||
| -rw-r--r-- | test/src/TestBytes.c | 153 | ||||
| -rw-r--r-- | test/src/TestFile.c | 184 |
16 files changed, 1447 insertions, 1096 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 7e1acdc..78a679e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -80,6 +80,8 @@ endif() set(BH_SOURCE src/Algo.c src/Args.c + src/Buffer.c + src/Bytes.c src/Hashmap.c src/IO.c src/Math/Box2f.c diff --git a/doc/Examples/PakReader.c b/doc/Examples/PakReader.c index e350b67..4a8cca1 100644 --- a/doc/Examples/PakReader.c +++ b/doc/Examples/PakReader.c @@ -165,9 +165,8 @@ static int ProcessPack(Config *config, if (strcmp(entry.name, config->input)) continue; - output = BH_FileNew(config->output); - if (BH_IOOpen(output, BH_IO_WRITE) || - BH_IOSeek(io, entry.offset, BH_IO_SEEK_SET) || + output = BH_FileNew(config->output, BH_FILE_WRITE | BH_FILE_TRUNCATE, NULL); + if (!output || BH_IOSeek(io, entry.offset, BH_IO_SEEK_SET) || CopyData(io, output, entry.size)) { BH_IOFree(output); @@ -209,8 +208,7 @@ int main(int argc, char **argv) } /* Read and write */ - io = BH_FileNew(config.file); - if (BH_IOOpen(io, BH_IO_READ | BH_IO_EXIST)) + if ((io = BH_FileNew(config.file, BH_FILE_READ | BH_FILE_EXIST, NULL)) == NULL) { printf("Can't open file %s\n", config.file); BH_IOFree(io); diff --git a/doc/Examples/Utf8Test.c b/doc/Examples/Utf8Test.c index e6d9e56..b7e4ac3 100644 --- a/doc/Examples/Utf8Test.c +++ b/doc/Examples/Utf8Test.c @@ -21,23 +21,25 @@ int main(int argc, char **argv) if (argc < 2) printUsage(); - inFile = BH_FileNew(argv[1]); - outFile = BH_FileNew(argv[2]); + inFile = BH_FileNew(argv[1], BH_FILE_READ | BH_FILE_EXIST, NULL); + outFile = BH_FileNew(argv[2], BH_FILE_WRITE | BH_FILE_TRUNCATE, NULL); - if (!inFile || BH_IOOpen(inFile, BH_IO_READ | BH_IO_EXIST)) - return -1; - - if (!outFile || BH_IOOpen(outFile, BH_IO_WRITE | BH_IO_TRUNCATE)) + if (!inFile || !outFile) return -1; inSize = 0; - while (!(BH_IOFlags(inFile) & BH_IO_FLAG_EOF)) + while (1) { /* Read one byte and try to decode */ if (!inSize || !(outSize = BH_UnicodeDecodeUtf8(inBuffer, inSize, &unit))) { + BH_IOPeek(inFile, inBuffer + inSize, 1, &outSize); BH_IORead(inFile, inBuffer + inSize, 1, &outSize); inSize += outSize; + + if (!outSize) + break; + continue; } diff --git a/doc/HowTo/PakReader.md b/doc/HowTo/PakReader.md index 4f75399..fb99796 100644 --- a/doc/HowTo/PakReader.md +++ b/doc/HowTo/PakReader.md @@ -61,22 +61,20 @@ To implement this utility, we are going to need to include the following headers ## Working with Files Working with files in BHLib is based around the IO device (called `BH_IO`). -Firstly, you need to create an IO device with the `BH_FileNew` function. -Secondly, you need to open the IO device with the `BH_IOOpen` function. While -opening the IO device, you can specify in which mode it will work: reading -(`BH_IO_READ`) or writing (`BH_IO_WRITE`). Additionally, we can specify whether -the IO device (or in our case, the file) should exist before opening -(`BH_IO_EXIST`), be truncated before opening (`BH_IO_TRUNCATE`), should it be -created (`BH_IO_CREATE`), or opened in append mode (`BH_IO_APPEND`). +Firstly, you need to create an IO file device with the `BH_FileNew` function. +While doing so, you can specify in which mode it will work: reading +(`BH_FILE_READ`) or writing (`BH_FILE_WRITE`). Additionally, we can specify +whether the file should exist before opening (`BH_IO_EXIST`), be truncated +before opening (`BH_IO_TRUNCATE`), should it be created (`BH_IO_CREATE`), or +opened in append mode (`BH_IO_APPEND`). Here is an example for opening an existing file in read-only mode: ```c -BH_IO *io = BH_FileNew("coolfile.dat"); -if (BH_IOOpen(io, BH_IO_READ | BH_IO_EXIST)) +BH_IO *io = BH_FileNew("coolfile.dat", BH_FILE_READ | BH_FILE_EXISTS, NULL); +if (!io) { printf("Can't open file 'coolfile.dat'\n", config.file); - BH_IOFree(io); return -1; } ``` @@ -207,6 +205,7 @@ Now, let's put everything together and implement `PakReader`. #define HEADER_SIZE 12 #define ENTRY_SIZE 64 + typedef struct PakHeader { char id[4]; @@ -361,9 +360,8 @@ static int ProcessPack(Config *config, if (strcmp(entry.name, config->input)) continue; - output = BH_FileNew(config->output); - if (BH_IOOpen(output, BH_IO_WRITE) || - BH_IOSeek(io, entry.offset, BH_IO_SEEK_SET) || + output = BH_FileNew(config->output, BH_FILE_WRITE | BH_FILE_TRUNCATE, NULL); + if (!output || BH_IOSeek(io, entry.offset, BH_IO_SEEK_SET) || CopyData(io, output, entry.size)) { BH_IOFree(output); @@ -405,8 +403,7 @@ int main(int argc, char **argv) } /* Read and write */ - io = BH_FileNew(config.file); - if (BH_IOOpen(io, BH_IO_READ | BH_IO_EXIST)) + if ((io = BH_FileNew(config.file, BH_FILE_READ | BH_FILE_EXIST, NULL)) == NULL) { printf("Can't open file %s\n", config.file); BH_IOFree(io); diff --git a/doc/HowTo/Utf8Test.md b/doc/HowTo/Utf8Test.md index 7e82ef0..f68b66e 100644 --- a/doc/HowTo/Utf8Test.md +++ b/doc/HowTo/Utf8Test.md @@ -21,37 +21,40 @@ To implement this utility, we are going to need to include the following headers ## Working with Files Working with files in BHLib is based around the IO device (called `BH_IO`). -Firstly, you need to create an IO device with the `BH_FileNew` function. -Secondly, you need to open the IO device with the `BH_IOOpen` function. While -opening the IO device, you can specify in which mode it will work: reading -(`BH_IO_READ`) or writing (`BH_IO_WRITE`). Additionally, we can specify whether -the IO device (or in our case, the file) should exist before opening -(`BH_IO_EXIST`), be truncated before opening (`BH_IO_TRUNCATE`), should it be -created (`BH_IO_CREATE`), or opened in append mode (`BH_IO_APPEND`). +Firstly, you need to create an IO file device with the `BH_FileNew` function. +While doing so, you can specify in which mode it will work: reading +(`BH_FILE_READ`) or writing (`BH_FILE_WRITE`). Additionally, we can specify +whether the file should exist before opening (`BH_IO_EXIST`), be truncated +before opening (`BH_IO_TRUNCATE`), should it be created (`BH_IO_CREATE`), or +opened in append mode (`BH_IO_APPEND`). Here is an example for opening an existing file in read-only mode: ```c -BH_IO *io = BH_FileNew("coolfile.dat"); -if (BH_IOOpen(io, BH_IO_READ | BH_IO_EXIST)) +BH_IO *io = BH_FileNew("coolfile.dat", BH_FILE_READ | BH_FILE_EXISTS, NULL); +if (!io) { printf("Can't open file 'coolfile.dat'\n", config.file); - BH_IOFree(io); return -1; } ``` + ## Working with UTF-8 Reading UTF-8/UTF-16/UTF-32 is based around simple loop: 1. Read bytes from input (IO or memory) to some buffer. -2. Call `BH_UnicodeDecodeUtf*`. If return value is 0 - we don't have enough data, so go to step 1. Otherwise remove result bytes from the front of the buffer. -3. If readed codepoint equals -1 - we encountered an error, so replace it with the code 0xFFFD. +2. Call `BH_UnicodeDecodeUtf*`. If return value is 0 - we don't have enough + data, so go to step 1. Otherwise remove result bytes from the front of the + buffer. +3. If readed codepoint equals -1 - we encountered an error, so replace it with + the code 0xFFFD. Writing UTF-8/UTF-16/UTF-32 is straight forward: -1. Call `BH_UnicodeEncodeUtf*`. If return value is 0 - we can't encode codepoint (either codepoint is surrogate pair or outside valid range). +1. Call `BH_UnicodeEncodeUtf*`. If return value is 0 - we can't encode codepoint + (either codepoint is surrogate pair or outside valid range). 2. Write data (to IO or memory). BH_UnicodeDecodeUtf8(inBuffer, inSize, &unit) @@ -107,23 +110,25 @@ int main(int argc, char **argv) if (argc < 2) printUsage(); - inFile = BH_FileNew(argv[1]); - outFile = BH_FileNew(argv[2]); - - if (!inFile || BH_IOOpen(inFile, BH_IO_READ | BH_IO_EXIST)) - return -1; + inFile = BH_FileNew(argv[1], BH_FILE_READ | BH_FILE_EXIST, NULL); + outFile = BH_FileNew(argv[2], BH_FILE_WRITE | BH_FILE_TRUNCATE, NULL); - if (!outFile || BH_IOOpen(outFile, BH_IO_WRITE | BH_IO_TRUNCATE)) + if (!inFile || !outFile) return -1; inSize = 0; - while (!(BH_IOFlags(inFile) & BH_IO_FLAG_EOF)) + while (1) { /* Read one byte and try to decode */ if (!inSize || !(outSize = BH_UnicodeDecodeUtf8(inBuffer, inSize, &unit))) { + BH_IOPeek(inFile, inBuffer + inSize, 1, &outSize); BH_IORead(inFile, inBuffer + inSize, 1, &outSize); inSize += outSize; + + if (!outSize) + break; + continue; } diff --git a/include/BH/Common.h b/include/BH/Common.h index 78fd503..e0e0263 100644 --- a/include/BH/Common.h +++ b/include/BH/Common.h @@ -12,6 +12,9 @@ #define BH_FOUND 0x0005 #define BH_NOTFOUND 0x0006 #define BH_TIMEOUT 0x0007 +#define BH_SHORT 0x0008 +#define BH_FULL 0x0009 + #define BH_UNUSED(x) (void)(x) #define BH_PTR2INT(x) ((intptr_t)(x)) diff --git a/include/BH/IO.h b/include/BH/IO.h index ab7bec1..ada9dc0 100644 --- a/include/BH/IO.h +++ b/include/BH/IO.h @@ -5,248 +5,308 @@ #include "Common.h" -#define BH_IO_INFO_CB 0x0000 -#define BH_IO_INIT_CB 0x0001 -#define BH_IO_DESTROY_CB 0x0002 -#define BH_IO_OPEN_CB 0x0003 -#define BH_IO_CLOSE_CB 0x0004 -#define BH_IO_READ_CB 0x0005 -#define BH_IO_WRITE_CB 0x0006 -#define BH_IO_PEEK_CB 0x0007 -#define BH_IO_TELL_CB 0x0008 -#define BH_IO_SEEK_CB 0x0009 -#define BH_IO_FLUSH_CB 0x000A -#define BH_IO_SIZE_CB 0x000B -#define BH_IO_FLAGS_CB 0x000C -#define BH_IO_CLEAR_CB 0x000D +#define BH_IO_OP_DESTROY 0x0000 +#define BH_IO_OP_READ 0x0001 +#define BH_IO_OP_WRITE 0x0002 +#define BH_IO_OP_CTL 0x0003 +#define BH_IO_OP_CAP 0x0004 -#define BH_IO_READ 0x0001 -#define BH_IO_WRITE 0x0002 -#define BH_IO_READWRITE 0x0003 -#define BH_IO_APPEND 0x0010 -#define BH_IO_TRUNCATE 0x0020 -#define BH_IO_CREATE 0x0040 -#define BH_IO_EXIST 0x0080 +#define BH_IO_CTL_FLAGS 0x0000 +#define BH_IO_CTL_CLEAR 0x0001 +#define BH_IO_CTL_PEEK 0x0002 +#define BH_IO_CTL_FLUSH 0x0003 +#define BH_IO_CTL_SIZE 0x0004 +#define BH_IO_CTL_TELL 0x0005 +#define BH_IO_CTL_SEEK 0x0006 +#define BH_IO_CTL_GET_IO 0x0007 +#define BH_IO_CTL_SET_IO 0x0008 -#define BH_IO_SEEK_SET 0x0000 -#define BH_IO_SEEK_CUR 0x0001 -#define BH_IO_SEEK_END 0x0002 +#define BH_IO_SEEK_SET 0x0000 +#define BH_IO_SEEK_CUR 0x0001 +#define BH_IO_SEEK_END 0x0002 -#define BH_IO_FLAG_OK 0x0000 -#define BH_IO_FLAG_ERROR 0x0001 -#define BH_IO_FLAG_EOF 0x0002 -#define BH_IO_FLAG_OPEN 0x0004 +#define BH_IO_FLAG_OK 0x0000 +#define BH_IO_FLAG_ERROR 0x0001 +#define BH_IO_FLAG_EOF 0x0002 -#define BH_FILE_CLASSNAME "BH_File" +#define BH_FILE_READ 0x0001 +#define BH_FILE_WRITE 0x0002 +#define BH_FILE_READWRITE 0x0003 +#define BH_FILE_APPEND 0x0010 +#define BH_FILE_TRUNCATE 0x0020 +#define BH_FILE_CREATE 0x0040 +#define BH_FILE_EXIST 0x0080 -typedef struct BH_IO BH_IO; -typedef int (*BH_IOCallback)(void *, int ,void *, void *); + +typedef int (*BH_IOCallback)(void *, int, void *); + + +typedef struct BH_IO +{ + BH_IOCallback callback; +} BH_IO; + + +typedef struct BH_IOReadInfo +{ + char *data; + size_t size; + size_t *actual; +} BH_IOReadInfo; + + +typedef struct BH_IOWriteInfo +{ + const char *data; + size_t size; + size_t *actual; +} BH_IOWriteInfo; + + +typedef struct BH_IOCtlInfo +{ + int op; + void *arg; +} BH_IOCtlInfo; + + +typedef struct BH_IOSeekInfo +{ + int64_t offset; + int whence; +} BH_IOSeekInfo; /** - * Creates the IO that represents file with the given \a path. + * Creates an input/output device representing a file at the given \a path. * - * \param path File path + * \param path File path + * \param mode Open mode + * \param result Result code * - * \return On success, returns IO pointer. + * \return On success, returns IO device pointer. * \return On failure, returns NULL pointer. */ -BH_IO *BH_FileNew(const char *path); +BH_IO *BH_FileNew(const char *path, + int mode, + int *result); /** - * Creates the IO that buffers access to other \a io. + * Creates an input/output deivce that buffers access to other \a device. * - * \param io IO pointer + * \param device IO device pointer + * \param size Buffer size + * \param result Result code * - * \return On success, returns IO pointer. + * \return On success, returns IO device pointer. * \return On failure, returns NULL pointer. */ -BH_IO *BH_BufferNew(BH_IO *io); +BH_IO *BH_BufferNew(BH_IO *device, + size_t size, + int *result); /** - * Creates the IO with specified callback \a cb and \a data. + * Creates an input/output devices that access memory buffer. * - * \param cb Callback - * \param data Initialization data + * \param data Buffer pointer + * \param size Buffer size + * \param result Result code * - * \return On success, returns IO pointer. + * \return On success, returns IO device pointer. * \return On failure, returns NULL pointer. */ -BH_IO *BH_IONew(BH_IOCallback cb, - void *data); +BH_IO *BH_BytesNew(char *data, + size_t size, + int *result); /** - * Destroys the \a io. + * Destroys the input/output \a device. * - * \param io IO pointer + * \param device IO device pointer */ -void BH_IOFree(BH_IO *io); +void BH_IOFree(BH_IO *device); /** - * Returns the \a io classname. + * Reads up to \a size bytes from the \a device into \a buffer. * - * \param io IO pointer + * \param device IO device pointer + * \param buffer Buffer pointer + * \param size Buffer size + * \param actual Bytes read (optional) * - * \return On success, returns pointer to constant string. - * \return On failure, returns NULL pointer + * \return On success, returns zero. + * \return On failure, returns error code. */ -const char *BH_IOClassname(BH_IO* io); +int BH_IORead(BH_IO *device, + char *buffer, + size_t size, + size_t *actual); /** - * Opens the \a io in specified \a mode of operation. + * Writes up to \a size bytes to the \a device from \a buffer. * - * \param io IO pointer - * \param mode Mode of operation + * \param io IO device pointer + * \param buffer Buffer pointer + * \param size Buffer size + * \param actual Bytes written (optional) * * \return On success, returns zero. * \return On failure, returns error code. */ -int BH_IOOpen(BH_IO *io, - int mode); +int BH_IOWrite(BH_IO *io, + const char *buffer, + size_t size, + size_t *actual); /** - * Closes the \a io. + * Manupulates an input/output \a device with specific \a op and and \a arg. * - * \param io IO pointer + * \param device IO device pointer + * \param op Operation + * \param arg Argument * * \return On success, returns zero. * \return On failure, returns error code. */ -int BH_IOClose(BH_IO *io); +int BH_IOCtl(BH_IO *device, + int op, + void *arg); /** - * Reads up to \a size bytes from the \a io into \a buffer. + * Checks if an input/output \a device supports specific \a op. * - * \param io IO pointer + * \param device IO device pointer + * \param op Operation + * + * \return On success, returns zero. + * \return On failure, returns error code. + */ +int BH_IOCap(BH_IO *device, + int op); + + +/** + * Peeks up to \a size bytes from the \a device into \a buffer. + * + * \param device IO device pointer * \param buffer Buffer pointer * \param size Buffer size - * \param actual Bytes read (optional) + * \param actial Bytes peeked (optional) * * \return On success, returns zero. * \return On failure, returns error code. */ -int BH_IORead(BH_IO *io, +int BH_IOPeek(BH_IO *device, char *buffer, size_t size, size_t *actual); /** - * Writes up to \a size bytes to the \a io from \a buffer. + * Tells current \a offset in the \a device. * - * \param io IO pointer - * \param buffer Buffer pointer - * \param size Buffer size - * \param actual Bytes written (optional) + * \param device IO device pointer + * \param offset Position * * \return On success, returns zero. * \return On failure, returns error code. */ -int BH_IOWrite(BH_IO *io, - const char *buffer, - size_t size, - size_t *actual); +int BH_IOTell(BH_IO *device, + int64_t *offset); /** - * Peeks up to \a size bytes from \a io into \a buffer. + * Seeks to specified \a offset and \a whence in the \a device. * - * \param io IO pointer - * \param buffer Buffer pointer - * \param size Buffer size - * \param actial Bytes peeked (optional) + * \param device IO device pointer + * \param offset Position + * \param whence Direction * * \return On success, returns zero. * \return On failure, returns error code. */ -int BH_IOPeek(BH_IO *io, - char *buffer, - size_t size, - size_t *actual); +int BH_IOSeek(BH_IO *device, + int64_t offset, + int whence); /** - * Tells current \a position in the \a io. + * Flushes the internal buffers of the \a device. * - * \param io IO pointer - * \param position Position + * \param device IO device pointer * * \return On success, returns zero. * \return On failure, returns error code. */ -int BH_IOTell(BH_IO *io, - int64_t *position); +int BH_IOFlush(BH_IO *device); /** - * Seeks to specified \a position and \a direction in the \a io. + * Returns total or available size of the \a device. * - * \param io IO pointer - * \param position Position - * \param direction Direction + * \param device IO pointer + * \param size Available/total size * * \return On success, returns zero. * \return On failure, returns error code. */ -int BH_IOSeek(BH_IO *io, - int64_t position, - int direction); +int BH_IOSize(BH_IO *device, + int64_t *size); /** - * Flushes the internal buffers of the \a io. + * Returns flags of the \a device. * - * \param io IO pointer + * \param device IO device pointer + * \param flags Flags * * \return On success, returns zero. * \return On failure, returns error code. */ -int BH_IOFlush(BH_IO *io); +int BH_IOFlags(BH_IO *device, + int *flags); /** - * Returns total or available size of the \a io. + * Returns error flag of the \a device. * - * \param io IO pointer - * \param size Available/total size + * \param device IO device pointer * - * \return On success, returns zero. - * \return On failure, returns error code. + * \return Returns error flag. */ -int BH_IOSize(BH_IO *io, - int64_t *size); +int BH_IOError(BH_IO *device); /** - * Returns flags of the \a io. + * Returns end-of-file flag of the \a device. * - * \param io IO pointer + * \param device IO device pointer * - * \return Flags of the IO + * \return Returns end-of-file flag. */ -int BH_IOFlags(BH_IO *io); +int BH_IOEndOfFile(BH_IO *device); /** - * Clears errors of the \a io. + * Clears errors of the \a device. * - * \param io IO pointer + * \param device IO device pointer * * \return On success, returns zero. * \return On failure, returns error code. */ -int BH_IOClear(BH_IO *io); +int BH_IOClear(BH_IO *device); #endif /* BH_IO_H */ diff --git a/src/Buffer.c b/src/Buffer.c new file mode 100644 index 0000000..69e8ea3 --- /dev/null +++ b/src/Buffer.c @@ -0,0 +1,304 @@ +#include <BH/IO.h> +#include <stdlib.h> +#include <string.h> + + +typedef struct BH_BufferData +{ + char *data; + size_t size; + size_t capacity; + size_t offset; +} BH_BufferData; + + +typedef struct BH_Buffer +{ + BH_IO parent; + BH_IO *device; + BH_BufferData in; + BH_BufferData out; + int flags; +} BH_Buffer; + + +#define MIN(a,b) ((a)<(b)?(a):(b)) +#define MAX(a,b) ((a)>(b)?(a):(b)) + + +static int bufferInit(BH_Buffer *buffer, + BH_IO *device, + size_t size) +{ + if (!size) + size = 4096; + + if (!device) + return BH_ERROR; + + buffer->device = device; + + /* Allocate input buffer */ + buffer->in.data = malloc(size); + buffer->in.capacity = size; + buffer->in.size = buffer->in.offset = 0; + if (!buffer->in.data) + return BH_OOM; + + /* Allocate output buffer */ + buffer->out.data = malloc(size); + buffer->out.capacity = size; + buffer->out.size = buffer->out.offset = 0; + if (!buffer->out.data) + { + free(buffer->out.data); + return BH_OOM; + } + + return BH_OK; +} + + +static int bufferDestroy(BH_Buffer *buffer) +{ + /* Free buffers on destruction */ + free(buffer->in.data); + if (buffer->in.data != buffer->out.data) + free(buffer->out.data); + + free(buffer); + return BH_OK; +} + + +static int bufferRefill(BH_Buffer *buffer) +{ + size_t size; + int result; + + /* Shift existing data towards begining */ + memmove(buffer->in.data, buffer->in.data + buffer->in.offset, buffer->in.size); + buffer->in.offset = 0; + + /* Read data from the device */ + size = buffer->in.capacity - buffer->in.size; + if ((result = BH_IORead(buffer->device, buffer->in.data + buffer->in.size, size, &size))) + goto done; + buffer->in.size += size; + +done: + return result; +} + + +static int bufferFlush(BH_Buffer *buffer) +{ + size_t size; + int result; + + /* Flush data to underlying input/output device */ + result = BH_IOWrite(buffer->device, buffer->out.data, buffer->out.size, &size); + if (!result) + { + /* Move remaining data */ + buffer->out.offset += size; + buffer->out.size -= size; + memmove(buffer->out.data, buffer->out.data + buffer->out.offset, buffer->out.size); + buffer->out.offset = 0; + + if (buffer->out.size) + return BH_SHORT; + } + + return result; +} + + +static int bufferRead(BH_Buffer *buffer, + BH_IOReadInfo *info) +{ + size_t readed, size; + int result; + + result = BH_OK; + for (readed = 0; readed < info->size; ) + { + /* Refill input buffer if needed */ + if (!buffer->in.size && ((result = bufferRefill(buffer)) || !buffer->in.size)) + break; + + /* Copy data from buffer into user buffer */ + size = MIN(info->size - readed, buffer->in.size); + memcpy(info->data + readed, buffer->in.data + buffer->in.offset, size); + buffer->in.offset += size; + buffer->in.size -= size; + readed += size; + } + + /* Report readed size */ + if (info->actual) + *info->actual = readed; + return result; +} + + +static int bufferWrite(BH_Buffer *buffer, + BH_IOWriteInfo *info) +{ + size_t written, size; + int result; + + result = BH_OK; + for (written = 0; written < info->size; ) + { + /* Write data into output buffer */ + size = MIN(info->size - written, buffer->out.capacity - buffer->out.size); + memcpy(buffer->out.data + buffer->out.size, info->data + written, size); + buffer->out.size += size; + written += size; + + /* Flush output buffer if needed */ + if (buffer->out.size == buffer->out.capacity && (result = bufferFlush(buffer))) + break; + } + + /* Report written size */ + if (info->actual) + *info->actual = written; + return result; +} + + +int bufferPeek(BH_Buffer *buffer, + BH_IOReadInfo *info) +{ + size_t size; + int result; + + /* Requested size can't be bigger then buffer capacity */ + if (info->size > buffer->in.capacity) + return BH_FULL; + + /* Try to refill the buffer if we dont have enough data */ + if (info->size > buffer->in.size && (result = bufferRefill(buffer))) + return result; + + /* Copy data */ + size = MIN(info->size, buffer->in.size); + memcpy(info->data, buffer->in.data + buffer->in.offset, size); + + if (info->actual) + *info->actual = size; + return BH_OK; +} + + +static int bufferGetIO(BH_Buffer *buffer, + BH_IO **io) +{ + *io = buffer->device; + return BH_OK; +} + + +static int bufferSetIO(BH_Buffer *buffer, + BH_IO *io) +{ + /* Reset buffer states and change input/output deivce */ + buffer->in.offset = 0; + buffer->in.size = 0; + buffer->out.offset = 0; + buffer->out.size = 0; + buffer->device = io; + + return BH_OK; +} + + +static int bufferCap(BH_Buffer *buffer, + int *op) +{ + BH_UNUSED(buffer); + + /* Return operations supported by the buffer input/output device */ + switch (*op) + { + case BH_IO_CTL_FLUSH: + case BH_IO_CTL_PEEK: + case BH_IO_CTL_GET_IO: + case BH_IO_CTL_SET_IO: + return BH_OK; + + default: + return BH_NOIMPL; + } +} + + +static int bufferCtl(BH_Buffer *buffer, + BH_IOCtlInfo *info) +{ + /* Handle supported operations */ + switch (info->op) + { + case BH_IO_CTL_FLUSH: + return bufferFlush(buffer); + + case BH_IO_CTL_PEEK: + return bufferPeek(buffer, (BH_IOReadInfo *)info->arg); + + case BH_IO_CTL_GET_IO: + return bufferGetIO(buffer, (BH_IO **)info->arg); + + case BH_IO_CTL_SET_IO: + return bufferSetIO(buffer, (BH_IO *)info->arg); + + default: + return BH_NOIMPL; + } +} + + +static int bufferCallback(BH_Buffer *buffer, + int type, + void *arg) +{ + /* Handle basic input/output operations */ + switch (type) + { + case BH_IO_OP_DESTROY: return bufferDestroy(buffer); + case BH_IO_OP_READ: return bufferRead(buffer, (BH_IOReadInfo *)arg); + case BH_IO_OP_WRITE: return bufferWrite(buffer, (BH_IOWriteInfo *)arg); + case BH_IO_OP_CTL: return bufferCtl(buffer, (BH_IOCtlInfo *)arg); + case BH_IO_OP_CAP: return bufferCap(buffer, (int*)arg); + default: return BH_NOIMPL; + } +} + + +BH_IO *BH_BufferNew(BH_IO *device, + size_t size, + int *result) +{ + BH_Buffer *buffer; + int code; + + code = BH_OOM; + + /* Allocate new buffer object and initialize it */ + if ((buffer = malloc(sizeof(*buffer)))) + { + buffer->parent.callback = (BH_IOCallback)bufferCallback; + if ((code = bufferInit(buffer, device, size))) + { + free(buffer); + buffer = NULL; + } + } + + /* Report error code */ + if (result) + *result = code; + + return (BH_IO*)buffer; +} diff --git a/src/Bytes.c b/src/Bytes.c new file mode 100644 index 0000000..efa973a --- /dev/null +++ b/src/Bytes.c @@ -0,0 +1,217 @@ +#include <BH/IO.h> +#include <string.h> +#include <stdlib.h> + + +#define MIN(a,b) ((a)<(b)?(a):(b)) +#define MAX(a,b) ((a)>(b)?(a):(b)) + + +typedef struct BH_Bytes +{ + BH_IO parent; + char *data; + size_t size; + size_t position; +} BH_Bytes; + + +static int bytesInit(BH_Bytes *bytes, + char *data, + size_t size) +{ + if (!data || !size) + return BH_ERROR; + + bytes->data = data; + bytes->size = size; + bytes->position = 0; + + return BH_OK; +} + + +static int bytesDestroy(BH_Bytes *bytes) +{ + BH_UNUSED(bytes); + + return BH_OK; +} + + +static int bytesRead(BH_Bytes *bytes, + BH_IOReadInfo *info) +{ + size_t size; + + size = MIN(info->size, bytes->size - bytes->position); + memmove(info->data, bytes->data + bytes->position, size); + bytes->position += size; + + if (info->actual) + *info->actual = size; + + return BH_OK; +} + + +static int bytesWrite(BH_Bytes *bytes, + BH_IOWriteInfo *info) +{ + size_t size; + + size = MIN(info->size, bytes->size - bytes->position); + memmove(bytes->data + bytes->position, info->data, size); + bytes->position += size; + + if (info->actual) + *info->actual = size; + + return BH_OK; +} + +static int bytesSeek(BH_Bytes *bytes, + BH_IOSeekInfo *info) +{ + int64_t offset; + + switch (info->whence) + { + case BH_IO_SEEK_SET: + offset = MAX(info->offset, 0); + offset = MIN(offset, (int64_t)bytes->size); + break; + + case BH_IO_SEEK_CUR: + offset = MAX((int64_t)bytes->position + info->offset, 0); + offset = MIN(offset, (int64_t)bytes->size); + break; + + case BH_IO_SEEK_END: + offset = MAX((int64_t)bytes->size + info->offset, 0); + offset = MIN(offset, (int64_t)bytes->size); + break; + } + + bytes->position = offset; + + return BH_OK; +} + + +static int bytesTell(BH_Bytes *bytes, + int64_t *pos) +{ + *pos = bytes->position; + + return BH_OK; +} + + +static int bytesSize(BH_Bytes *bytes, + int64_t *size) +{ + *size = bytes->size; + + return BH_OK; +} + + +static int bytesFlags(BH_Bytes *bytes, + int *flags) +{ + if (bytes->position == bytes->size) + *flags = BH_IO_FLAG_EOF; + else + *flags = 0; + + return BH_OK; +} + + +static int bytesCap(BH_Bytes *bytes, + int *op) +{ + BH_UNUSED(bytes); + + /* Return operations supported by the buffer input/output device */ + switch (*op) + { + case BH_IO_CTL_FLAGS: + case BH_IO_CTL_SIZE: + case BH_IO_CTL_TELL: + case BH_IO_CTL_SEEK: + return BH_OK; + + default: + return BH_NOIMPL; + } +} + + +static int bytesCtl(BH_Bytes *bytes, + BH_IOCtlInfo *info) +{ + /* Handle supported operations */ + switch (info->op) + { + case BH_IO_CTL_FLAGS: + return bytesFlags(bytes, (int *)info->arg); + + case BH_IO_CTL_SIZE: + return bytesSize(bytes, (int64_t *)(info->arg)); + + case BH_IO_CTL_TELL: + return bytesTell(bytes, (int64_t *)(info->arg)); + + case BH_IO_CTL_SEEK: + return bytesSeek(bytes, (BH_IOSeekInfo *)(info->arg)); + + default: + return BH_NOIMPL; + } +} + + +static int bytesCallback(BH_Bytes *bytes, + int type, + void *arg) +{ + /* Handle basic input/output operations */ + switch (type) + { + case BH_IO_OP_DESTROY: return bytesDestroy(bytes); + case BH_IO_OP_READ: return bytesRead(bytes, (BH_IOReadInfo *)arg); + case BH_IO_OP_WRITE: return bytesWrite(bytes, (BH_IOWriteInfo *)arg); + case BH_IO_OP_CTL: return bytesCtl(bytes, (BH_IOCtlInfo *)arg); + case BH_IO_OP_CAP: return bytesCap(bytes, (int*)arg); + default: return BH_NOIMPL; + } +} + + +BH_IO *BH_BytesNew(char *data, + size_t size, + int *result) +{ + BH_Bytes *bytes; + int code; + + code = BH_OOM; + /* Allocate new buffer object and initialize it */ + if ((bytes = malloc(sizeof(*bytes)))) + { + bytes->parent.callback = (BH_IOCallback)bytesCallback; + if ((code = bytesInit(bytes, data, size))) + { + free(bytes); + bytes = NULL; + } + } + + /* Report error code */ + if (result) + *result = code; + + return (BH_IO*)bytes; +} @@ -5,231 +5,176 @@ #define BUFFER_SIZE (sizeof(char *)) -struct BH_IO -{ - BH_IOCallback cb; -}; - - -BH_IO *BH_IONew(BH_IOCallback cb, - void *data) -{ - size_t requested; - BH_IO *io; - - /* Get information about IO device size */ - if (cb(NULL, BH_IO_INFO_CB, &requested, NULL)) - return NULL; - - /* Allocate space for the IO device */ - io = malloc(sizeof(*io) + requested); - if (!io) - return NULL; - - /* Initialize IO device */ - io->cb = cb; - if (cb(io + 1, BH_IO_INIT_CB, data, NULL)) - { - free(io); - return NULL; - } - - return io; -} - - -void BH_IOFree(BH_IO *io) +void BH_IOFree(BH_IO *device) { /* Prevent working with NULL io */ - if (!io) + if (!device) return; - /* Call the IO device destruction handler */ - io->cb(io + 1, BH_IO_DESTROY_CB, NULL, NULL); - - /* Deallocate object */ - free(io); + /* Call the IO device destruction handler and deallocate */ + device->callback(device, BH_IO_OP_DESTROY, NULL); } -const char *BH_IOClassname(BH_IO *io) +int BH_IORead(BH_IO *device, + char *buffer, + size_t size, + size_t *actual) { - const char *name; - - if (!io) - goto error; + BH_IOReadInfo info; - if (io->cb(io + 1, BH_IO_INFO_CB, NULL, &name) != BH_OK) - goto error; - - return name; - -error: - return NULL; -} - - -int BH_IOOpen(BH_IO *io, - int mode) -{ /* Prevent working with NULL io */ - if (!io) + if (!device) return BH_ERROR; - /* Call the IO device open handler with specified mode */ - return io->cb(io + 1, BH_IO_OPEN_CB, &mode, NULL); + info.data = buffer; + info.size = size; + info.actual = actual; + return device->callback(device, BH_IO_OP_READ, &info); } -int BH_IOClose(BH_IO *io) +int BH_IOWrite(BH_IO *device, + const char *buffer, + size_t size, + size_t *actual) { + BH_IOWriteInfo info; + /* Prevent working with NULL io */ - if (!io) + if (!device) return BH_ERROR; - /* Call the IO device close handler */ - return io->cb(io + 1, BH_IO_CLOSE_CB, NULL, NULL); + info.data = buffer; + info.size = size; + info.actual = actual; + + return device->callback(device, BH_IO_OP_WRITE, &info); } -int BH_IORead(BH_IO *io, - char *buffer, - size_t size, - size_t *actual) +int BH_IOCtl(BH_IO *device, + int op, + void *arg) { - int code; + BH_IOCtlInfo info; - /* Prevent working with NULL io */ - if (!io) + if (!device) return BH_ERROR; - /* Call the IO device read handler */ - code = io->cb(io + 1, BH_IO_READ_CB, buffer, &size); - - /* If caller wants to know actual read size - report it back */ - if (actual) - *actual = size; - - return code; + info.op = op; + info.arg = arg; + return device->callback(device, BH_IO_OP_CTL, &info); } -int BH_IOWrite(BH_IO *io, - const char *buffer, - size_t size, - size_t *actual) +int BH_IOCap(BH_IO *device, + int op) { - int code; - - /* Prevent working with NULL io */ - if (!io) + if (!device) return BH_ERROR; - /* Call the IO device write handler */ - code = io->cb(io + 1, BH_IO_WRITE_CB, (void *)buffer, &size); - - /* If caller wants to know actual written size - report it back */ - if (actual) - *actual = size; - - return code; + return device->callback(device, BH_IO_OP_CAP, &op); } -int BH_IOPeek(BH_IO *io, +int BH_IOPeek(BH_IO *device, char *buffer, size_t size, size_t *actual) { - int code; + BH_IOReadInfo readInfo; + BH_IOSeekInfo posInfo; + size_t readed; - /* Prevent working with NULL io */ - if (!io) - return BH_ERROR; + readInfo.data = buffer; + readInfo.size = size; + readInfo.actual = actual; + + if (BH_IOCap(device, BH_IO_CTL_PEEK)) + { + if (BH_IOCap(device, BH_IO_CTL_SEEK)) + return BH_NOIMPL; + + if (BH_IORead(device, buffer, size, &readed)) + return BH_ERROR; + + posInfo.whence = BH_IO_SEEK_CUR; + posInfo.offset = -(int64_t)readed; + if (BH_IOCtl(device, BH_IO_CTL_SEEK, &posInfo)) + return BH_ERROR; - /* Call the IO device peek handler */ - code = io->cb(io + 1, BH_IO_PEEK_CB, (void *)buffer, &size); + if (actual) + *actual = readed; - /* If caller wants to know actual written size - report it back */ - if (actual) - *actual = size; + return BH_OK; + } - return code; + return BH_IOCtl(device, BH_IO_CTL_PEEK, &readInfo); } -int BH_IOTell(BH_IO *io, - int64_t *position) +int BH_IOTell(BH_IO *device, + int64_t *offset) { - /* Prevent working with NULL io */ - if (!io) - return BH_ERROR; - - /* Call the IO device tell handler */ - return io->cb(io + 1, BH_IO_TELL_CB, position, NULL); + return BH_IOCtl(device, BH_IO_CTL_TELL, offset); } -int BH_IOSeek(BH_IO *io, - int64_t position, - int direction) +int BH_IOSeek(BH_IO *device, + int64_t offset, + int whence) { - /* Prevent working with NULL io */ - if (!io) - return BH_ERROR; + BH_IOSeekInfo info; - /* Call the IO device seek handler */ - return io->cb(io + 1, BH_IO_SEEK_CB, &position, &direction); + info.offset = offset; + info.whence = whence; + return BH_IOCtl(device, BH_IO_CTL_SEEK, &info); } -int BH_IOFlush(BH_IO *io) +int BH_IOFlush(BH_IO *device) { - /* Prevent working with NULL io */ - if (!io) - return BH_ERROR; - - /* Call the IO device flush handler */ - return io->cb(io + 1, BH_IO_FLUSH_CB, NULL, NULL); + return BH_IOCtl(device, BH_IO_CTL_FLUSH, NULL); } -int BH_IOSize(BH_IO *io, +int BH_IOSize(BH_IO *device, int64_t *size) { - /* Prevent working with NULL io */ - if (!io) - return BH_ERROR; - - /* Call the IO device size handler */ - return io->cb(io + 1, BH_IO_SIZE_CB, size, NULL); + return BH_IOCtl(device, BH_IO_CTL_SIZE, size); } -int BH_IOFlags(BH_IO *io) +int BH_IOFlags(BH_IO *device, int *flags) { - /* Prevent working with NULL io */ - if (!io) - return BH_IO_FLAG_ERROR; + return BH_IOCtl(device, BH_IO_CTL_FLAGS, flags); +} - /* Call the IO device flags handler */ - return io->cb(io + 1, BH_IO_FLAGS_CB, NULL, NULL); + +int BH_IOClear(BH_IO *device) +{ + return BH_IOCtl(device, BH_IO_CTL_CLEAR, NULL); } -int BH_IOClear(BH_IO *io) +int BH_IOError(BH_IO *device) { - /* Prevent working with NULL io */ - if (!io) - return BH_OK; + int flags; - /* Call the IO device clear error handler */ - return io->cb(io + 1, BH_IO_CLEAR_CB, NULL, NULL); + if (BH_IOFlags(device, &flags)) + return BH_ERROR; + + return flags & BH_IO_FLAG_ERROR; } -BH_IO *BH_BufferNew(BH_IO *io) +int BH_IOEndOfFile(BH_IO *device) { - (void)io; - return NULL; + int flags; + + if (BH_IOFlags(device, &flags)) + return BH_ERROR; + + return flags & BH_IO_FLAG_EOF; } diff --git a/src/Platform/Dummy/File.c b/src/Platform/Dummy/File.c index 2cb1cd6..5e5b515 100644 --- a/src/Platform/Dummy/File.c +++ b/src/Platform/Dummy/File.c @@ -1,200 +1,15 @@ #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) +BH_IO *BH_FileNew(const char *path, + int mode, + int *result) { - return BH_NOIMPL; -} + BH_UNUSED(path); + BH_UNUSED(mode); + if (result) + *result = 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); + return NULL; } diff --git a/src/Platform/Posix/File.c b/src/Platform/Posix/File.c index f8ee089..c91a46f 100644 --- a/src/Platform/Posix/File.c +++ b/src/Platform/Posix/File.c @@ -10,166 +10,67 @@ typedef struct BH_File { - char *path; - int mode; + BH_IO parent; 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) +static int fileOpenFlags(int mode) { int flags = 0; /* Determine read/write flags */ - if ((mode & BH_IO_READWRITE) == BH_IO_READWRITE) + if ((mode & BH_FILE_READWRITE) == BH_FILE_READWRITE) flags |= O_RDWR; - else if (mode & BH_IO_WRITE) + else if (mode & BH_FILE_WRITE) flags |= O_WRONLY; - else if (mode & BH_IO_READ) + else if (mode & BH_FILE_READ) flags |= O_RDONLY; else return -1; /* Check if existing file should be opened */ - if (!(mode & BH_IO_EXIST)) + if (!(mode & BH_FILE_EXIST)) { flags |= O_CREAT; /* Check if file should be created */ - if (mode & BH_IO_CREATE) + if (mode & BH_FILE_CREATE) flags |= O_EXCL; } /* Check if file should be opened in append mode */ - if (mode & BH_IO_APPEND) + if (mode & BH_FILE_APPEND) flags |= O_APPEND; /* Check if file should be truncated */ - if (mode & BH_IO_TRUNCATE) + if (mode & BH_FILE_TRUNCATE) flags |= O_TRUNC; return flags; } -static int BH_FileOpen(BH_File *file, - int *mode) +static int fileInit(BH_File *file, + const char *path, + 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) + /* Check if path is valid */ + if (!path) return BH_ERROR; /* Determine file open flags */ - flags = BH_FileOpenFlags(*mode); + flags = fileOpenFlags(mode); if (flags == -1) return BH_ERROR; /* Open the file */ - file->handle = open(file->path, flags, open_mode); + file->flags = 0; + file->handle = open(path, flags, open_mode); if (file->handle == -1) return BH_ERROR; @@ -177,32 +78,22 @@ static int BH_FileOpen(BH_File *file, } -static int BH_FileClose(BH_File *file) +static int fileDestroy(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; + free(file); return BH_OK; } -static int BH_FileRead(BH_File *file, - char *data, - size_t *size) +static int fileRead(BH_File *file, + BH_IOReadInfo *info) { 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); + readed = read(file->handle, info->data, info->size); if (readed < 0) goto error; @@ -212,7 +103,8 @@ static int BH_FileRead(BH_File *file, else file->flags |= BH_IO_FLAG_EOF; - *size = readed; + if (info->actual) + *info->actual = readed; return BH_OK; error: @@ -221,18 +113,13 @@ error: } -static int BH_FileWrite(BH_File *file, - const char *data, - size_t *size) +static int fileWrite(BH_File *file, + BH_IOWriteInfo *info) { 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); + written = write(file->handle, info->data, info->size); if (written < 0) goto error; @@ -242,7 +129,8 @@ static int BH_FileWrite(BH_File *file, else file->flags &= ~BH_IO_FLAG_EOF; - *size = written; + if (info->actual) + *info->actual = written; return BH_OK; error: @@ -251,60 +139,19 @@ error: } -static int BH_FilePeek(BH_File *file, - char *data, - size_t *size) +static int fileFlush(BH_File *file) { - 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) +static int fileSeek(BH_File *file, + BH_IOSeekInfo *info) { - /* Check if file is open */ - if (file->handle == -1) - goto error; - /* Seek to the specified position */ - if (lseek(file->handle, *pos, *dir) == -1) + if (lseek(file->handle, info->offset, info->whence) == -1) goto error; return BH_OK; @@ -315,13 +162,9 @@ error: } -static int BH_FileTell(BH_File *file, - int64_t *pos) +static int 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; @@ -334,15 +177,11 @@ error: } -static int BH_FileSize(BH_File *file, - int64_t *size) +static int 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; @@ -356,51 +195,114 @@ error: } -static int BH_FileFlags(BH_File *file) +static int fileFlags(BH_File *file, + int *flags) { - /* If file handle is valid - append IO_OPEN flag */ - if (file->handle != -1) - return file->flags | BH_IO_FLAG_OPEN; - - return file->flags; + *flags = file->flags; + return BH_OK; } -static int BH_FileClear(BH_File *file) +static int fileClear(BH_File *file) { - /* Clear IO_ERROR flag */ + /* Clear BH_IO_FLAG_ERROR flag */ file->flags &= ~BH_IO_FLAG_ERROR; return BH_OK; } -static int BH_FileCallback(BH_File *file, - int type, - void *arg1, - void *arg2) +static int fileCap(BH_File *file, + int *op) +{ + BH_UNUSED(file); + + /* Return operations supported by the file input/output device */ + switch (*op) + { + case BH_IO_CTL_FLAGS: + case BH_IO_CTL_CLEAR: + case BH_IO_CTL_FLUSH: + case BH_IO_CTL_SIZE: + case BH_IO_CTL_TELL: + case BH_IO_CTL_SEEK: + return BH_OK; + + default: + return BH_NOIMPL; + } +} + + +static int fileCtl(BH_File *file, + BH_IOCtlInfo *info) +{ + /* Handle supported operations */ + switch (info->op) + { + case BH_IO_CTL_FLAGS: + return fileFlags(file, (int *)info->arg); + + case BH_IO_CTL_CLEAR: + return fileClear(file); + + case BH_IO_CTL_FLUSH: + return fileFlush(file); + + case BH_IO_CTL_SIZE: + return fileSize(file, (int64_t *)(info->arg)); + + case BH_IO_CTL_TELL: + return fileTell(file, (int64_t *)(info->arg)); + + case BH_IO_CTL_SEEK: + return fileSeek(file, (BH_IOSeekInfo *)(info->arg)); + + default: + return BH_NOIMPL; + } +} + + +static int fileCallback(BH_File *file, + int type, + void *arg) { + /* Handle basic input/output operations */ 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); + case BH_IO_OP_DESTROY: return fileDestroy(file); + case BH_IO_OP_READ: return fileRead(file, (BH_IOReadInfo *)arg); + case BH_IO_OP_WRITE: return fileWrite(file, (BH_IOWriteInfo *)arg); + case BH_IO_OP_CTL: return fileCtl(file, (BH_IOCtlInfo *)arg); + case BH_IO_OP_CAP: return fileCap(file, (int*)arg); default: return BH_NOIMPL; } } -BH_IO *BH_FileNew(const char *path) +BH_IO *BH_FileNew(const char *path, + int mode, + int *result) { - return BH_IONew((BH_IOCallback)BH_FileCallback, (void *)path); + BH_File *file; + int code; + + code = BH_OOM; + + /* Allocate new file object and initialize it */ + if ((file = malloc(sizeof(*file)))) + { + file->parent.callback = (BH_IOCallback)fileCallback; + if ((code = fileInit(file, path, mode))) + { + free(file); + file = NULL; + } + } + + /* Report error code */ + if (result) + *result = code; + + return (BH_IO*)file; } diff --git a/src/Platform/Win32/File.c b/src/Platform/Win32/File.c index 3cb1972..05a0d56 100644 --- a/src/Platform/Win32/File.c +++ b/src/Platform/Win32/File.c @@ -6,195 +6,87 @@ typedef struct BH_File { - char *path; - int mode; + BH_IO parent; int flags; + int mode; 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 int fileInit(BH_File *file, + const char *path, + int mode) { - static const char classname[] = BH_FILE_CLASSNAME; - - if (size) - *size = sizeof(*file); - if (name) - *name = classname; - - return BH_OK; -} - + DWORD access = 0, how = 0; -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) + if (mode & BH_FILE_READ) access |= GENERIC_READ; - if (*mode & BH_IO_WRITE) + if (mode & BH_FILE_WRITE) access |= GENERIC_WRITE; if (!access) return BH_ERROR; /* Determine open mode flags */ - if (*mode & BH_IO_TRUNCATE) + if (mode & BH_FILE_TRUNCATE) { - switch (*mode & (BH_IO_CREATE | BH_IO_EXIST)) + switch (mode & (BH_FILE_CREATE | BH_FILE_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; + case 0: how = CREATE_ALWAYS; break; + case BH_FILE_CREATE: how = CREATE_NEW; break; + case BH_FILE_EXIST: how = TRUNCATE_EXISTING; break; + default: return BH_ERROR; } } else { - switch (*mode & (BH_IO_CREATE | BH_IO_EXIST)) + switch (mode & (BH_FILE_CREATE | BH_FILE_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; + case 0: how = OPEN_ALWAYS; break; + case BH_FILE_CREATE: how = CREATE_NEW; break; + case BH_FILE_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); + 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 BH_ERROR; /* Truncate file if needed */ - if (*mode & BH_IO_TRUNCATE) + if (mode & BH_FILE_TRUNCATE) SetEndOfFile(file->handle); return BH_OK; } -static int BH_FileClose(BH_File *file) +static int fileDestroy(BH_File *file) { - /* If file is opened - close it */ - if (file->handle == INVALID_HANDLE_VALUE) - return BH_ERROR; - - /* Reset handle and mode values */ + /* Close the file handle on destruction */ CloseHandle(file->handle); - file->handle = INVALID_HANDLE_VALUE; - file->mode = 0; + free(file); + return BH_OK; } -static int BH_FileRead(BH_File *file, - char *data, - size_t *size) +static int fileRead(BH_File *file, + BH_IOReadInfo *info) { 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)) + if (!ReadFile(file->handle, info->data, (DWORD)info->size, &readed, NULL)) goto error; /* Check if we reached end of file */ @@ -203,7 +95,9 @@ static int BH_FileRead(BH_File *file, else file->flags &= ~BH_IO_FLAG_EOF; - *size = readed; + if (info->actual) + *info->actual = readed; + return BH_OK; error: @@ -212,28 +106,22 @@ error: } -static int BH_FileWrite(BH_File *file, - const char *data, - size_t *size) +static int fileWrite(BH_File *file, + BH_IOWriteInfo *info) { DWORD written; - - /* Check if file is opened */ - if (file->handle == INVALID_HANDLE_VALUE) - goto error; + LARGE_INTEGER position; /* Adjust current position in the file to the end */ - if (file->mode & BH_IO_APPEND) + if (file->mode & BH_FILE_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)) + if (!WriteFile(file->handle, info->data, (DWORD)info->size, &written, NULL)) goto error; /* Check for end of file */ @@ -242,7 +130,9 @@ static int BH_FileWrite(BH_File *file, else file->flags &= ~BH_IO_FLAG_EOF; - *size = written; + if (info->actual) + *info->actual = written; + return BH_OK; error: @@ -251,56 +141,22 @@ 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) +static int 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) +static int fileSeek(BH_File *file, + BH_IOSeekInfo *info) { 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)) + position.QuadPart = info->offset; + if (!SetFilePointerEx(file->handle, position, NULL, info->whence)) goto error; return BH_OK; @@ -311,15 +167,11 @@ error: } -static int BH_FileTell(BH_File *file, - int64_t *pos) +static int 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)) @@ -334,15 +186,11 @@ error: } -static int BH_FileSize(BH_File *file, - int64_t *size) +static int 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; @@ -356,50 +204,114 @@ error: } -static int BH_FileFlags(BH_File *file) +static int fileFlags(BH_File *file, + int *flags) { - /* 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; + *flags = file->flags; + return BH_OK; } -static int BH_FileClear(BH_File *file) +static int fileClear(BH_File *file) { - /* Clear IO_ERROR flag */ + /* Clear BH_IO_FLAG_ERROR flag */ file->flags &= ~BH_IO_FLAG_ERROR; return BH_OK; } -static int BH_FileCallback(BH_File *file, - int type, - void *arg1, - void *arg2) +static int fileCap(BH_File *file, + int *op) +{ + BH_UNUSED(file); + + /* Return operations supported by the file input/output device */ + switch (*op) + { + case BH_IO_CTL_FLAGS: + case BH_IO_CTL_CLEAR: + case BH_IO_CTL_FLUSH: + case BH_IO_CTL_SIZE: + case BH_IO_CTL_TELL: + case BH_IO_CTL_SEEK: + return BH_OK; + + default: + return BH_NOIMPL; + } +} + + +static int fileCtl(BH_File *file, + BH_IOCtlInfo *info) { + /* Handle supported operations */ + switch (info->op) + { + case BH_IO_CTL_FLAGS: + return fileFlags(file, (int *)(info->arg)); + + case BH_IO_CTL_CLEAR: + return fileClear(file); + + case BH_IO_CTL_FLUSH: + return fileFlush(file); + + case BH_IO_CTL_SIZE: + return fileSize(file, (int64_t *)(info->arg)); + + case BH_IO_CTL_TELL: + return fileTell(file, (int64_t *)(info->arg)); + + case BH_IO_CTL_SEEK: + return fileSeek(file, (BH_IOSeekInfo *)(info->arg)); + + default: + return BH_NOIMPL; + } +} + + +static int fileCallback(BH_File *file, + int type, + void *arg) +{ + /* Handle basic input/output operations */ 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); + case BH_IO_OP_DESTROY: return fileDestroy(file); + case BH_IO_OP_READ: return fileRead(file, (BH_IOReadInfo *)arg); + case BH_IO_OP_WRITE: return fileWrite(file, (BH_IOWriteInfo *)arg); + case BH_IO_OP_CTL: return fileCtl(file, (BH_IOCtlInfo *)arg); + case BH_IO_OP_CAP: return fileCap(file, (int*)arg); default: return BH_NOIMPL; } } -BH_IO *BH_FileNew(const char *path) +BH_IO *BH_FileNew(const char *path, + int mode, + int *result) { - return BH_IONew((BH_IOCallback)BH_FileCallback, (void *)path); + BH_File *file; + int code; + + code = BH_OOM; + + /* Allocate new file object and initialize it */ + if ((file = malloc(sizeof(*file)))) + { + file->parent.callback = (BH_IOCallback)fileCallback; + if ((code = fileInit(file, path, mode))) + { + free(file); + file = NULL; + } + } + + /* Report error code */ + if (result) + *result = code; + + return (BH_IO*)file; } diff --git a/test/src/TestBuffer.c b/test/src/TestBuffer.c new file mode 100644 index 0000000..05d6923 --- /dev/null +++ b/test/src/TestBuffer.c @@ -0,0 +1,126 @@ +#include <BH/IO.h> +#include <BH/Unit.h> +#include <string.h> +#include <stdio.h> + + +BH_UNIT_TEST(Null) +{ + BH_VERIFY(BH_BufferNew(NULL, 0, NULL) == NULL); + return 0; +} + + +BH_UNIT_TEST(Write) +{ + BH_IO *buffer, *io; + char data[16]; + int64_t offset; + size_t size; + + memset(data, 0, 16); + BH_VERIFY((io = BH_BytesNew(data, 16, NULL)) != NULL); + BH_VERIFY((buffer = BH_BufferNew(io, 4, NULL)) != NULL); + + BH_VERIFY(BH_IOWrite(buffer, "1234567", 7, &size) == BH_OK); + BH_VERIFY(size == 7); + + BH_VERIFY(BH_IOWrite(buffer, "8901234", 7, &size) == BH_OK); + BH_VERIFY(size == 7); + + BH_VERIFY(BH_IOWrite(buffer, "5", 1, &size) == BH_OK); + BH_VERIFY(size == 1); + BH_VERIFY(memcmp(data, "123456789012", 13) == 0); + BH_VERIFY(BH_IOTell(io, &offset) == BH_OK); + BH_VERIFY(offset == 12); + + BH_VERIFY(BH_IOFlush(buffer) == BH_OK); + BH_VERIFY(memcmp(data, "123456789012345", 15) == 0); + BH_VERIFY(BH_IOTell(io, &offset) == BH_OK); + BH_VERIFY(offset == 15); + + BH_VERIFY(BH_IOWrite(buffer, "678", 3, &size) == BH_OK); + BH_VERIFY(size == 3); + BH_VERIFY(BH_IOFlush(buffer) != BH_OK); + BH_VERIFY(memcmp(data, "1234567890123456", 16) == 0); + BH_VERIFY(BH_IOTell(io, &offset) == BH_OK); + BH_VERIFY(offset == 16); + + BH_IOFree(buffer); + BH_IOFree(io); + return 0; +} + + +BH_UNIT_TEST(Read) +{ + BH_IO *buffer, *io; + char data[16]; + char tmp[4]; + size_t size; + + memset(data, '1', 16); + BH_VERIFY((io = BH_BytesNew(data, 16, NULL)) != NULL); + BH_VERIFY((buffer = BH_BufferNew(io, 4, NULL)) != NULL); + + BH_VERIFY(BH_IORead(buffer, tmp, 2, &size) == BH_OK); + BH_VERIFY(size == 2); + BH_VERIFY(memcmp(tmp, "11", 2) == 0); + memset(data, '2', 16); + + BH_VERIFY(BH_IORead(buffer, tmp, 2, &size) == BH_OK); + BH_VERIFY(size == 2); + BH_VERIFY(memcmp(tmp, "11", 2) == 0); + + BH_VERIFY(BH_IORead(buffer, tmp, 2, &size) == BH_OK); + BH_VERIFY(size == 2); + BH_VERIFY(memcmp(tmp, "22", 2) == 0); + + BH_IOFree(buffer); + BH_IOFree(io); + return 0; +} + + +BH_UNIT_TEST(Reset) +{ + BH_IO *buffer, *io, *previous; + char data[16]; + char tmp[4]; + size_t size; + + memset(data, '1', 16); + BH_VERIFY((io = BH_BytesNew(data, 16, NULL)) != NULL); + BH_VERIFY((buffer = BH_BufferNew(io, 4, NULL)) != NULL); + + BH_VERIFY(BH_IORead(buffer, tmp, 2, &size) == BH_OK); + BH_VERIFY(size == 2); + BH_VERIFY(memcmp(tmp, "11", 2) == 0); + memset(data, '2', 16); + + BH_VERIFY(BH_IOCtl(buffer, BH_IO_CTL_GET_IO, &previous) == BH_OK); + BH_VERIFY(previous == io); + BH_VERIFY(BH_IOCtl(buffer, BH_IO_CTL_SET_IO, io) == BH_OK); + BH_VERIFY(BH_IORead(buffer, tmp, 2, &size) == BH_OK); + BH_VERIFY(size == 2); + BH_VERIFY(memcmp(tmp, "22", 2) == 0); + + BH_IOFree(buffer); + BH_IOFree(io); + return 0; +} + + +int main(int argc, + char **argv) +{ + BH_UNUSED(argc); + BH_UNUSED(argv); + + BH_UNIT_ADD(Null); + BH_UNIT_ADD(Write); + BH_UNIT_ADD(Read); + BH_UNIT_ADD(Reset); + + return BH_UnitRun(); +} diff --git a/test/src/TestBytes.c b/test/src/TestBytes.c new file mode 100644 index 0000000..e718a96 --- /dev/null +++ b/test/src/TestBytes.c @@ -0,0 +1,153 @@ +#include <BH/IO.h> +#include <BH/Unit.h> +#include <string.h> + + +BH_UNIT_TEST(Null) +{ + char data; + + BH_VERIFY(BH_BytesNew(NULL, 0, NULL) == NULL); + BH_VERIFY(BH_BytesNew(&data, 0, NULL) == NULL); + BH_VERIFY(BH_BytesNew(NULL, 1234, NULL) == NULL); + return 0; +} + + +BH_UNIT_TEST(Read) +{ + BH_IO *io; + char buffer1[14] = "Hello, world!"; + char buffer2[14]; + size_t size; + + BH_VERIFY((io = BH_BytesNew(buffer1, 14, NULL)) != NULL); + BH_VERIFY(BH_IORead(io, buffer2, 14, &size) == BH_OK); + BH_VERIFY(size == 14); + BH_VERIFY(memcmp(buffer1, buffer2, 14) == 0); + BH_VERIFY(BH_IOEndOfFile(io)); + + BH_VERIFY(BH_IORead(io, buffer2, 14, &size) == BH_OK); + BH_VERIFY(size == 0); + BH_VERIFY(BH_IOEndOfFile(io)); + BH_IOFree(io); + + return 0; +} + + +BH_UNIT_TEST(Write) +{ + BH_IO *io; + char buffer[14]; + size_t size; + + BH_VERIFY((io = BH_BytesNew(buffer, 14, NULL)) != NULL); + BH_VERIFY(BH_IOWrite(io, "Hello, world!", 14, &size) == BH_OK); + BH_VERIFY(size == 14); + BH_VERIFY(memcmp(buffer, "Hello, world!", 14) == 0); + + BH_VERIFY(BH_IOWrite(io, "Something", 10, &size) == BH_OK); + BH_VERIFY(size == 0); + BH_VERIFY(memcmp(buffer, "Hello, world!", 14) == 0); + BH_IOFree(io); + + return 0; +} + + +BH_UNIT_TEST(SeekTell) +{ + BH_IO *io; + char buffer[14] = "Hello, world!"; + char symbol; + int64_t offset; + size_t size; + + BH_VERIFY((io = BH_BytesNew(buffer, 14, NULL)) != NULL); + BH_VERIFY(BH_IOTell(io, &offset) == BH_OK); + BH_VERIFY(offset == 0); + BH_VERIFY(BH_IORead(io, &symbol, 1, &size) == BH_OK); + BH_VERIFY(BH_IOTell(io, &offset) == BH_OK); + BH_VERIFY(size == 1); + BH_VERIFY(symbol == 'H'); + BH_VERIFY(offset == 1); + + BH_VERIFY(BH_IOSeek(io, 8, BH_IO_SEEK_SET) == BH_OK); + BH_VERIFY(BH_IOTell(io, &offset) == BH_OK); + BH_VERIFY(offset == 8); + BH_VERIFY(BH_IORead(io, &symbol, 1, &size) == BH_OK); + BH_VERIFY(BH_IOTell(io, &offset) == BH_OK); + BH_VERIFY(size == 1); + BH_VERIFY(symbol == 'o'); + BH_VERIFY(offset == 9); + + BH_VERIFY(BH_IOSeek(io, -1, BH_IO_SEEK_CUR) == BH_OK); + BH_VERIFY(BH_IOTell(io, &offset) == BH_OK); + BH_VERIFY(offset == 8); + BH_VERIFY(BH_IORead(io, &symbol, 1, &size) == BH_OK); + BH_VERIFY(BH_IOTell(io, &offset) == BH_OK); + BH_VERIFY(size == 1); + BH_VERIFY(symbol == 'o'); + BH_VERIFY(offset == 9); + + BH_VERIFY(BH_IOSeek(io, -123456, BH_IO_SEEK_CUR) == BH_OK); + BH_VERIFY(BH_IOTell(io, &offset) == BH_OK); + BH_VERIFY(offset == 0); + BH_VERIFY(BH_IORead(io, &symbol, 1, &size) == BH_OK); + BH_VERIFY(BH_IOTell(io, &offset) == BH_OK); + BH_VERIFY(size == 1); + BH_VERIFY(symbol == 'H'); + BH_VERIFY(offset == 1); + + BH_VERIFY(BH_IOSeek(io, 123456, BH_IO_SEEK_CUR) == BH_OK); + BH_VERIFY(BH_IOTell(io, &offset) == BH_OK); + BH_VERIFY(offset == 14); + BH_VERIFY(BH_IORead(io, &symbol, 1, &size) == BH_OK); + BH_VERIFY(BH_IOTell(io, &offset) == BH_OK); + BH_VERIFY(size == 0); + BH_VERIFY(offset == 14); + + BH_VERIFY(BH_IOSeek(io, -1, BH_IO_SEEK_SET) == BH_OK); + BH_VERIFY(BH_IOTell(io, &offset) == BH_OK); + BH_VERIFY(offset == 0); + + BH_VERIFY(BH_IOSeek(io, 123456, BH_IO_SEEK_SET) == BH_OK); + BH_VERIFY(BH_IOTell(io, &offset) == BH_OK); + BH_VERIFY(offset == 14); + + BH_VERIFY(BH_IOSeek(io, 123456, BH_IO_SEEK_END) == BH_OK); + BH_VERIFY(BH_IOTell(io, &offset) == BH_OK); + BH_VERIFY(offset == 14); + + BH_VERIFY(BH_IOSeek(io, -123456, BH_IO_SEEK_END) == BH_OK); + BH_VERIFY(BH_IOTell(io, &offset) == BH_OK); + BH_VERIFY(offset == 0); + + BH_VERIFY(BH_IOSeek(io, -2, BH_IO_SEEK_END) == BH_OK); + BH_VERIFY(BH_IOTell(io, &offset) == BH_OK); + BH_VERIFY(offset == 12); + BH_VERIFY(BH_IORead(io, &symbol, 1, &size) == BH_OK); + BH_VERIFY(size == 1); + BH_VERIFY(symbol == '!'); + + BH_IOFree(io); + + return 0; +} + + +int main(int argc, + char **argv) +{ + BH_UNUSED(argc); + BH_UNUSED(argv); + + BH_UNIT_ADD(Null); + BH_UNIT_ADD(Write); + BH_UNIT_ADD(Read); + BH_UNIT_ADD(SeekTell); + + + return BH_UnitRun(); +} diff --git a/test/src/TestFile.c b/test/src/TestFile.c index 8fae14c..37542bf 100644 --- a/test/src/TestFile.c +++ b/test/src/TestFile.c @@ -26,13 +26,7 @@ static void cleanup(void) */ static int checkNull(void) { - BH_IO *io; - /* Check against NULL pointers */ - BH_VERIFY(BH_FileNew(NULL) == NULL); - BH_VERIFY(BH_IOClassname(NULL) == NULL); - BH_VERIFY(BH_IOOpen(NULL, 0) != BH_OK); - BH_VERIFY(BH_IOClose(NULL) != BH_OK); BH_VERIFY(BH_IORead(NULL, NULL, 0, NULL) != BH_OK); BH_VERIFY(BH_IOWrite(NULL, NULL, 0, NULL) != BH_OK); BH_VERIFY(BH_IOPeek(NULL, NULL, 0, NULL) != BH_OK); @@ -40,26 +34,14 @@ static int checkNull(void) BH_VERIFY(BH_IOSeek(NULL, 0, 0) != BH_OK); BH_VERIFY(BH_IOFlush(NULL) != BH_OK); BH_VERIFY(BH_IOSize(NULL, NULL) != BH_OK); - BH_VERIFY(BH_IOFlags(NULL) == BH_IO_FLAG_ERROR); - BH_VERIFY(BH_IOClear(NULL) == BH_OK); + BH_VERIFY(BH_IOFlags(NULL, NULL) != BH_OK); + BH_VERIFY(BH_IOClear(NULL) != BH_OK); + BH_VERIFY(BH_IOCtl(NULL, 0, NULL) != BH_OK); + BH_VERIFY(BH_IOCap(NULL, 0) != BH_OK); + BH_VERIFY(BH_IOEndOfFile(NULL) != BH_OK); + BH_VERIFY(BH_IOError(NULL) != BH_OK); BH_IOFree(NULL); - /* Check against NULL pointers and valid IO object */ - BH_VERIFY((io = BH_FileNew(FILENAME1)) != NULL); - BH_VERIFY(strcmp(BH_IOClassname(io), BH_FILE_CLASSNAME) == 0); - BH_VERIFY(BH_IOOpen(io, 0) != BH_OK); - BH_VERIFY(BH_IOClose(io) != BH_OK); - BH_VERIFY(BH_IORead(io, NULL, 0, NULL) != BH_OK); - BH_VERIFY(BH_IOWrite(io, NULL, 0, NULL) != BH_OK); - BH_VERIFY(BH_IOPeek(io, NULL, 0, NULL) != BH_OK); - BH_VERIFY(BH_IOTell(io, NULL) != BH_OK); - BH_VERIFY(BH_IOSeek(io, 0, 0) != BH_OK); - BH_VERIFY(BH_IOFlush(io) != BH_OK); - BH_VERIFY(BH_IOSize(io, NULL) != BH_OK); - BH_VERIFY(BH_IOFlags(io) == BH_IO_FLAG_ERROR); - BH_VERIFY(BH_IOClear(io) == BH_OK); - BH_IOFree(io); - return 0; } @@ -75,13 +57,7 @@ static int checkNormal(void) BH_IO *io; /* Check operations for write only access */ - BH_VERIFY((io = BH_FileNew(FILENAME1)) != NULL); - BH_VERIFY(strcmp(BH_IOClassname(io), BH_FILE_CLASSNAME) == 0); - BH_VERIFY(BH_IOOpen(io, BH_IO_WRITE) == BH_OK); - BH_VERIFY(BH_IOFlags(io) & BH_IO_FLAG_OPEN); - - BH_VERIFY(BH_IOOpen(io, BH_IO_READ) != BH_OK); - + BH_VERIFY((io = BH_FileNew(FILENAME1, BH_FILE_WRITE, NULL)) != NULL); BH_VERIFY(BH_IOWrite(io, "1234567890", 10, &actual) == BH_OK); BH_VERIFY(actual == 10); @@ -97,12 +73,10 @@ static int checkNormal(void) BH_VERIFY(BH_IOSeek(io, 0, BH_IO_SEEK_END) == BH_OK); BH_VERIFY(BH_IOTell(io, &position) == BH_OK); BH_VERIFY(position == 20); - BH_IOClose(io); + BH_IOFree(io); /* Check operations for read only access */ - BH_VERIFY(BH_IOOpen(io, BH_IO_READ) == BH_OK); - BH_VERIFY(BH_IOFlags(io) & BH_IO_FLAG_OPEN); - BH_VERIFY(strcmp(BH_IOClassname(io), BH_FILE_CLASSNAME) == 0); + BH_VERIFY((io = BH_FileNew(FILENAME1, BH_FILE_READ, NULL)) != NULL); BH_VERIFY(BH_IORead(io, buffer, 10, &actual) == BH_OK); BH_VERIFY(actual == 10); BH_VERIFY(memcmp(buffer, "1234567890", 10) == 0); @@ -124,10 +98,7 @@ static int checkNormal(void) BH_IOFree(io); /* Check operations for read and write access */ - BH_VERIFY((io = BH_FileNew(FILENAME1)) != NULL); - BH_VERIFY(strcmp(BH_IOClassname(io), BH_FILE_CLASSNAME) == 0); - BH_VERIFY(BH_IOOpen(io, BH_IO_WRITE | BH_IO_READ) == BH_OK); - BH_VERIFY(BH_IOFlags(io) & BH_IO_FLAG_OPEN); + BH_VERIFY((io = BH_FileNew(FILENAME1, BH_FILE_READWRITE, NULL)) != NULL); BH_VERIFY(BH_IOWrite(io, "abcde", 5, &actual) == BH_OK); BH_VERIFY(actual == 5); @@ -151,8 +122,6 @@ static int checkNormal(void) BH_VERIFY(BH_IORead(io, buffer, 35, &actual) == BH_OK); BH_VERIFY(actual == 35); BH_VERIFY(memcmp(buffer, "abcde12345678901234567890abcde67890", 35) == 0); - BH_IOClose(io); - BH_IOFree(io); return 0; } @@ -169,11 +138,7 @@ static int checkTruncate(void) BH_IO *io; /* Check operations for write only access */ - BH_VERIFY((io = BH_FileNew(FILENAME1)) != NULL); - BH_VERIFY(strcmp(BH_IOClassname(io), BH_FILE_CLASSNAME) == 0); - BH_VERIFY(BH_IOOpen(io, BH_IO_WRITE | BH_IO_TRUNCATE) == BH_OK); - BH_VERIFY(BH_IOFlags(io) & BH_IO_FLAG_OPEN); - + BH_VERIFY((io = BH_FileNew(FILENAME1, BH_FILE_WRITE | BH_FILE_TRUNCATE, NULL)) != NULL); BH_VERIFY(BH_IOWrite(io, "1234567890", 10, &actual) == BH_OK); BH_VERIFY(actual == 10); @@ -189,11 +154,10 @@ static int checkTruncate(void) BH_VERIFY(BH_IOSeek(io, 0, BH_IO_SEEK_END) == BH_OK); BH_VERIFY(BH_IOTell(io, &position) == BH_OK); BH_VERIFY(position == 20); - BH_IOClose(io); + BH_IOFree(io); /* Check operations for read only access without truncate */ - BH_VERIFY(BH_IOOpen(io, BH_IO_READ) == BH_OK); - BH_VERIFY(BH_IOFlags(io) & BH_IO_FLAG_OPEN); + BH_VERIFY((io = BH_FileNew(FILENAME1, BH_FILE_READ, NULL)) != NULL); BH_VERIFY(BH_IORead(io, buffer, 10, &actual) == BH_OK); BH_VERIFY(actual == 10); BH_VERIFY(memcmp(buffer, "1234567890", 10) == 0); @@ -211,11 +175,10 @@ static int checkTruncate(void) BH_VERIFY(BH_IORead(io, buffer, 5, &actual) == BH_OK); BH_VERIFY(actual == 5); BH_VERIFY(memcmp(buffer, "67890", 5) == 0); - BH_IOClose(io); + BH_IOFree(io); /* Check operations for read only access */ - BH_VERIFY(BH_IOOpen(io, BH_IO_READ | BH_IO_TRUNCATE) == BH_OK); - BH_VERIFY(BH_IOFlags(io) & BH_IO_FLAG_OPEN); + BH_VERIFY((io = BH_FileNew(FILENAME1, BH_FILE_READ | BH_FILE_TRUNCATE, NULL)) != NULL); BH_VERIFY(BH_IORead(io, buffer, 10, &actual) == BH_OK); BH_VERIFY(actual == 0); @@ -229,11 +192,7 @@ static int checkTruncate(void) BH_IOFree(io); /* Check operations for read and write access */ - BH_VERIFY((io = BH_FileNew(FILENAME1)) != NULL); - BH_VERIFY(strcmp(BH_IOClassname(io), BH_FILE_CLASSNAME) == 0); - BH_VERIFY(BH_IOOpen(io, BH_IO_WRITE | BH_IO_READ | BH_IO_TRUNCATE) == BH_OK); - BH_VERIFY(BH_IOFlags(io) & BH_IO_FLAG_OPEN); - + BH_VERIFY((io = BH_FileNew(FILENAME1, BH_FILE_READWRITE | BH_FILE_TRUNCATE, NULL)) != NULL); BH_VERIFY(BH_IOWrite(io, "abcde", 5, &actual) == BH_OK); BH_VERIFY(actual == 5); @@ -256,13 +215,11 @@ static int checkTruncate(void) BH_VERIFY(BH_IORead(io, buffer, 35, &actual) == BH_OK); BH_VERIFY(actual == 35); BH_VERIFY(memcmp(buffer, "abcde12345678901234567890abcde67890", 35) == 0); - BH_IOClose(io); - - BH_VERIFY(BH_IOOpen(io, BH_IO_WRITE | BH_IO_TRUNCATE) == BH_OK); - BH_VERIFY(BH_IOFlags(io) & BH_IO_FLAG_OPEN); - BH_IOClose(io); + BH_IOFree(io); + BH_VERIFY((io = BH_FileNew(FILENAME1, BH_FILE_WRITE | BH_FILE_TRUNCATE, NULL)) != NULL); BH_IOFree(io); + return 0; } @@ -278,10 +235,7 @@ static int checkExist(void) BH_IO *io; /* Check operations for write only access */ - BH_VERIFY((io = BH_FileNew(FILENAME1)) != NULL); - BH_VERIFY(strcmp(BH_IOClassname(io), BH_FILE_CLASSNAME) == 0); - BH_VERIFY(BH_IOOpen(io, BH_IO_WRITE | BH_IO_EXIST) == BH_OK); - BH_VERIFY(BH_IOFlags(io) & BH_IO_FLAG_OPEN); + BH_VERIFY((io = BH_FileNew(FILENAME1, BH_FILE_WRITE | BH_FILE_EXIST, NULL)) != NULL); BH_VERIFY(BH_IOWrite(io, "1234567890", 10, &actual) == BH_OK); BH_VERIFY(actual == 10); @@ -298,11 +252,11 @@ static int checkExist(void) BH_VERIFY(BH_IOSeek(io, 0, BH_IO_SEEK_END) == BH_OK); BH_VERIFY(BH_IOTell(io, &position) == BH_OK); BH_VERIFY(position == 20); - BH_IOClose(io); + BH_IOFree(io); /* Check operations for read only access */ - BH_VERIFY(BH_IOOpen(io, BH_IO_READ | BH_IO_EXIST) == BH_OK); - BH_VERIFY(BH_IOFlags(io) & BH_IO_FLAG_OPEN); + BH_VERIFY((io = BH_FileNew(FILENAME1, BH_FILE_READ | BH_FILE_EXIST, NULL)) != NULL); + BH_VERIFY(BH_IORead(io, buffer, 10, &actual) == BH_OK); BH_VERIFY(actual == 10); BH_VERIFY(memcmp(buffer, "1234567890", 10) == 0); @@ -324,10 +278,7 @@ static int checkExist(void) BH_IOFree(io); /* Check operations for read and write access */ - BH_VERIFY((io = BH_FileNew(FILENAME1)) != NULL); - BH_VERIFY(strcmp(BH_IOClassname(io), BH_FILE_CLASSNAME) == 0); - BH_VERIFY(BH_IOOpen(io, BH_IO_WRITE | BH_IO_READ | BH_IO_EXIST) == BH_OK); - BH_VERIFY(BH_IOFlags(io) & BH_IO_FLAG_OPEN); + BH_VERIFY((io = BH_FileNew(FILENAME1, BH_FILE_WRITE | BH_FILE_READ | BH_FILE_EXIST, NULL)) != NULL); BH_VERIFY(BH_IOWrite(io, "abcde", 5, &actual) == BH_OK); BH_VERIFY(actual == 5); @@ -351,19 +302,12 @@ static int checkExist(void) BH_VERIFY(BH_IORead(io, buffer, 35, &actual) == BH_OK); BH_VERIFY(actual == 35); BH_VERIFY(memcmp(buffer, "abcde12345678901234567890abcde67890", 35) == 0); - BH_IOClose(io); BH_IOFree(io); /* Check against non existing files */ - BH_VERIFY((io = BH_FileNew(FILENAME2)) != NULL); - BH_VERIFY(strcmp(BH_IOClassname(io), BH_FILE_CLASSNAME) == 0); - BH_VERIFY(BH_IOOpen(io, BH_IO_WRITE | BH_IO_EXIST) != BH_OK); - BH_VERIFY((BH_IOFlags(io) & BH_IO_FLAG_OPEN) == 0); - BH_VERIFY(BH_IOOpen(io, BH_IO_READ | BH_IO_EXIST) != BH_OK); - BH_VERIFY((BH_IOFlags(io) & BH_IO_FLAG_OPEN) == 0); - BH_VERIFY(BH_IOOpen(io, BH_IO_WRITE | BH_IO_READ | BH_IO_EXIST) != BH_OK); - BH_VERIFY((BH_IOFlags(io) & BH_IO_FLAG_OPEN) == 0); - BH_IOFree(io); + BH_VERIFY(BH_FileNew(FILENAME2, BH_FILE_WRITE | BH_FILE_EXIST, NULL) == NULL); + BH_VERIFY(BH_FileNew(FILENAME2, BH_FILE_READ | BH_FILE_EXIST, NULL) == NULL); + BH_VERIFY(BH_FileNew(FILENAME2, BH_FILE_READWRITE | BH_FILE_EXIST, NULL) == NULL); return 0; } @@ -382,10 +326,7 @@ static int checkAppend(void) cleanup(); /* Check operations for write only access */ - BH_VERIFY((io = BH_FileNew(FILENAME1)) != NULL); - BH_VERIFY(strcmp(BH_IOClassname(io), BH_FILE_CLASSNAME) == 0); - BH_VERIFY(BH_IOOpen(io, BH_IO_WRITE | BH_IO_APPEND) == BH_OK); - BH_VERIFY(BH_IOFlags(io) & BH_IO_FLAG_OPEN); + BH_VERIFY((io = BH_FileNew(FILENAME1, BH_FILE_WRITE | BH_FILE_APPEND, NULL)) != NULL); BH_VERIFY(BH_IOWrite(io, "1234567890", 10, &actual) == BH_OK); BH_VERIFY(actual == 10); @@ -402,12 +343,11 @@ static int checkAppend(void) BH_VERIFY(BH_IOSeek(io, 0, BH_IO_SEEK_END) == BH_OK); BH_VERIFY(BH_IOTell(io, &position) == BH_OK); BH_VERIFY(position == 25); - BH_IOClose(io); + BH_IOFree(io); /* Check operations for read only access */ - BH_VERIFY(BH_IOOpen(io, BH_IO_READ | BH_IO_APPEND) == BH_OK); - BH_VERIFY(BH_IOFlags(io) & BH_IO_FLAG_OPEN); - BH_VERIFY(strcmp(BH_IOClassname(io), BH_FILE_CLASSNAME) == 0); + BH_VERIFY((io = BH_FileNew(FILENAME1, BH_FILE_READ | BH_FILE_APPEND, NULL)) != NULL); + BH_VERIFY(BH_IORead(io, buffer, 10, &actual) == BH_OK); BH_VERIFY(actual == 10); BH_VERIFY(memcmp(buffer, "1234567890", 10) == 0); @@ -425,11 +365,10 @@ static int checkAppend(void) BH_VERIFY(BH_IORead(io, buffer, 5, &actual) == BH_OK); BH_VERIFY(actual == 5); BH_VERIFY(memcmp(buffer, "abcde", 5) == 0); - BH_IOClose(io); + BH_IOFree(io); /* Check operations for read and write access */ - BH_VERIFY(BH_IOOpen(io, BH_IO_WRITE | BH_IO_READ | BH_IO_APPEND) == BH_OK); - BH_VERIFY(BH_IOFlags(io) & BH_IO_FLAG_OPEN); + BH_VERIFY((io = BH_FileNew(FILENAME1, BH_FILE_READWRITE | BH_FILE_APPEND, NULL)) != NULL); BH_VERIFY(BH_IOWrite(io, "abcde", 5, &actual) == BH_OK); BH_VERIFY(actual == 5); @@ -441,13 +380,12 @@ static int checkAppend(void) BH_VERIFY(BH_IORead(io, buffer, 40, &actual) == BH_OK); BH_VERIFY(actual == 40); BH_VERIFY(memcmp(buffer, "12345678901234567890abcdeabcde1234567890", 40) == 0); - BH_IOClose(io); + BH_IOFree(io); - BH_VERIFY(BH_IOOpen(io, BH_IO_WRITE | BH_IO_TRUNCATE) == BH_OK); - BH_VERIFY(BH_IOFlags(io) & BH_IO_FLAG_OPEN); - BH_IOClose(io); + BH_VERIFY((io = BH_FileNew(FILENAME1, BH_FILE_WRITE | BH_FILE_TRUNCATE, NULL)) != NULL); BH_IOFree(io); + return 0; } @@ -460,31 +398,18 @@ static int checkCreate(void) BH_IO *io; /* Check for already existing file */ - BH_VERIFY((io = BH_FileNew(FILENAME1)) != NULL); - BH_VERIFY(strcmp(BH_IOClassname(io), BH_FILE_CLASSNAME) == 0); - BH_VERIFY(BH_IOOpen(io, BH_IO_WRITE | BH_IO_CREATE) != BH_OK); - BH_VERIFY((BH_IOFlags(io) & BH_IO_FLAG_OPEN) == 0); - BH_IOFree(io); + BH_VERIFY(BH_FileNew(FILENAME1, BH_FILE_WRITE | BH_FILE_CREATE, NULL) == NULL); /* Check for new file with write access */ - BH_VERIFY((io = BH_FileNew(FILENAME2)) != NULL); - BH_VERIFY(strcmp(BH_IOClassname(io), BH_FILE_CLASSNAME) == 0); - BH_VERIFY(BH_IOOpen(io, BH_IO_WRITE | BH_IO_CREATE) == BH_OK); - BH_VERIFY(BH_IOFlags(io) & BH_IO_FLAG_OPEN); + BH_VERIFY((io = BH_FileNew(FILENAME2, BH_FILE_WRITE | BH_FILE_CREATE, NULL)) != NULL); BH_IOFree(io); /* Check for new file with read access */ - BH_VERIFY((io = BH_FileNew(FILENAME3)) != NULL); - BH_VERIFY(strcmp(BH_IOClassname(io), BH_FILE_CLASSNAME) == 0); - BH_VERIFY(BH_IOOpen(io, BH_IO_READ | BH_IO_CREATE) == BH_OK); - BH_VERIFY(BH_IOFlags(io) & BH_IO_FLAG_OPEN); + BH_VERIFY((io = BH_FileNew(FILENAME3, BH_FILE_READ | BH_FILE_CREATE, NULL)) != NULL); BH_IOFree(io); /* Check for new file with read/write access */ - BH_VERIFY((io = BH_FileNew(FILENAME4)) != NULL); - BH_VERIFY(strcmp(BH_IOClassname(io), BH_FILE_CLASSNAME) == 0); - BH_VERIFY(BH_IOOpen(io, BH_IO_WRITE | BH_IO_READ | BH_IO_CREATE) == BH_OK); - BH_VERIFY(BH_IOFlags(io) & BH_IO_FLAG_OPEN); + BH_VERIFY((io = BH_FileNew(FILENAME4, BH_FILE_READWRITE | BH_FILE_CREATE, NULL)) != NULL); BH_IOFree(io); return 0; @@ -500,16 +425,12 @@ static int checkEOF(void) size_t actual; BH_IO *io; - BH_VERIFY((io = BH_FileNew(FILENAME1)) != NULL); - BH_VERIFY(strcmp(BH_IOClassname(io), BH_FILE_CLASSNAME) == 0); - BH_VERIFY(BH_IOOpen(io, BH_IO_READ | BH_IO_TRUNCATE) == BH_OK); - BH_VERIFY(BH_IOFlags(io) & BH_IO_FLAG_OPEN); + BH_VERIFY((io = BH_FileNew(FILENAME1, BH_FILE_READ | BH_FILE_TRUNCATE, NULL)) != NULL); BH_VERIFY(BH_IORead(io, buffer, 128, &actual) == BH_OK); BH_VERIFY(actual == 0); - BH_VERIFY(BH_IOFlags(io) & BH_IO_FLAG_EOF); + BH_VERIFY(BH_IOEndOfFile(io)); - BH_IOClose(io); BH_IOFree(io); return 0; @@ -524,17 +445,13 @@ static int checkError(void) size_t actual; BH_IO *io; - BH_VERIFY((io = BH_FileNew(FILENAME1)) != NULL); - BH_VERIFY(strcmp(BH_IOClassname(io), BH_FILE_CLASSNAME) == 0); - BH_VERIFY(BH_IOOpen(io, BH_IO_READ) == BH_OK); - BH_VERIFY(BH_IOFlags(io) & BH_IO_FLAG_OPEN); + BH_VERIFY((io = BH_FileNew(FILENAME1, BH_FILE_READ, NULL)) != NULL); BH_VERIFY(BH_IOWrite(io, "12345", 5, &actual) != BH_OK); - BH_VERIFY(BH_IOFlags(io) & BH_IO_FLAG_ERROR); + BH_VERIFY(BH_IOError(io) != BH_OK); BH_VERIFY(BH_IOClear(io) == BH_OK); - BH_VERIFY((BH_IOFlags(io) & BH_IO_FLAG_ERROR) == 0); + BH_VERIFY(BH_IOError(io) == BH_OK); - BH_IOClose(io); BH_IOFree(io); return 0; @@ -551,10 +468,7 @@ static int checkPeek(void) size_t actual; BH_IO *io; - BH_VERIFY((io = BH_FileNew(FILENAME1)) != NULL); - BH_VERIFY(strcmp(BH_IOClassname(io), BH_FILE_CLASSNAME) == 0); - BH_VERIFY(BH_IOOpen(io, BH_IO_WRITE | BH_IO_READ | BH_IO_TRUNCATE) == BH_OK); - BH_VERIFY(BH_IOFlags(io) & BH_IO_FLAG_OPEN); + BH_VERIFY((io = BH_FileNew(FILENAME1, BH_FILE_READWRITE | BH_FILE_TRUNCATE, NULL)) != NULL); BH_VERIFY(BH_IOWrite(io, "1234567890", 10, &actual) == BH_OK); BH_VERIFY(actual == 10); @@ -578,7 +492,6 @@ static int checkPeek(void) BH_VERIFY(memcmp(buffer, "12345678901234567890", 20) == 0); BH_VERIFY(previous == current); - BH_IOClose(io); BH_IOFree(io); return 0; @@ -593,14 +506,11 @@ static int checkSize(void) BH_IO *io; int64_t size; - BH_VERIFY((io = BH_FileNew(FILENAME1)) != NULL); - BH_VERIFY(strcmp(BH_IOClassname(io), BH_FILE_CLASSNAME) == 0); - BH_VERIFY(BH_IOOpen(io, BH_IO_READ) == BH_OK); + BH_VERIFY((io = BH_FileNew(FILENAME1, BH_FILE_READ, NULL)) != NULL); BH_VERIFY(BH_IOSize(io, &size) == BH_OK); BH_VERIFY(size == 20); - BH_IOClose(io); BH_IOFree(io); return 0; } |
