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
src/Algo.c
src/Args.c
src/Buffer.c
src/Bytes.c
src/Hashmap.c
src/IO.c
src/Math/Box2f.c

View File

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

View File

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

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 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);

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 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]);
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;
}

View File

@@ -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))

View File

@@ -5,130 +5,139 @@
#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_FILE_CLASSNAME "BH_File"
#define BH_IO_FLAG_OK 0x0000
#define BH_IO_FLAG_ERROR 0x0001
#define BH_IO_FLAG_EOF 0x0002
typedef struct BH_IO BH_IO;
typedef int (*BH_IOCallback)(void *, int ,void *, void *);
#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 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
*
* \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 device IO device pointer
* \param buffer Buffer pointer
* \param size Buffer size
* \param actual Bytes read (optional)
@@ -136,16 +145,16 @@ int BH_IOClose(BH_IO *io);
* \return On success, returns zero.
* \return On failure, returns error code.
*/
int BH_IORead(BH_IO *io,
int BH_IORead(BH_IO *device,
char *buffer,
size_t size,
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 size Buffer size
* \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 size Buffer size
* \param actial Bytes peeked (optional)
@@ -170,83 +207,106 @@ int BH_IOWrite(BH_IO *io,
* \return On success, returns zero.
* \return On failure, returns error code.
*/
int BH_IOPeek(BH_IO *io,
int BH_IOPeek(BH_IO *device,
char *buffer,
size_t size,
size_t *actual);
/**
* Tells current \a position in the \a io.
* Tells current \a offset in the \a device.
*
* \param io IO pointer
* \param position Position
* \param device IO device pointer
* \param offset Position
*
* \return On success, returns zero.
* \return On failure, returns error code.
*/
int BH_IOTell(BH_IO *io,
int64_t *position);
int BH_IOTell(BH_IO *device,
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 position Position
* \param direction Direction
* \param device IO device pointer
* \param offset Position
* \param whence Direction
*
* \return On success, returns zero.
* \return On failure, returns error code.
*/
int BH_IOSeek(BH_IO *io,
int64_t position,
int direction);
int BH_IOSeek(BH_IO *device,
int64_t offset,
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 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 size Available/total size
* \param device IO pointer
* \param size Available/total size
*
* \return On success, returns zero.
* \return On failure, returns error code.
*/
int BH_IOSize(BH_IO *io,
int BH_IOSize(BH_IO *device,
int64_t *size);
/**
* Returns flags of the \a io.
* Returns flags of the \a device.
*
* \param io IO pointer
*
* \return Flags of the IO
*/
int BH_IOFlags(BH_IO *io);
/**
* Clears errors of the \a io.
*
* \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_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 */

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 *))
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)
{
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,
int BH_IORead(BH_IO *device,
char *buffer,
size_t size,
size_t *actual)
{
int code;
BH_IOReadInfo 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.data = buffer;
info.size = size;
info.actual = actual;
return device->callback(device, BH_IO_OP_READ, &info);
}
int BH_IOWrite(BH_IO *io,
int BH_IOWrite(BH_IO *device,
const char *buffer,
size_t size,
size_t *actual)
{
int code;
BH_IOWriteInfo info;
/* 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);
info.data = buffer;
info.size = size;
info.actual = actual;
/* If caller wants to know actual written size - report it back */
if (actual)
*actual = size;
return code;
return device->callback(device, BH_IO_OP_WRITE, &info);
}
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,
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;
/* Call the IO device peek handler */
code = io->cb(io + 1, BH_IO_PEEK_CB, (void *)buffer, &size);
if (BH_IOCap(device, BH_IO_CTL_PEEK))
{
if (BH_IOCap(device, BH_IO_CTL_SEEK))
return BH_NOIMPL;
/* If caller wants to know actual written size - report it back */
if (actual)
*actual = size;
if (BH_IORead(device, buffer, size, &readed))
return BH_ERROR;
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,
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_IOCtl(device, BH_IO_CTL_SIZE, size);
}
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;
/* Call the IO device size handler */
return io->cb(io + 1, BH_IO_SIZE_CB, size, NULL);
return flags & BH_IO_FLAG_ERROR;
}
int BH_IOFlags(BH_IO *io)
int BH_IOEndOfFile(BH_IO *device)
{
/* Prevent working with NULL io */
if (!io)
return BH_IO_FLAG_ERROR;
int flags;
/* Call the IO device flags handler */
return io->cb(io + 1, BH_IO_FLAGS_CB, NULL, NULL);
}
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;
if (BH_IOFlags(device, &flags))
return BH_ERROR;
return flags & BH_IO_FLAG_EOF;
}

View File

@@ -1,200 +1,15 @@
#include <BH/IO.h>
typedef struct BH_File
BH_IO *BH_FileNew(const char *path,
int mode,
int *result)
{
int implement;
int me;
} BH_File;
BH_UNUSED(path);
BH_UNUSED(mode);
if (result)
*result = BH_NOIMPL;
static int BH_FileInfo(BH_File *file,
size_t *size,
const char **name);
static int BH_FileInit(BH_File *file,
const char *path);
static int BH_FileDestroy(BH_File *file);
static int BH_FileOpen(BH_File *file,
int *mode);
static int BH_FileClose(BH_File *file);
static int BH_FileRead(BH_File *file,
char *data,
size_t *size);
static int BH_FileWrite(BH_File *file,
const char *data,
size_t *size);
static int BH_FilePeek(BH_File* file,
char *data,
size_t *size);
static int BH_FileFlush(BH_File *file);
static int BH_FileSeek(BH_File *file,
int64_t *pos,
int *dir);
static int BH_FileTell(BH_File *file,
int64_t *pos);
static int BH_FileSize(BH_File *file,
int64_t *size);
static int BH_FileFlags(BH_File *file);
static int BH_FileClear(BH_File *file);
static int BH_FileInfo(BH_File *file,
size_t *size,
const char **name)
{
static const char classname[] = BH_FILE_CLASSNAME;
if (size)
*size = sizeof(*file);
if (name)
*name = classname;
return BH_NOIMPL;
}
static int BH_FileInit(BH_File *file,
const char *path)
{
return BH_NOIMPL;
}
static int BH_FileDestroy(BH_File *file)
{
return BH_NOIMPL;
}
static int BH_FileOpen(BH_File *file,
int *mode)
{
return BH_NOIMPL;
}
static int BH_FileClose(BH_File *file)
{
return BH_NOIMPL;
}
static int BH_FileRead(BH_File *file,
char *data,
size_t *size)
{
return BH_NOIMPL;
}
static int BH_FileWrite(BH_File *file,
const char *data,
size_t *size)
{
return BH_NOIMPL;
}
static int BH_FilePeek(BH_File *file,
char *data,
size_t *size)
{
return BH_NOIMPL;
}
static int BH_FileFlush(BH_File *file)
{
return BH_NOIMPL;
}
static int BH_FileSeek(BH_File *file,
int64_t *pos,
int *dir)
{
return BH_NOIMPL;
}
static int BH_FileTell(BH_File *file,
int64_t *pos)
{
return BH_NOIMPL;
}
static int BH_FileSize(BH_File *file,
int64_t *size)
{
return BH_NOIMPL;
}
static int BH_FileFlags(BH_File *file)
{
return BH_IO_FLAG_ERROR;
}
static int BH_FileClear(BH_File *file)
{
return BH_NOIMPL;
}
static int BH_FileCallback(BH_File *file,
int type,
void *arg1,
void *arg2)
{
switch (type)
{
case BH_IO_INFO_CB: return BH_FileInfo(file, (size_t *)arg1, (const char **)arg2);
case BH_IO_INIT_CB: return BH_FileInit(file, (const char *)arg1);
case BH_IO_DESTROY_CB: return BH_FileDestroy(file);
case BH_IO_OPEN_CB: return BH_FileOpen(file, (int *)arg1);
case BH_IO_CLOSE_CB: return BH_FileClose(file);
case BH_IO_READ_CB: return BH_FileRead(file, (char *)arg1, (size_t *)arg2);
case BH_IO_WRITE_CB: return BH_FileWrite(file, (const char *)arg1, (size_t *)arg2);
case BH_IO_PEEK_CB: return BH_FilePeek(file, (char *)arg1, (size_t *)arg2);
case BH_IO_FLUSH_CB: return BH_FileFlush(file);
case BH_IO_SEEK_CB: return BH_FileSeek(file, (int64_t *)arg1, (int *)arg2);
case BH_IO_TELL_CB: return BH_FileTell(file, (int64_t *)arg1);
case BH_IO_SIZE_CB: return BH_FileSize(file, (int64_t *)arg1);
case BH_IO_FLAGS_CB: return BH_FileFlags(file);
case BH_IO_CLEAR_CB: return BH_FileClear(file);
default: return BH_NOIMPL;
}
}
BH_IO *BH_FileNew(const char *path)
{
return BH_IONew((BH_IOCallback)BH_FileCallback, (void *)path);
return NULL;
}

View File

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

View File

@@ -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;
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 */
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)
static int fileFlush(BH_File *file)
{
int64_t position;
int direction;
/* Read data from the file */
if (BH_FileRead(file, data, size))
return BH_ERROR;
/* Backtrack by the read amount */
position = -((int64_t)*size);
direction = BH_IO_SEEK_CUR;
if (BH_FileSeek(file, &position, &direction))
return BH_ERROR;
return BH_OK;
}
static int BH_FileFlush(BH_File *file)
{
/* Check if file is opened */
if (file->handle == INVALID_HANDLE_VALUE)
goto error;
/* Flush OS buffers */
FlushFileBuffers(file->handle);
return BH_OK;
error:
file->flags |= BH_IO_FLAG_ERROR;
return BH_ERROR;
}
static int BH_FileSeek(BH_File *file,
int64_t *pos,
int *dir)
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;
}

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)
{
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;
}