Refactor IO, add buffered IO

I wasn't happy with existing implementation of the IO, so I decided
to change it - as a result there is no longer BH_IOOpen and BH_IOClose
and many IO operations are now optional (behind BH_IOCtl).

Finnally implemented buffered IO and fixed size memory buffer IO.
This commit is contained in:
2025-04-26 07:50:13 +03:00
parent 48ddd91dd4
commit 1b6c858a1b
16 changed files with 1473 additions and 1122 deletions

View File

@@ -80,6 +80,8 @@ endif()
set(BH_SOURCE set(BH_SOURCE
src/Algo.c src/Algo.c
src/Args.c src/Args.c
src/Buffer.c
src/Bytes.c
src/Hashmap.c src/Hashmap.c
src/IO.c src/IO.c
src/Math/Box2f.c src/Math/Box2f.c

View File

@@ -165,9 +165,8 @@ static int ProcessPack(Config *config,
if (strcmp(entry.name, config->input)) if (strcmp(entry.name, config->input))
continue; continue;
output = BH_FileNew(config->output); output = BH_FileNew(config->output, BH_FILE_WRITE | BH_FILE_TRUNCATE, NULL);
if (BH_IOOpen(output, BH_IO_WRITE) || if (!output || BH_IOSeek(io, entry.offset, BH_IO_SEEK_SET) ||
BH_IOSeek(io, entry.offset, BH_IO_SEEK_SET) ||
CopyData(io, output, entry.size)) CopyData(io, output, entry.size))
{ {
BH_IOFree(output); BH_IOFree(output);
@@ -209,8 +208,7 @@ int main(int argc, char **argv)
} }
/* Read and write */ /* Read and write */
io = BH_FileNew(config.file); if ((io = BH_FileNew(config.file, BH_FILE_READ | BH_FILE_EXIST, NULL)) == NULL)
if (BH_IOOpen(io, BH_IO_READ | BH_IO_EXIST))
{ {
printf("Can't open file %s\n", config.file); printf("Can't open file %s\n", config.file);
BH_IOFree(io); BH_IOFree(io);

View File

@@ -21,23 +21,25 @@ int main(int argc, char **argv)
if (argc < 2) if (argc < 2)
printUsage(); printUsage();
inFile = BH_FileNew(argv[1]); inFile = BH_FileNew(argv[1], BH_FILE_READ | BH_FILE_EXIST, NULL);
outFile = BH_FileNew(argv[2]); outFile = BH_FileNew(argv[2], BH_FILE_WRITE | BH_FILE_TRUNCATE, NULL);
if (!inFile || BH_IOOpen(inFile, BH_IO_READ | BH_IO_EXIST)) if (!inFile || !outFile)
return -1;
if (!outFile || BH_IOOpen(outFile, BH_IO_WRITE | BH_IO_TRUNCATE))
return -1; return -1;
inSize = 0; inSize = 0;
while (!(BH_IOFlags(inFile) & BH_IO_FLAG_EOF)) while (1)
{ {
/* Read one byte and try to decode */ /* Read one byte and try to decode */
if (!inSize || !(outSize = BH_UnicodeDecodeUtf8(inBuffer, inSize, &unit))) if (!inSize || !(outSize = BH_UnicodeDecodeUtf8(inBuffer, inSize, &unit)))
{ {
BH_IOPeek(inFile, inBuffer + inSize, 1, &outSize);
BH_IORead(inFile, inBuffer + inSize, 1, &outSize); BH_IORead(inFile, inBuffer + inSize, 1, &outSize);
inSize += outSize; inSize += outSize;
if (!outSize)
break;
continue; continue;
} }

View File

@@ -61,22 +61,20 @@ To implement this utility, we are going to need to include the following headers
## Working with Files ## Working with Files
Working with files in BHLib is based around the IO device (called `BH_IO`). 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. Firstly, you need to create an IO file device with the `BH_FileNew` function.
Secondly, you need to open the IO device with the `BH_IOOpen` function. While While doing so, you can specify in which mode it will work: reading
opening the IO device, you can specify in which mode it will work: reading (`BH_FILE_READ`) or writing (`BH_FILE_WRITE`). Additionally, we can specify
(`BH_IO_READ`) or writing (`BH_IO_WRITE`). Additionally, we can specify whether whether the file should exist before opening (`BH_IO_EXIST`), be truncated
the IO device (or in our case, the file) should exist before opening before opening (`BH_IO_TRUNCATE`), should it be created (`BH_IO_CREATE`), or
(`BH_IO_EXIST`), be truncated before opening (`BH_IO_TRUNCATE`), should it be opened in append mode (`BH_IO_APPEND`).
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: Here is an example for opening an existing file in read-only mode:
```c ```c
BH_IO *io = BH_FileNew("coolfile.dat"); BH_IO *io = BH_FileNew("coolfile.dat", BH_FILE_READ | BH_FILE_EXISTS, NULL);
if (BH_IOOpen(io, BH_IO_READ | BH_IO_EXIST)) if (!io)
{ {
printf("Can't open file 'coolfile.dat'\n", config.file); printf("Can't open file 'coolfile.dat'\n", config.file);
BH_IOFree(io);
return -1; return -1;
} }
``` ```
@@ -207,6 +205,7 @@ Now, let's put everything together and implement `PakReader`.
#define HEADER_SIZE 12 #define HEADER_SIZE 12
#define ENTRY_SIZE 64 #define ENTRY_SIZE 64
typedef struct PakHeader typedef struct PakHeader
{ {
char id[4]; char id[4];
@@ -361,9 +360,8 @@ static int ProcessPack(Config *config,
if (strcmp(entry.name, config->input)) if (strcmp(entry.name, config->input))
continue; continue;
output = BH_FileNew(config->output); output = BH_FileNew(config->output, BH_FILE_WRITE | BH_FILE_TRUNCATE, NULL);
if (BH_IOOpen(output, BH_IO_WRITE) || if (!output || BH_IOSeek(io, entry.offset, BH_IO_SEEK_SET) ||
BH_IOSeek(io, entry.offset, BH_IO_SEEK_SET) ||
CopyData(io, output, entry.size)) CopyData(io, output, entry.size))
{ {
BH_IOFree(output); BH_IOFree(output);
@@ -405,8 +403,7 @@ int main(int argc, char **argv)
} }
/* Read and write */ /* Read and write */
io = BH_FileNew(config.file); if ((io = BH_FileNew(config.file, BH_FILE_READ | BH_FILE_EXIST, NULL)) == NULL)
if (BH_IOOpen(io, BH_IO_READ | BH_IO_EXIST))
{ {
printf("Can't open file %s\n", config.file); printf("Can't open file %s\n", config.file);
BH_IOFree(io); BH_IOFree(io);

View File

@@ -21,37 +21,40 @@ To implement this utility, we are going to need to include the following headers
## Working with Files ## Working with Files
Working with files in BHLib is based around the IO device (called `BH_IO`). 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. Firstly, you need to create an IO file device with the `BH_FileNew` function.
Secondly, you need to open the IO device with the `BH_IOOpen` function. While While doing so, you can specify in which mode it will work: reading
opening the IO device, you can specify in which mode it will work: reading (`BH_FILE_READ`) or writing (`BH_FILE_WRITE`). Additionally, we can specify
(`BH_IO_READ`) or writing (`BH_IO_WRITE`). Additionally, we can specify whether whether the file should exist before opening (`BH_IO_EXIST`), be truncated
the IO device (or in our case, the file) should exist before opening before opening (`BH_IO_TRUNCATE`), should it be created (`BH_IO_CREATE`), or
(`BH_IO_EXIST`), be truncated before opening (`BH_IO_TRUNCATE`), should it be opened in append mode (`BH_IO_APPEND`).
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: Here is an example for opening an existing file in read-only mode:
```c ```c
BH_IO *io = BH_FileNew("coolfile.dat"); BH_IO *io = BH_FileNew("coolfile.dat", BH_FILE_READ | BH_FILE_EXISTS, NULL);
if (BH_IOOpen(io, BH_IO_READ | BH_IO_EXIST)) if (!io)
{ {
printf("Can't open file 'coolfile.dat'\n", config.file); printf("Can't open file 'coolfile.dat'\n", config.file);
BH_IOFree(io);
return -1; return -1;
} }
``` ```
## Working with UTF-8 ## Working with UTF-8
Reading UTF-8/UTF-16/UTF-32 is based around simple loop: Reading UTF-8/UTF-16/UTF-32 is based around simple loop:
1. Read bytes from input (IO or memory) to some buffer. 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. 2. Call `BH_UnicodeDecodeUtf*`. If return value is 0 - we don't have enough
3. If readed codepoint equals -1 - we encountered an error, so replace it with the code 0xFFFD. 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: 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). 2. Write data (to IO or memory).
BH_UnicodeDecodeUtf8(inBuffer, inSize, &unit) BH_UnicodeDecodeUtf8(inBuffer, inSize, &unit)
@@ -107,23 +110,25 @@ int main(int argc, char **argv)
if (argc < 2) if (argc < 2)
printUsage(); printUsage();
inFile = BH_FileNew(argv[1]); inFile = BH_FileNew(argv[1], BH_FILE_READ | BH_FILE_EXIST, NULL);
outFile = BH_FileNew(argv[2]); outFile = BH_FileNew(argv[2], BH_FILE_WRITE | BH_FILE_TRUNCATE, NULL);
if (!inFile || BH_IOOpen(inFile, BH_IO_READ | BH_IO_EXIST)) if (!inFile || !outFile)
return -1;
if (!outFile || BH_IOOpen(outFile, BH_IO_WRITE | BH_IO_TRUNCATE))
return -1; return -1;
inSize = 0; inSize = 0;
while (!(BH_IOFlags(inFile) & BH_IO_FLAG_EOF)) while (1)
{ {
/* Read one byte and try to decode */ /* Read one byte and try to decode */
if (!inSize || !(outSize = BH_UnicodeDecodeUtf8(inBuffer, inSize, &unit))) if (!inSize || !(outSize = BH_UnicodeDecodeUtf8(inBuffer, inSize, &unit)))
{ {
BH_IOPeek(inFile, inBuffer + inSize, 1, &outSize);
BH_IORead(inFile, inBuffer + inSize, 1, &outSize); BH_IORead(inFile, inBuffer + inSize, 1, &outSize);
inSize += outSize; inSize += outSize;
if (!outSize)
break;
continue; continue;
} }

View File

@@ -12,6 +12,9 @@
#define BH_FOUND 0x0005 #define BH_FOUND 0x0005
#define BH_NOTFOUND 0x0006 #define BH_NOTFOUND 0x0006
#define BH_TIMEOUT 0x0007 #define BH_TIMEOUT 0x0007
#define BH_SHORT 0x0008
#define BH_FULL 0x0009
#define BH_UNUSED(x) (void)(x) #define BH_UNUSED(x) (void)(x)
#define BH_PTR2INT(x) ((intptr_t)(x)) #define BH_PTR2INT(x) ((intptr_t)(x))

View File

@@ -5,130 +5,139 @@
#include "Common.h" #include "Common.h"
#define BH_IO_INFO_CB 0x0000 #define BH_IO_OP_DESTROY 0x0000
#define BH_IO_INIT_CB 0x0001 #define BH_IO_OP_READ 0x0001
#define BH_IO_DESTROY_CB 0x0002 #define BH_IO_OP_WRITE 0x0002
#define BH_IO_OPEN_CB 0x0003 #define BH_IO_OP_CTL 0x0003
#define BH_IO_CLOSE_CB 0x0004 #define BH_IO_OP_CAP 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_READ 0x0001 #define BH_IO_CTL_FLAGS 0x0000
#define BH_IO_WRITE 0x0002 #define BH_IO_CTL_CLEAR 0x0001
#define BH_IO_READWRITE 0x0003 #define BH_IO_CTL_PEEK 0x0002
#define BH_IO_APPEND 0x0010 #define BH_IO_CTL_FLUSH 0x0003
#define BH_IO_TRUNCATE 0x0020 #define BH_IO_CTL_SIZE 0x0004
#define BH_IO_CREATE 0x0040 #define BH_IO_CTL_TELL 0x0005
#define BH_IO_EXIST 0x0080 #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_SET 0x0000
#define BH_IO_SEEK_CUR 0x0001 #define BH_IO_SEEK_CUR 0x0001
#define BH_IO_SEEK_END 0x0002 #define BH_IO_SEEK_END 0x0002
#define BH_IO_FLAG_OK 0x0000 #define BH_IO_FLAG_OK 0x0000
#define BH_IO_FLAG_ERROR 0x0001 #define BH_IO_FLAG_ERROR 0x0001
#define BH_IO_FLAG_EOF 0x0002 #define BH_IO_FLAG_EOF 0x0002
#define BH_IO_FLAG_OPEN 0x0004
#define BH_FILE_CLASSNAME "BH_File"
typedef struct BH_IO BH_IO; #define BH_FILE_READ 0x0001
typedef int (*BH_IOCallback)(void *, int ,void *, void *); #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 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. * \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. * \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 Buffer pointer
* \param data Initialization data * \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. * \return On failure, returns NULL pointer.
*/ */
BH_IO *BH_IONew(BH_IOCallback cb, BH_IO *BH_BytesNew(char *data,
void *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
*
* \return On success, returns pointer to constant string.
* \return On failure, returns NULL pointer
*/
const char *BH_IOClassname(BH_IO* io);
/**
* Opens the \a io in specified \a mode of operation.
*
* \param io IO pointer
* \param mode Mode of operation
*
* \return On success, returns zero.
* \return On failure, returns error code.
*/
int BH_IOOpen(BH_IO *io,
int mode);
/**
* Closes the \a io.
*
* \param io IO pointer
*
* \return On success, returns zero.
* \return On failure, returns error code.
*/
int BH_IOClose(BH_IO *io);
/**
* Reads up to \a size bytes from the \a io into \a buffer.
*
* \param io IO pointer
* \param buffer Buffer pointer * \param buffer Buffer pointer
* \param size Buffer size * \param size Buffer size
* \param actual Bytes read (optional) * \param actual Bytes read (optional)
@@ -136,16 +145,16 @@ int BH_IOClose(BH_IO *io);
* \return On success, returns zero. * \return On success, returns zero.
* \return On failure, returns error code. * \return On failure, returns error code.
*/ */
int BH_IORead(BH_IO *io, int BH_IORead(BH_IO *device,
char *buffer, char *buffer,
size_t size, size_t size,
size_t *actual); size_t *actual);
/** /**
* Writes up to \a size bytes to the \a io from \a buffer. * Writes up to \a size bytes to the \a device from \a buffer.
* *
* \param io IO pointer * \param io IO device pointer
* \param buffer Buffer pointer * \param buffer Buffer pointer
* \param size Buffer size * \param size Buffer size
* \param actual Bytes written (optional) * \param actual Bytes written (optional)
@@ -160,9 +169,37 @@ int BH_IOWrite(BH_IO *io,
/** /**
* Peeks up to \a size bytes from \a io into \a buffer. * 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_IOCtl(BH_IO *device,
int op,
void *arg);
/**
* Checks if an input/output \a device supports specific \a op.
*
* \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 buffer Buffer pointer
* \param size Buffer size * \param size Buffer size
* \param actial Bytes peeked (optional) * \param actial Bytes peeked (optional)
@@ -170,83 +207,106 @@ int BH_IOWrite(BH_IO *io,
* \return On success, returns zero. * \return On success, returns zero.
* \return On failure, returns error code. * \return On failure, returns error code.
*/ */
int BH_IOPeek(BH_IO *io, int BH_IOPeek(BH_IO *device,
char *buffer, char *buffer,
size_t size, size_t size,
size_t *actual); size_t *actual);
/** /**
* Tells current \a position in the \a io. * Tells current \a offset in the \a device.
* *
* \param io IO pointer * \param device IO device pointer
* \param position Position * \param offset Position
* *
* \return On success, returns zero. * \return On success, returns zero.
* \return On failure, returns error code. * \return On failure, returns error code.
*/ */
int BH_IOTell(BH_IO *io, int BH_IOTell(BH_IO *device,
int64_t *position); int64_t *offset);
/** /**
* Seeks to specified \a position and \a direction in the \a io. * Seeks to specified \a offset and \a whence in the \a device.
* *
* \param io IO pointer * \param device IO device pointer
* \param position Position * \param offset Position
* \param direction Direction * \param whence Direction
* *
* \return On success, returns zero. * \return On success, returns zero.
* \return On failure, returns error code. * \return On failure, returns error code.
*/ */
int BH_IOSeek(BH_IO *io, int BH_IOSeek(BH_IO *device,
int64_t position, int64_t offset,
int direction); int whence);
/** /**
* Flushes the internal buffers of the \a io. * Flushes the internal buffers of the \a device.
* *
* \param io IO pointer * \param device IO device pointer
* *
* \return On success, returns zero. * \return On success, returns zero.
* \return On failure, returns error code. * \return On failure, returns error code.
*/ */
int BH_IOFlush(BH_IO *io); int BH_IOFlush(BH_IO *device);
/** /**
* Returns total or available size of the \a io. * Returns total or available size of the \a device.
* *
* \param io IO pointer * \param device IO pointer
* \param size Available/total size * \param size Available/total size
* *
* \return On success, returns zero. * \return On success, returns zero.
* \return On failure, returns error code. * \return On failure, returns error code.
*/ */
int BH_IOSize(BH_IO *io, int BH_IOSize(BH_IO *device,
int64_t *size); int64_t *size);
/** /**
* Returns flags of the \a io. * Returns flags of the \a device.
* *
* \param io IO pointer * \param device IO device pointer
* * \param flags Flags
* \return Flags of the IO
*/
int BH_IOFlags(BH_IO *io);
/**
* Clears errors of the \a io.
*
* \param io IO pointer
* *
* \return On success, returns zero. * \return On success, returns zero.
* \return On failure, returns error code. * \return On failure, returns error code.
*/ */
int BH_IOClear(BH_IO *io); int BH_IOFlags(BH_IO *device,
int *flags);
/**
* Returns error flag of the \a device.
*
* \param device IO device pointer
*
* \return Returns error flag.
*/
int BH_IOError(BH_IO *device);
/**
* Returns end-of-file flag of the \a device.
*
* \param device IO device pointer
*
* \return Returns end-of-file flag.
*/
int BH_IOEndOfFile(BH_IO *device);
/**
* Clears errors of the \a device.
*
* \param device IO device pointer
*
* \return On success, returns zero.
* \return On failure, returns error code.
*/
int BH_IOClear(BH_IO *device);
#endif /* BH_IO_H */ #endif /* BH_IO_H */

304
src/Buffer.c Normal file
View File

@@ -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;
}

217
src/Bytes.c Normal file
View File

@@ -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;
}

273
src/IO.c
View File

@@ -5,231 +5,176 @@
#define BUFFER_SIZE (sizeof(char *)) #define BUFFER_SIZE (sizeof(char *))
struct BH_IO void BH_IOFree(BH_IO *device)
{
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)
{ {
/* Prevent working with NULL io */ /* Prevent working with NULL io */
if (!io) if (!device)
return; return;
/* Call the IO device destruction handler */ /* Call the IO device destruction handler and deallocate */
io->cb(io + 1, BH_IO_DESTROY_CB, NULL, NULL); device->callback(device, BH_IO_OP_DESTROY, NULL);
/* Deallocate object */
free(io);
} }
const char *BH_IOClassname(BH_IO *io) int BH_IORead(BH_IO *device,
{
const char *name;
if (!io)
goto error;
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)
return BH_ERROR;
/* Call the IO device open handler with specified mode */
return io->cb(io + 1, BH_IO_OPEN_CB, &mode, NULL);
}
int BH_IOClose(BH_IO *io)
{
/* Prevent working with NULL io */
if (!io)
return BH_ERROR;
/* Call the IO device close handler */
return io->cb(io + 1, BH_IO_CLOSE_CB, NULL, NULL);
}
int BH_IORead(BH_IO *io,
char *buffer, char *buffer,
size_t size, size_t size,
size_t *actual) size_t *actual)
{ {
int code; BH_IOReadInfo info;
/* Prevent working with NULL io */ /* Prevent working with NULL io */
if (!io) if (!device)
return BH_ERROR; return BH_ERROR;
/* Call the IO device read handler */ info.data = buffer;
code = io->cb(io + 1, BH_IO_READ_CB, buffer, &size); info.size = size;
info.actual = actual;
/* If caller wants to know actual read size - report it back */ return device->callback(device, BH_IO_OP_READ, &info);
if (actual)
*actual = size;
return code;
} }
int BH_IOWrite(BH_IO *io, int BH_IOWrite(BH_IO *device,
const char *buffer, const char *buffer,
size_t size, size_t size,
size_t *actual) size_t *actual)
{ {
int code; BH_IOWriteInfo info;
/* Prevent working with NULL io */ /* Prevent working with NULL io */
if (!io) if (!device)
return BH_ERROR; return BH_ERROR;
/* Call the IO device write handler */ info.data = buffer;
code = io->cb(io + 1, BH_IO_WRITE_CB, (void *)buffer, &size); info.size = size;
info.actual = actual;
/* If caller wants to know actual written size - report it back */ return device->callback(device, BH_IO_OP_WRITE, &info);
if (actual)
*actual = size;
return code;
} }
int BH_IOPeek(BH_IO *io, int BH_IOCtl(BH_IO *device,
int op,
void *arg)
{
BH_IOCtlInfo info;
if (!device)
return BH_ERROR;
info.op = op;
info.arg = arg;
return device->callback(device, BH_IO_OP_CTL, &info);
}
int BH_IOCap(BH_IO *device,
int op)
{
if (!device)
return BH_ERROR;
return device->callback(device, BH_IO_OP_CAP, &op);
}
int BH_IOPeek(BH_IO *device,
char *buffer, char *buffer,
size_t size, size_t size,
size_t *actual) size_t *actual)
{ {
int code; BH_IOReadInfo readInfo;
BH_IOSeekInfo posInfo;
size_t readed;
/* Prevent working with NULL io */ readInfo.data = buffer;
if (!io) readInfo.size = size;
return BH_ERROR; readInfo.actual = actual;
/* Call the IO device peek handler */ if (BH_IOCap(device, BH_IO_CTL_PEEK))
code = io->cb(io + 1, BH_IO_PEEK_CB, (void *)buffer, &size); {
if (BH_IOCap(device, BH_IO_CTL_SEEK))
return BH_NOIMPL;
/* If caller wants to know actual written size - report it back */ if (BH_IORead(device, buffer, size, &readed))
if (actual) return BH_ERROR;
*actual = size;
return code; posInfo.whence = BH_IO_SEEK_CUR;
posInfo.offset = -(int64_t)readed;
if (BH_IOCtl(device, BH_IO_CTL_SEEK, &posInfo))
return BH_ERROR;
if (actual)
*actual = readed;
return BH_OK;
}
return BH_IOCtl(device, BH_IO_CTL_PEEK, &readInfo);
} }
int BH_IOTell(BH_IO *io, int BH_IOTell(BH_IO *device,
int64_t *position) int64_t *offset)
{ {
/* Prevent working with NULL io */ return BH_IOCtl(device, BH_IO_CTL_TELL, offset);
if (!io)
return BH_ERROR;
/* Call the IO device tell handler */
return io->cb(io + 1, BH_IO_TELL_CB, position, NULL);
} }
int BH_IOSeek(BH_IO *io, int BH_IOSeek(BH_IO *device,
int64_t position, int64_t offset,
int direction) int whence)
{ {
/* Prevent working with NULL io */ BH_IOSeekInfo info;
if (!io)
return BH_ERROR;
/* Call the IO device seek handler */ info.offset = offset;
return io->cb(io + 1, BH_IO_SEEK_CB, &position, &direction); 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 */ return BH_IOCtl(device, BH_IO_CTL_FLUSH, NULL);
if (!io)
return BH_ERROR;
/* Call the IO device flush handler */
return io->cb(io + 1, BH_IO_FLUSH_CB, NULL, NULL);
} }
int BH_IOSize(BH_IO *io, int BH_IOSize(BH_IO *device,
int64_t *size) int64_t *size)
{ {
/* Prevent working with NULL io */ return BH_IOCtl(device, BH_IO_CTL_SIZE, size);
if (!io) }
int BH_IOFlags(BH_IO *device, int *flags)
{
return BH_IOCtl(device, BH_IO_CTL_FLAGS, flags);
}
int BH_IOClear(BH_IO *device)
{
return BH_IOCtl(device, BH_IO_CTL_CLEAR, NULL);
}
int BH_IOError(BH_IO *device)
{
int flags;
if (BH_IOFlags(device, &flags))
return BH_ERROR; return BH_ERROR;
/* Call the IO device size handler */ return flags & BH_IO_FLAG_ERROR;
return io->cb(io + 1, BH_IO_SIZE_CB, size, NULL);
} }
int BH_IOFlags(BH_IO *io) int BH_IOEndOfFile(BH_IO *device)
{ {
/* Prevent working with NULL io */ int flags;
if (!io)
return BH_IO_FLAG_ERROR;
/* Call the IO device flags handler */ if (BH_IOFlags(device, &flags))
return io->cb(io + 1, BH_IO_FLAGS_CB, NULL, NULL); return BH_ERROR;
}
return flags & BH_IO_FLAG_EOF;
int BH_IOClear(BH_IO *io)
{
/* Prevent working with NULL io */
if (!io)
return BH_OK;
/* Call the IO device clear error handler */
return io->cb(io + 1, BH_IO_CLEAR_CB, NULL, NULL);
}
BH_IO *BH_BufferNew(BH_IO *io)
{
(void)io;
return NULL;
} }

View File

@@ -1,200 +1,15 @@
#include <BH/IO.h> #include <BH/IO.h>
typedef struct BH_File
BH_IO *BH_FileNew(const char *path,
int mode,
int *result)
{ {
int implement; BH_UNUSED(path);
int me; BH_UNUSED(mode);
} BH_File;
if (result)
*result = BH_NOIMPL;
static int BH_FileInfo(BH_File *file, return NULL;
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);
} }

View File

@@ -10,166 +10,67 @@
typedef struct BH_File typedef struct BH_File
{ {
char *path; BH_IO parent;
int mode;
int flags; int flags;
int handle; int handle;
} BH_File; } BH_File;
static int BH_FileInfo(BH_File *file, static int fileOpenFlags(int mode)
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; int flags = 0;
/* Determine read/write flags */ /* Determine read/write flags */
if ((mode & BH_IO_READWRITE) == BH_IO_READWRITE) if ((mode & BH_FILE_READWRITE) == BH_FILE_READWRITE)
flags |= O_RDWR; flags |= O_RDWR;
else if (mode & BH_IO_WRITE) else if (mode & BH_FILE_WRITE)
flags |= O_WRONLY; flags |= O_WRONLY;
else if (mode & BH_IO_READ) else if (mode & BH_FILE_READ)
flags |= O_RDONLY; flags |= O_RDONLY;
else else
return -1; return -1;
/* Check if existing file should be opened */ /* Check if existing file should be opened */
if (!(mode & BH_IO_EXIST)) if (!(mode & BH_FILE_EXIST))
{ {
flags |= O_CREAT; flags |= O_CREAT;
/* Check if file should be created */ /* Check if file should be created */
if (mode & BH_IO_CREATE) if (mode & BH_FILE_CREATE)
flags |= O_EXCL; flags |= O_EXCL;
} }
/* Check if file should be opened in append mode */ /* Check if file should be opened in append mode */
if (mode & BH_IO_APPEND) if (mode & BH_FILE_APPEND)
flags |= O_APPEND; flags |= O_APPEND;
/* Check if file should be truncated */ /* Check if file should be truncated */
if (mode & BH_IO_TRUNCATE) if (mode & BH_FILE_TRUNCATE)
flags |= O_TRUNC; flags |= O_TRUNC;
return flags; return flags;
} }
static int BH_FileOpen(BH_File *file, static int fileInit(BH_File *file,
int *mode) const char *path,
int mode)
{ {
static const mode_t open_mode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); static const mode_t open_mode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
int flags; int flags;
/* If file is already opened - report error */ /* Check if path is valid */
if (file->handle != -1) if (!path)
return BH_ERROR; return BH_ERROR;
/* Determine file open flags */ /* Determine file open flags */
flags = BH_FileOpenFlags(*mode); flags = fileOpenFlags(mode);
if (flags == -1) if (flags == -1)
return BH_ERROR; return BH_ERROR;
/* Open the file */ /* 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) if (file->handle == -1)
return BH_ERROR; 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); close(file->handle);
file->handle = -1; free(file);
return BH_OK; return BH_OK;
} }
static int BH_FileRead(BH_File *file, static int fileRead(BH_File *file,
char *data, BH_IOReadInfo *info)
size_t *size)
{ {
ssize_t readed; ssize_t readed;
/* Check if file is open */
if (file->handle == -1)
goto error;
/* Read data from the file */ /* Read data from the file */
readed = read(file->handle, data, *size); readed = read(file->handle, info->data, info->size);
if (readed < 0) if (readed < 0)
goto error; goto error;
@@ -212,7 +103,8 @@ static int BH_FileRead(BH_File *file,
else else
file->flags |= BH_IO_FLAG_EOF; file->flags |= BH_IO_FLAG_EOF;
*size = readed; if (info->actual)
*info->actual = readed;
return BH_OK; return BH_OK;
error: error:
@@ -221,18 +113,13 @@ error:
} }
static int BH_FileWrite(BH_File *file, static int fileWrite(BH_File *file,
const char *data, BH_IOWriteInfo *info)
size_t *size)
{ {
ssize_t written; ssize_t written;
/* Check if file is open */
if (file->handle == -1)
goto error;
/* Write data to the file */ /* Write data to the file */
written = write(file->handle, data, *size); written = write(file->handle, info->data, info->size);
if (written < 0) if (written < 0)
goto error; goto error;
@@ -242,7 +129,8 @@ static int BH_FileWrite(BH_File *file,
else else
file->flags &= ~BH_IO_FLAG_EOF; file->flags &= ~BH_IO_FLAG_EOF;
*size = written; if (info->actual)
*info->actual = written;
return BH_OK; return BH_OK;
error: error:
@@ -251,60 +139,19 @@ error:
} }
static int BH_FilePeek(BH_File *file, static int fileFlush(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 */ /* Flush the buffers */
fsync(file->handle); fsync(file->handle);
return BH_OK; return BH_OK;
} }
static int BH_FileSeek(BH_File *file, static int fileSeek(BH_File *file,
int64_t *pos, BH_IOSeekInfo *info)
int *dir)
{ {
/* Check if file is open */
if (file->handle == -1)
goto error;
/* Seek to the specified position */ /* Seek to the specified position */
if (lseek(file->handle, *pos, *dir) == -1) if (lseek(file->handle, info->offset, info->whence) == -1)
goto error; goto error;
return BH_OK; return BH_OK;
@@ -315,13 +162,9 @@ error:
} }
static int BH_FileTell(BH_File *file, static int fileTell(BH_File *file,
int64_t *pos) int64_t *pos)
{ {
/* Check if file is open */
if (file->handle == -1)
goto error;
/* Get current offset in the file */ /* Get current offset in the file */
if ((*pos = lseek(file->handle, 0, SEEK_CUR)) == -1) if ((*pos = lseek(file->handle, 0, SEEK_CUR)) == -1)
goto error; goto error;
@@ -334,15 +177,11 @@ error:
} }
static int BH_FileSize(BH_File *file, static int fileSize(BH_File *file,
int64_t *size) int64_t *size)
{ {
struct stat sb; struct stat sb;
/* Check if file is open */
if (file->handle == -1)
goto error;
/* Get file size from the OS */ /* Get file size from the OS */
if (fstat(file->handle, &sb)) if (fstat(file->handle, &sb))
goto error; 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 */ *flags = file->flags;
if (file->handle != -1) return BH_OK;
return file->flags | BH_IO_FLAG_OPEN;
return file->flags;
} }
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; file->flags &= ~BH_IO_FLAG_ERROR;
return BH_OK; return BH_OK;
} }
static int BH_FileCallback(BH_File *file, static int fileCap(BH_File *file,
int type, int *op)
void *arg1,
void *arg2)
{ {
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) switch (type)
{ {
case BH_IO_INFO_CB: return BH_FileInfo(file, (size_t *)arg1, (const char **)arg2); case BH_IO_OP_DESTROY: return fileDestroy(file);
case BH_IO_INIT_CB: return BH_FileInit(file, (const char *)arg1); case BH_IO_OP_READ: return fileRead(file, (BH_IOReadInfo *)arg);
case BH_IO_DESTROY_CB: return BH_FileDestroy(file); case BH_IO_OP_WRITE: return fileWrite(file, (BH_IOWriteInfo *)arg);
case BH_IO_OPEN_CB: return BH_FileOpen(file, (int *)arg1); case BH_IO_OP_CTL: return fileCtl(file, (BH_IOCtlInfo *)arg);
case BH_IO_CLOSE_CB: return BH_FileClose(file); case BH_IO_OP_CAP: return fileCap(file, (int*)arg);
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; 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;
} }

View File

@@ -6,195 +6,87 @@
typedef struct BH_File typedef struct BH_File
{ {
char *path; BH_IO parent;
int mode;
int flags; int flags;
int mode;
HANDLE handle; HANDLE handle;
} BH_File; } BH_File;
static int BH_FileInfo(BH_File *file, static int fileInit(BH_File *file,
size_t *size, const char *path,
const char **name); int mode)
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; DWORD access = 0, how = 0;
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 */ /* Check if path is valid */
if (!path) if (!path)
return BH_ERROR; 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 */ /* Determine read/write access flags */
if (*mode & BH_IO_READ) if (mode & BH_FILE_READ)
access |= GENERIC_READ; access |= GENERIC_READ;
if (*mode & BH_IO_WRITE) if (mode & BH_FILE_WRITE)
access |= GENERIC_WRITE; access |= GENERIC_WRITE;
if (!access) if (!access)
return BH_ERROR; return BH_ERROR;
/* Determine open mode flags */ /* 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 0: how = CREATE_ALWAYS; break;
case BH_IO_CREATE: how = CREATE_NEW; break; case BH_FILE_CREATE: how = CREATE_NEW; break;
case BH_IO_EXIST: how = TRUNCATE_EXISTING; break; case BH_FILE_EXIST: how = TRUNCATE_EXISTING; break;
default: return BH_ERROR; default: return BH_ERROR;
} }
} }
else else
{ {
switch (*mode & (BH_IO_CREATE | BH_IO_EXIST)) switch (mode & (BH_FILE_CREATE | BH_FILE_EXIST))
{ {
case 0: how = OPEN_ALWAYS; break; case 0: how = OPEN_ALWAYS; break;
case BH_IO_CREATE: how = CREATE_NEW; break; case BH_FILE_CREATE: how = CREATE_NEW; break;
case BH_IO_EXIST: how = OPEN_EXISTING; break; case BH_FILE_EXIST: how = OPEN_EXISTING; break;
default: return BH_ERROR; default: return BH_ERROR;
} }
} }
/* Save mode that we are in and open file */ /* Save mode that we are in and open file */
file->mode = *mode; file->flags = 0;
file->handle = CreateFileA(file->path, access, FILE_SHARE_READ, NULL, how, FILE_ATTRIBUTE_NORMAL, NULL); file->mode = mode;
file->handle = CreateFileA(path, access, FILE_SHARE_READ, NULL, how, FILE_ATTRIBUTE_NORMAL, NULL);
if (file->handle == INVALID_HANDLE_VALUE) if (file->handle == INVALID_HANDLE_VALUE)
return BH_ERROR; return BH_ERROR;
/* Truncate file if needed */ /* Truncate file if needed */
if (*mode & BH_IO_TRUNCATE) if (mode & BH_FILE_TRUNCATE)
SetEndOfFile(file->handle); SetEndOfFile(file->handle);
return BH_OK; return BH_OK;
} }
static int BH_FileClose(BH_File *file) static int fileDestroy(BH_File *file)
{ {
/* If file is opened - close it */ /* Close the file handle on destruction */
if (file->handle == INVALID_HANDLE_VALUE)
return BH_ERROR;
/* Reset handle and mode values */
CloseHandle(file->handle); CloseHandle(file->handle);
file->handle = INVALID_HANDLE_VALUE; free(file);
file->mode = 0;
return BH_OK; return BH_OK;
} }
static int BH_FileRead(BH_File *file, static int fileRead(BH_File *file,
char *data, BH_IOReadInfo *info)
size_t *size)
{ {
DWORD readed; DWORD readed;
/* Check if file is opened */
if (file->handle == INVALID_HANDLE_VALUE)
goto error;
/* Read data from the file */ /* 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; goto error;
/* Check if we reached end of file */ /* Check if we reached end of file */
@@ -203,7 +95,9 @@ static int BH_FileRead(BH_File *file,
else else
file->flags &= ~BH_IO_FLAG_EOF; file->flags &= ~BH_IO_FLAG_EOF;
*size = readed; if (info->actual)
*info->actual = readed;
return BH_OK; return BH_OK;
error: error:
@@ -212,28 +106,22 @@ error:
} }
static int BH_FileWrite(BH_File *file, static int fileWrite(BH_File *file,
const char *data, BH_IOWriteInfo *info)
size_t *size)
{ {
DWORD written; DWORD written;
LARGE_INTEGER position;
/* Check if file is opened */
if (file->handle == INVALID_HANDLE_VALUE)
goto error;
/* Adjust current position in the file to the end */ /* 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; position.QuadPart = 0;
if (!SetFilePointerEx(file->handle, position, NULL, FILE_END)) if (!SetFilePointerEx(file->handle, position, NULL, FILE_END))
goto error; goto error;
} }
/* Write data to the file */ /* 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; goto error;
/* Check for end of file */ /* Check for end of file */
@@ -242,7 +130,9 @@ static int BH_FileWrite(BH_File *file,
else else
file->flags &= ~BH_IO_FLAG_EOF; file->flags &= ~BH_IO_FLAG_EOF;
*size = written; if (info->actual)
*info->actual = written;
return BH_OK; return BH_OK;
error: error:
@@ -251,56 +141,22 @@ error:
} }
static int BH_FilePeek(BH_File *file, static int fileFlush(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 */ /* Flush OS buffers */
FlushFileBuffers(file->handle); FlushFileBuffers(file->handle);
return BH_OK; return BH_OK;
error:
file->flags |= BH_IO_FLAG_ERROR;
return BH_ERROR;
} }
static int BH_FileSeek(BH_File *file, static int fileSeek(BH_File *file,
int64_t *pos, BH_IOSeekInfo *info)
int *dir)
{ {
LARGE_INTEGER position; LARGE_INTEGER position;
/* Check if file is opened */
if (file->handle == INVALID_HANDLE_VALUE)
goto error;
/* Set read/write position in the file */ /* Set read/write position in the file */
position.QuadPart = *pos; position.QuadPart = info->offset;
if (!SetFilePointerEx(file->handle, position, NULL, *dir)) if (!SetFilePointerEx(file->handle, position, NULL, info->whence))
goto error; goto error;
return BH_OK; return BH_OK;
@@ -311,15 +167,11 @@ error:
} }
static int BH_FileTell(BH_File *file, static int fileTell(BH_File *file,
int64_t *pos) int64_t *pos)
{ {
LARGE_INTEGER dummy, position; LARGE_INTEGER dummy, position;
/* Check if file is opened */
if (file->handle == INVALID_HANDLE_VALUE)
goto error;
/* Readback current position in the file */ /* Readback current position in the file */
dummy.QuadPart = 0; dummy.QuadPart = 0;
if (!SetFilePointerEx(file->handle, dummy, &position, BH_IO_SEEK_CUR)) if (!SetFilePointerEx(file->handle, dummy, &position, BH_IO_SEEK_CUR))
@@ -334,15 +186,11 @@ error:
} }
static int BH_FileSize(BH_File *file, static int fileSize(BH_File *file,
int64_t *size) int64_t *size)
{ {
LARGE_INTEGER dummy; LARGE_INTEGER dummy;
/* Check if file is opened */
if (file->handle == INVALID_HANDLE_VALUE)
goto error;
/* Get current file size */ /* Get current file size */
if (!GetFileSizeEx(file->handle, &dummy)) if (!GetFileSizeEx(file->handle, &dummy))
goto error; 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 */ *flags = file->flags;
if (file->handle != INVALID_HANDLE_VALUE) return BH_OK;
return file->flags | BH_IO_FLAG_OPEN;
return file->flags;
} }
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; file->flags &= ~BH_IO_FLAG_ERROR;
return BH_OK; return BH_OK;
} }
static int BH_FileCallback(BH_File *file, static int fileCap(BH_File *file,
int type, int *op)
void *arg1,
void *arg2)
{ {
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) switch (type)
{ {
case BH_IO_INFO_CB: return BH_FileInfo(file, (size_t *)arg1, (const char **)arg2); case BH_IO_OP_DESTROY: return fileDestroy(file);
case BH_IO_INIT_CB: return BH_FileInit(file, (const char *)arg1); case BH_IO_OP_READ: return fileRead(file, (BH_IOReadInfo *)arg);
case BH_IO_DESTROY_CB: return BH_FileDestroy(file); case BH_IO_OP_WRITE: return fileWrite(file, (BH_IOWriteInfo *)arg);
case BH_IO_OPEN_CB: return BH_FileOpen(file, (int *)arg1); case BH_IO_OP_CTL: return fileCtl(file, (BH_IOCtlInfo *)arg);
case BH_IO_CLOSE_CB: return BH_FileClose(file); case BH_IO_OP_CAP: return fileCap(file, (int*)arg);
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; 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;
} }

126
test/src/TestBuffer.c Normal file
View File

@@ -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();
}

153
test/src/TestBytes.c Normal file
View File

@@ -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();
}

View File

@@ -26,13 +26,7 @@ static void cleanup(void)
*/ */
static int checkNull(void) static int checkNull(void)
{ {
BH_IO *io;
/* Check against NULL pointers */ /* 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_IORead(NULL, NULL, 0, NULL) != BH_OK);
BH_VERIFY(BH_IOWrite(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); 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_IOSeek(NULL, 0, 0) != BH_OK);
BH_VERIFY(BH_IOFlush(NULL) != BH_OK); BH_VERIFY(BH_IOFlush(NULL) != BH_OK);
BH_VERIFY(BH_IOSize(NULL, NULL) != BH_OK); BH_VERIFY(BH_IOSize(NULL, NULL) != BH_OK);
BH_VERIFY(BH_IOFlags(NULL) == BH_IO_FLAG_ERROR); BH_VERIFY(BH_IOFlags(NULL, NULL) != BH_OK);
BH_VERIFY(BH_IOClear(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); 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; return 0;
} }
@@ -75,13 +57,7 @@ static int checkNormal(void)
BH_IO *io; BH_IO *io;
/* Check operations for write only access */ /* Check operations for write only access */
BH_VERIFY((io = BH_FileNew(FILENAME1)) != NULL); BH_VERIFY((io = BH_FileNew(FILENAME1, BH_FILE_WRITE, NULL)) != 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(BH_IOWrite(io, "1234567890", 10, &actual) == BH_OK); BH_VERIFY(BH_IOWrite(io, "1234567890", 10, &actual) == BH_OK);
BH_VERIFY(actual == 10); 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_IOSeek(io, 0, BH_IO_SEEK_END) == BH_OK);
BH_VERIFY(BH_IOTell(io, &position) == BH_OK); BH_VERIFY(BH_IOTell(io, &position) == BH_OK);
BH_VERIFY(position == 20); BH_VERIFY(position == 20);
BH_IOClose(io); BH_IOFree(io);
/* Check operations for read only access */ /* Check operations for read only access */
BH_VERIFY(BH_IOOpen(io, BH_IO_READ) == BH_OK); BH_VERIFY((io = BH_FileNew(FILENAME1, BH_FILE_READ, NULL)) != NULL);
BH_VERIFY(BH_IOFlags(io) & BH_IO_FLAG_OPEN);
BH_VERIFY(strcmp(BH_IOClassname(io), BH_FILE_CLASSNAME) == 0);
BH_VERIFY(BH_IORead(io, buffer, 10, &actual) == BH_OK); BH_VERIFY(BH_IORead(io, buffer, 10, &actual) == BH_OK);
BH_VERIFY(actual == 10); BH_VERIFY(actual == 10);
BH_VERIFY(memcmp(buffer, "1234567890", 10) == 0); BH_VERIFY(memcmp(buffer, "1234567890", 10) == 0);
@@ -124,10 +98,7 @@ static int checkNormal(void)
BH_IOFree(io); BH_IOFree(io);
/* Check operations for read and write access */ /* Check operations for read and write access */
BH_VERIFY((io = BH_FileNew(FILENAME1)) != NULL); BH_VERIFY((io = BH_FileNew(FILENAME1, BH_FILE_READWRITE, NULL)) != 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(BH_IOWrite(io, "abcde", 5, &actual) == BH_OK); BH_VERIFY(BH_IOWrite(io, "abcde", 5, &actual) == BH_OK);
BH_VERIFY(actual == 5); BH_VERIFY(actual == 5);
@@ -151,8 +122,6 @@ static int checkNormal(void)
BH_VERIFY(BH_IORead(io, buffer, 35, &actual) == BH_OK); BH_VERIFY(BH_IORead(io, buffer, 35, &actual) == BH_OK);
BH_VERIFY(actual == 35); BH_VERIFY(actual == 35);
BH_VERIFY(memcmp(buffer, "abcde12345678901234567890abcde67890", 35) == 0); BH_VERIFY(memcmp(buffer, "abcde12345678901234567890abcde67890", 35) == 0);
BH_IOClose(io);
BH_IOFree(io); BH_IOFree(io);
return 0; return 0;
} }
@@ -169,11 +138,7 @@ static int checkTruncate(void)
BH_IO *io; BH_IO *io;
/* Check operations for write only access */ /* Check operations for write only access */
BH_VERIFY((io = BH_FileNew(FILENAME1)) != NULL); BH_VERIFY((io = BH_FileNew(FILENAME1, BH_FILE_WRITE | BH_FILE_TRUNCATE, NULL)) != 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(BH_IOWrite(io, "1234567890", 10, &actual) == BH_OK); BH_VERIFY(BH_IOWrite(io, "1234567890", 10, &actual) == BH_OK);
BH_VERIFY(actual == 10); 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_IOSeek(io, 0, BH_IO_SEEK_END) == BH_OK);
BH_VERIFY(BH_IOTell(io, &position) == BH_OK); BH_VERIFY(BH_IOTell(io, &position) == BH_OK);
BH_VERIFY(position == 20); BH_VERIFY(position == 20);
BH_IOClose(io); BH_IOFree(io);
/* Check operations for read only access without truncate */ /* Check operations for read only access without truncate */
BH_VERIFY(BH_IOOpen(io, BH_IO_READ) == BH_OK); BH_VERIFY((io = BH_FileNew(FILENAME1, BH_FILE_READ, NULL)) != NULL);
BH_VERIFY(BH_IOFlags(io) & BH_IO_FLAG_OPEN);
BH_VERIFY(BH_IORead(io, buffer, 10, &actual) == BH_OK); BH_VERIFY(BH_IORead(io, buffer, 10, &actual) == BH_OK);
BH_VERIFY(actual == 10); BH_VERIFY(actual == 10);
BH_VERIFY(memcmp(buffer, "1234567890", 10) == 0); 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(BH_IORead(io, buffer, 5, &actual) == BH_OK);
BH_VERIFY(actual == 5); BH_VERIFY(actual == 5);
BH_VERIFY(memcmp(buffer, "67890", 5) == 0); BH_VERIFY(memcmp(buffer, "67890", 5) == 0);
BH_IOClose(io); BH_IOFree(io);
/* Check operations for read only access */ /* Check operations for read only access */
BH_VERIFY(BH_IOOpen(io, BH_IO_READ | BH_IO_TRUNCATE) == BH_OK); BH_VERIFY((io = BH_FileNew(FILENAME1, BH_FILE_READ | BH_FILE_TRUNCATE, NULL)) != NULL);
BH_VERIFY(BH_IOFlags(io) & BH_IO_FLAG_OPEN);
BH_VERIFY(BH_IORead(io, buffer, 10, &actual) == BH_OK); BH_VERIFY(BH_IORead(io, buffer, 10, &actual) == BH_OK);
BH_VERIFY(actual == 0); BH_VERIFY(actual == 0);
@@ -229,11 +192,7 @@ static int checkTruncate(void)
BH_IOFree(io); BH_IOFree(io);
/* Check operations for read and write access */ /* Check operations for read and write access */
BH_VERIFY((io = BH_FileNew(FILENAME1)) != NULL); BH_VERIFY((io = BH_FileNew(FILENAME1, BH_FILE_READWRITE | BH_FILE_TRUNCATE, NULL)) != 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(BH_IOWrite(io, "abcde", 5, &actual) == BH_OK); BH_VERIFY(BH_IOWrite(io, "abcde", 5, &actual) == BH_OK);
BH_VERIFY(actual == 5); BH_VERIFY(actual == 5);
@@ -256,13 +215,11 @@ static int checkTruncate(void)
BH_VERIFY(BH_IORead(io, buffer, 35, &actual) == BH_OK); BH_VERIFY(BH_IORead(io, buffer, 35, &actual) == BH_OK);
BH_VERIFY(actual == 35); BH_VERIFY(actual == 35);
BH_VERIFY(memcmp(buffer, "abcde12345678901234567890abcde67890", 35) == 0); 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_IOFree(io);
BH_VERIFY((io = BH_FileNew(FILENAME1, BH_FILE_WRITE | BH_FILE_TRUNCATE, NULL)) != NULL);
BH_IOFree(io);
return 0; return 0;
} }
@@ -278,10 +235,7 @@ static int checkExist(void)
BH_IO *io; BH_IO *io;
/* Check operations for write only access */ /* Check operations for write only access */
BH_VERIFY((io = BH_FileNew(FILENAME1)) != NULL); BH_VERIFY((io = BH_FileNew(FILENAME1, BH_FILE_WRITE | BH_FILE_EXIST, NULL)) != 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(BH_IOWrite(io, "1234567890", 10, &actual) == BH_OK); BH_VERIFY(BH_IOWrite(io, "1234567890", 10, &actual) == BH_OK);
BH_VERIFY(actual == 10); 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_IOSeek(io, 0, BH_IO_SEEK_END) == BH_OK);
BH_VERIFY(BH_IOTell(io, &position) == BH_OK); BH_VERIFY(BH_IOTell(io, &position) == BH_OK);
BH_VERIFY(position == 20); BH_VERIFY(position == 20);
BH_IOClose(io); BH_IOFree(io);
/* Check operations for read only access */ /* Check operations for read only access */
BH_VERIFY(BH_IOOpen(io, BH_IO_READ | BH_IO_EXIST) == BH_OK); BH_VERIFY((io = BH_FileNew(FILENAME1, BH_FILE_READ | BH_FILE_EXIST, NULL)) != NULL);
BH_VERIFY(BH_IOFlags(io) & BH_IO_FLAG_OPEN);
BH_VERIFY(BH_IORead(io, buffer, 10, &actual) == BH_OK); BH_VERIFY(BH_IORead(io, buffer, 10, &actual) == BH_OK);
BH_VERIFY(actual == 10); BH_VERIFY(actual == 10);
BH_VERIFY(memcmp(buffer, "1234567890", 10) == 0); BH_VERIFY(memcmp(buffer, "1234567890", 10) == 0);
@@ -324,10 +278,7 @@ static int checkExist(void)
BH_IOFree(io); BH_IOFree(io);
/* Check operations for read and write access */ /* Check operations for read and write access */
BH_VERIFY((io = BH_FileNew(FILENAME1)) != NULL); BH_VERIFY((io = BH_FileNew(FILENAME1, BH_FILE_WRITE | BH_FILE_READ | BH_FILE_EXIST, NULL)) != 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(BH_IOWrite(io, "abcde", 5, &actual) == BH_OK); BH_VERIFY(BH_IOWrite(io, "abcde", 5, &actual) == BH_OK);
BH_VERIFY(actual == 5); BH_VERIFY(actual == 5);
@@ -351,19 +302,12 @@ static int checkExist(void)
BH_VERIFY(BH_IORead(io, buffer, 35, &actual) == BH_OK); BH_VERIFY(BH_IORead(io, buffer, 35, &actual) == BH_OK);
BH_VERIFY(actual == 35); BH_VERIFY(actual == 35);
BH_VERIFY(memcmp(buffer, "abcde12345678901234567890abcde67890", 35) == 0); BH_VERIFY(memcmp(buffer, "abcde12345678901234567890abcde67890", 35) == 0);
BH_IOClose(io);
BH_IOFree(io); BH_IOFree(io);
/* Check against non existing files */ /* Check against non existing files */
BH_VERIFY((io = BH_FileNew(FILENAME2)) != NULL); BH_VERIFY(BH_FileNew(FILENAME2, BH_FILE_WRITE | BH_FILE_EXIST, NULL) == NULL);
BH_VERIFY(strcmp(BH_IOClassname(io), BH_FILE_CLASSNAME) == 0); BH_VERIFY(BH_FileNew(FILENAME2, BH_FILE_READ | BH_FILE_EXIST, NULL) == NULL);
BH_VERIFY(BH_IOOpen(io, BH_IO_WRITE | BH_IO_EXIST) != BH_OK); BH_VERIFY(BH_FileNew(FILENAME2, BH_FILE_READWRITE | BH_FILE_EXIST, NULL) == NULL);
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);
return 0; return 0;
} }
@@ -382,10 +326,7 @@ static int checkAppend(void)
cleanup(); cleanup();
/* Check operations for write only access */ /* Check operations for write only access */
BH_VERIFY((io = BH_FileNew(FILENAME1)) != NULL); BH_VERIFY((io = BH_FileNew(FILENAME1, BH_FILE_WRITE | BH_FILE_APPEND, NULL)) != 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(BH_IOWrite(io, "1234567890", 10, &actual) == BH_OK); BH_VERIFY(BH_IOWrite(io, "1234567890", 10, &actual) == BH_OK);
BH_VERIFY(actual == 10); 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_IOSeek(io, 0, BH_IO_SEEK_END) == BH_OK);
BH_VERIFY(BH_IOTell(io, &position) == BH_OK); BH_VERIFY(BH_IOTell(io, &position) == BH_OK);
BH_VERIFY(position == 25); BH_VERIFY(position == 25);
BH_IOClose(io); BH_IOFree(io);
/* Check operations for read only access */ /* Check operations for read only access */
BH_VERIFY(BH_IOOpen(io, BH_IO_READ | BH_IO_APPEND) == BH_OK); BH_VERIFY((io = BH_FileNew(FILENAME1, BH_FILE_READ | BH_FILE_APPEND, NULL)) != NULL);
BH_VERIFY(BH_IOFlags(io) & BH_IO_FLAG_OPEN);
BH_VERIFY(strcmp(BH_IOClassname(io), BH_FILE_CLASSNAME) == 0);
BH_VERIFY(BH_IORead(io, buffer, 10, &actual) == BH_OK); BH_VERIFY(BH_IORead(io, buffer, 10, &actual) == BH_OK);
BH_VERIFY(actual == 10); BH_VERIFY(actual == 10);
BH_VERIFY(memcmp(buffer, "1234567890", 10) == 0); 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(BH_IORead(io, buffer, 5, &actual) == BH_OK);
BH_VERIFY(actual == 5); BH_VERIFY(actual == 5);
BH_VERIFY(memcmp(buffer, "abcde", 5) == 0); BH_VERIFY(memcmp(buffer, "abcde", 5) == 0);
BH_IOClose(io); BH_IOFree(io);
/* Check operations for read and write access */ /* 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((io = BH_FileNew(FILENAME1, BH_FILE_READWRITE | BH_FILE_APPEND, NULL)) != NULL);
BH_VERIFY(BH_IOFlags(io) & BH_IO_FLAG_OPEN);
BH_VERIFY(BH_IOWrite(io, "abcde", 5, &actual) == BH_OK); BH_VERIFY(BH_IOWrite(io, "abcde", 5, &actual) == BH_OK);
BH_VERIFY(actual == 5); BH_VERIFY(actual == 5);
@@ -441,13 +380,12 @@ static int checkAppend(void)
BH_VERIFY(BH_IORead(io, buffer, 40, &actual) == BH_OK); BH_VERIFY(BH_IORead(io, buffer, 40, &actual) == BH_OK);
BH_VERIFY(actual == 40); BH_VERIFY(actual == 40);
BH_VERIFY(memcmp(buffer, "12345678901234567890abcdeabcde1234567890", 40) == 0); 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((io = BH_FileNew(FILENAME1, BH_FILE_WRITE | BH_FILE_TRUNCATE, NULL)) != NULL);
BH_VERIFY(BH_IOFlags(io) & BH_IO_FLAG_OPEN);
BH_IOClose(io);
BH_IOFree(io); BH_IOFree(io);
return 0; return 0;
} }
@@ -460,31 +398,18 @@ static int checkCreate(void)
BH_IO *io; BH_IO *io;
/* Check for already existing file */ /* Check for already existing file */
BH_VERIFY((io = BH_FileNew(FILENAME1)) != NULL); BH_VERIFY(BH_FileNew(FILENAME1, BH_FILE_WRITE | BH_FILE_CREATE, NULL) == 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);
/* Check for new file with write access */ /* Check for new file with write access */
BH_VERIFY((io = BH_FileNew(FILENAME2)) != NULL); BH_VERIFY((io = BH_FileNew(FILENAME2, BH_FILE_WRITE | BH_FILE_CREATE, NULL)) != 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_IOFree(io); BH_IOFree(io);
/* Check for new file with read access */ /* Check for new file with read access */
BH_VERIFY((io = BH_FileNew(FILENAME3)) != NULL); BH_VERIFY((io = BH_FileNew(FILENAME3, BH_FILE_READ | BH_FILE_CREATE, NULL)) != 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_IOFree(io); BH_IOFree(io);
/* Check for new file with read/write access */ /* Check for new file with read/write access */
BH_VERIFY((io = BH_FileNew(FILENAME4)) != NULL); BH_VERIFY((io = BH_FileNew(FILENAME4, BH_FILE_READWRITE | BH_FILE_CREATE, NULL)) != 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_IOFree(io); BH_IOFree(io);
return 0; return 0;
@@ -500,16 +425,12 @@ static int checkEOF(void)
size_t actual; size_t actual;
BH_IO *io; BH_IO *io;
BH_VERIFY((io = BH_FileNew(FILENAME1)) != NULL); BH_VERIFY((io = BH_FileNew(FILENAME1, BH_FILE_READ | BH_FILE_TRUNCATE, NULL)) != 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(BH_IORead(io, buffer, 128, &actual) == BH_OK); BH_VERIFY(BH_IORead(io, buffer, 128, &actual) == BH_OK);
BH_VERIFY(actual == 0); BH_VERIFY(actual == 0);
BH_VERIFY(BH_IOFlags(io) & BH_IO_FLAG_EOF); BH_VERIFY(BH_IOEndOfFile(io));
BH_IOClose(io);
BH_IOFree(io); BH_IOFree(io);
return 0; return 0;
@@ -524,17 +445,13 @@ static int checkError(void)
size_t actual; size_t actual;
BH_IO *io; BH_IO *io;
BH_VERIFY((io = BH_FileNew(FILENAME1)) != NULL); BH_VERIFY((io = BH_FileNew(FILENAME1, BH_FILE_READ, NULL)) != 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(BH_IOWrite(io, "12345", 5, &actual) != BH_OK); 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_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); BH_IOFree(io);
return 0; return 0;
@@ -551,10 +468,7 @@ static int checkPeek(void)
size_t actual; size_t actual;
BH_IO *io; BH_IO *io;
BH_VERIFY((io = BH_FileNew(FILENAME1)) != NULL); BH_VERIFY((io = BH_FileNew(FILENAME1, BH_FILE_READWRITE | BH_FILE_TRUNCATE, NULL)) != 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(BH_IOWrite(io, "1234567890", 10, &actual) == BH_OK); BH_VERIFY(BH_IOWrite(io, "1234567890", 10, &actual) == BH_OK);
BH_VERIFY(actual == 10); BH_VERIFY(actual == 10);
@@ -578,7 +492,6 @@ static int checkPeek(void)
BH_VERIFY(memcmp(buffer, "12345678901234567890", 20) == 0); BH_VERIFY(memcmp(buffer, "12345678901234567890", 20) == 0);
BH_VERIFY(previous == current); BH_VERIFY(previous == current);
BH_IOClose(io);
BH_IOFree(io); BH_IOFree(io);
return 0; return 0;
@@ -593,14 +506,11 @@ static int checkSize(void)
BH_IO *io; BH_IO *io;
int64_t size; int64_t size;
BH_VERIFY((io = BH_FileNew(FILENAME1)) != NULL); BH_VERIFY((io = BH_FileNew(FILENAME1, BH_FILE_READ, NULL)) != NULL);
BH_VERIFY(strcmp(BH_IOClassname(io), BH_FILE_CLASSNAME) == 0);
BH_VERIFY(BH_IOOpen(io, BH_IO_READ) == BH_OK);
BH_VERIFY(BH_IOSize(io, &size) == BH_OK); BH_VERIFY(BH_IOSize(io, &size) == BH_OK);
BH_VERIFY(size == 20); BH_VERIFY(size == 20);
BH_IOClose(io);
BH_IOFree(io); BH_IOFree(io);
return 0; return 0;
} }