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