aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/bh/buffer.h32
-rw-r--r--include/bh/file.h35
-rw-r--r--include/bh/internal/buffer.h34
-rw-r--r--include/bh/internal/file.h34
-rw-r--r--include/bh/internal/io.h6
-rw-r--r--include/bh/io.h26
-rw-r--r--src/buffer.c14
-rw-r--r--src/file_null.c15
-rw-r--r--src/file_posix.c15
-rw-r--r--src/file_win.c16
-rw-r--r--src/io.c425
11 files changed, 524 insertions, 128 deletions
diff --git a/include/bh/buffer.h b/include/bh/buffer.h
index b3a891f..da758e2 100644
--- a/include/bh/buffer.h
+++ b/include/bh/buffer.h
@@ -8,8 +8,6 @@ typedef struct bh_buffer_s bh_buffer_t;
bh_buffer_t *bh_buffer_new(void);
-void bh_buffer_free(bh_buffer_t *buffer);
-
const char *bh_buffer_data(bh_buffer_t *buffer);
void bh_buffer_set_data(bh_buffer_t *buffer,
@@ -21,34 +19,8 @@ size_t bh_buffer_capacity(bh_buffer_t *buffer);
int bh_buffer_reserve(bh_buffer_t *buffer,
size_t size);
-int bh_buffer_open_base(bh_buffer_t *buffer,
- int mode);
-
-void bh_buffer_close_base(bh_buffer_t *buffer);
-
-int bh_buffer_is_open_base(bh_buffer_t *buffer);
-
-size_t bh_buffer_read_base(bh_buffer_t *buffer,
- char *data,
- size_t size);
-
-size_t bh_buffer_write_base(bh_buffer_t *buffer,
- const char *data,
- size_t size);
-
-void bh_buffer_flush_base(bh_buffer_t *buffer);
-
-int bh_buffer_seek_base(bh_buffer_t *buffer,
- bh_off_t pos,
- int dir);
-
-bh_off_t bh_buffer_size_base(bh_buffer_t *buffer);
-
-bh_off_t bh_buffer_tell_base(bh_buffer_t *buffer);
-
-bh_off_t bh_buffer_available_base(bh_buffer_t *buffer);
-
-void bh_buffer_clear_base(bh_buffer_t *buffer);
+#define bh_buffer_free(buffer) \
+ bh_io_free((bh_io_t *)(buffer))
#define bh_buffer_open(buffer, mode) \
bh_io_open((bh_io_t *)(buffer), (mode))
diff --git a/include/bh/file.h b/include/bh/file.h
index 8a0d3b1..304eb55 100644
--- a/include/bh/file.h
+++ b/include/bh/file.h
@@ -8,36 +8,8 @@ typedef struct bh_file_s bh_file_t;
bh_file_t *bh_file_new(const char *path);
-void bh_file_free(bh_file_t *file);
-
-int bh_file_open_base(bh_file_t *file,
- int mode);
-
-void bh_file_close_base(bh_file_t *file);
-
-int bh_file_is_open_base(bh_file_t *file);
-
-size_t bh_file_read_base(bh_file_t *file,
- char *data,
- size_t size);
-
-size_t bh_file_write_base(bh_file_t *file,
- const char *data,
- size_t size);
-
-void bh_file_flush_base(bh_file_t *file);
-
-int bh_file_seek_base(bh_file_t *file,
- bh_off_t pos,
- int dir);
-
-bh_off_t bh_file_size_base(bh_file_t *file);
-
-bh_off_t bh_file_tell_base(bh_file_t *file);
-
-bh_off_t bh_file_available_base(bh_file_t *file);
-
-void bh_file_clear_base(bh_file_t *file);
+#define bh_file_free(file) \
+ bh_io_free((bh_io_t *)(file))
#define bh_file_open(file, mode) \
bh_io_open((bh_io_t *)(file), (mode))
@@ -51,6 +23,9 @@ void bh_file_clear_base(bh_file_t *file);
#define bh_file_read(file, data, size) \
bh_io_read((bh_io_t *)(file), (data), (size))
+#define bh_file_peek(file, data, size) \
+ bh_io_peek((bh_io_t *)(file), (data), (size))
+
#define bh_file_write(file, data, size) \
bh_io_write((bh_io_t *)(file), (data), (size))
diff --git a/include/bh/internal/buffer.h b/include/bh/internal/buffer.h
index 4e232d8..96b295e 100644
--- a/include/bh/internal/buffer.h
+++ b/include/bh/internal/buffer.h
@@ -16,6 +16,38 @@ struct bh_buffer_s
int bh_buffer_init(bh_buffer_t *buffer);
-void bh_buffer_destroy(bh_buffer_t *buffer);
+#define bh_buffer_destroy(buffer) \
+ bh_io_destroy((bh_io_t *)(buffer))
+
+void bh_buffer_destroy_base(bh_buffer_t *buffer);
+
+int bh_buffer_open_base(bh_buffer_t *buffer,
+ int mode);
+
+void bh_buffer_close_base(bh_buffer_t *buffer);
+
+int bh_buffer_is_open_base(bh_buffer_t *buffer);
+
+size_t bh_buffer_read_base(bh_buffer_t *buffer,
+ char *data,
+ size_t size);
+
+size_t bh_buffer_write_base(bh_buffer_t *buffer,
+ const char *data,
+ size_t size);
+
+void bh_buffer_flush_base(bh_buffer_t *buffer);
+
+int bh_buffer_seek_base(bh_buffer_t *buffer,
+ bh_off_t pos,
+ int dir);
+
+bh_off_t bh_buffer_size_base(bh_buffer_t *buffer);
+
+bh_off_t bh_buffer_tell_base(bh_buffer_t *buffer);
+
+bh_off_t bh_buffer_available_base(bh_buffer_t *buffer);
+
+void bh_buffer_clear_base(bh_buffer_t *buffer);
#endif /* BH_INTERNAL_BUFFER_H */
diff --git a/include/bh/internal/file.h b/include/bh/internal/file.h
index 1e9fed0..20c6c31 100644
--- a/include/bh/internal/file.h
+++ b/include/bh/internal/file.h
@@ -16,6 +16,38 @@
int bh_file_init(bh_file_t *file,
const char *path);
-void bh_file_destroy(bh_file_t *file);
+#define bh_file_destroy(file) \
+ bh_io_destroy((bh_io_t *)(file))
+
+void bh_file_destroy_base(bh_file_t *file);
+
+int bh_file_open_base(bh_file_t *file,
+ int mode);
+
+void bh_file_close_base(bh_file_t *file);
+
+int bh_file_is_open_base(bh_file_t *file);
+
+size_t bh_file_read_base(bh_file_t *file,
+ char *data,
+ size_t size);
+
+size_t bh_file_write_base(bh_file_t *file,
+ const char *data,
+ size_t size);
+
+void bh_file_flush_base(bh_file_t *file);
+
+int bh_file_seek_base(bh_file_t *file,
+ bh_off_t pos,
+ int dir);
+
+bh_off_t bh_file_size_base(bh_file_t *file);
+
+bh_off_t bh_file_tell_base(bh_file_t *file);
+
+bh_off_t bh_file_available_base(bh_file_t *file);
+
+void bh_file_clear_base(bh_file_t *file);
#endif /* BH_INTERNAL_FILE_H */
diff --git a/include/bh/internal/io.h b/include/bh/internal/io.h
index d0be93b..c840703 100644
--- a/include/bh/internal/io.h
+++ b/include/bh/internal/io.h
@@ -4,10 +4,4 @@
#include "bh.h"
#include <bh/io.h>
-void bh_io_init(bh_io_t *io,
- const bh_io_table_t *table);
-
-void bh_io_destroy(bh_io_t *io);
-
#endif /* BH_INTERNAL_IO_H */
-
diff --git a/include/bh/io.h b/include/bh/io.h
index cee0834..f44fce7 100644
--- a/include/bh/io.h
+++ b/include/bh/io.h
@@ -5,6 +5,7 @@
#define BH_IO_ERROR 0x0001
#define BH_IO_EOF 0x0002
+#define BH_IO_UNIFIED 0x0004
#define BH_IO_NONE 0x0000
#define BH_IO_READ 0x0001
@@ -63,13 +64,30 @@ typedef struct bh_io_s
{
const bh_io_table_t *table;
int flags;
+ struct
+ {
+ char *data;
+ size_t head;
+ size_t tail;
+ size_t size;
+ size_t capacity;
+ } buffer;
} bh_io_t;
-bh_io_t *bh_io_new(bh_io_table_t *table,
- size_t size);
+void bh_io_destroy_base(bh_io_t *io);
+
+bh_io_t *bh_io_new(const bh_io_table_t *table,
+ size_t size,
+ int unified);
void bh_io_free(bh_io_t *io);
+void bh_io_init(bh_io_t *io,
+ const bh_io_table_t *table,
+ int unified);
+
+void bh_io_destroy(bh_io_t *io);
+
int bh_io_open(bh_io_t *io,
int mode);
@@ -81,6 +99,9 @@ size_t bh_io_read(bh_io_t *io,
char *data,
size_t size);
+size_t bh_io_peek(bh_io_t *io,
+ char *data,
+ size_t size);
size_t bh_io_write(bh_io_t *io,
const char* data,
@@ -97,7 +118,6 @@ bh_off_t bh_io_size(bh_io_t *io);
bh_off_t bh_io_tell(bh_io_t *io);
-
bh_off_t bh_io_available(bh_io_t *io);
int bh_io_error(bh_io_t *io);
diff --git a/src/buffer.c b/src/buffer.c
index 3e5c062..58a1e82 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -15,7 +15,7 @@ static const bh_io_table_t bh_buffer_table = {
(bh_off_t (*)(struct bh_io_s *)) bh_buffer_tell_base,
(bh_off_t (*)(struct bh_io_s *)) bh_buffer_available_base,
(void (*)(struct bh_io_s *)) bh_buffer_clear_base,
- (void (*)(struct bh_io_s *)) bh_buffer_destroy
+ (void (*)(struct bh_io_s *)) bh_buffer_destroy_base
};
bh_buffer_t *bh_buffer_new(void)
@@ -34,17 +34,10 @@ bh_buffer_t *bh_buffer_new(void)
return result;
}
-void bh_buffer_free(bh_buffer_t *buffer)
-{
- /* Destroy buffer and free the memory */
- bh_buffer_destroy(buffer);
- free(buffer);
-}
-
int bh_buffer_init(bh_buffer_t *buffer)
{
/* Initialize underlying io object */
- bh_io_init(&buffer->base, &bh_buffer_table);
+ bh_io_init(&buffer->base, &bh_buffer_table, 1);
/* Setup internal information */
buffer->data = NULL;
@@ -56,12 +49,13 @@ int bh_buffer_init(bh_buffer_t *buffer)
return BH_OK;
}
-void bh_buffer_destroy(bh_buffer_t *buffer)
+void bh_buffer_destroy_base(bh_buffer_t *buffer)
{
/* Close the buffer and free allocated memory */
bh_buffer_close(buffer);
if (buffer->data)
free(buffer->data);
+ bh_io_destroy_base(&buffer->base);
}
const char *bh_buffer_data(bh_buffer_t *buffer)
diff --git a/src/file_null.c b/src/file_null.c
index 75684d8..ac2cfe4 100644
--- a/src/file_null.c
+++ b/src/file_null.c
@@ -22,19 +22,6 @@ bh_file_t *bh_file_new(const char *path)
}
/**
- * Frees the \a file object.
- *
- * Before freeing the file object, this function ensures that underlying file
- * was closed.
- *
- * \param file Pointer to the file object
- */
-void bh_file_free(bh_file_t *file)
-{
- (void)file;
-}
-
-/**
* Initializes the \a file object with specified \a path to file.
*
* \param file Pointer to the file object
@@ -59,7 +46,7 @@ int bh_file_init(bh_file_t *file,
*
* \param file Pointer to the file object
*/
-void bh_file_destroy(bh_file_t *file)
+void bh_file_destroy_base(bh_file_t *file)
{
(void)file;
}
diff --git a/src/file_posix.c b/src/file_posix.c
index e6915a5..9b61c01 100644
--- a/src/file_posix.c
+++ b/src/file_posix.c
@@ -19,7 +19,7 @@ static const bh_io_table_t bh_file_table = {
(bh_off_t (*)(struct bh_io_s *)) bh_file_tell_base,
(bh_off_t (*)(struct bh_io_s *)) bh_file_available_base,
(void (*)(struct bh_io_s *)) bh_file_clear_base,
- (void (*)(struct bh_io_s *)) bh_file_destroy
+ (void (*)(struct bh_io_s *)) bh_file_destroy_base
};
bh_file_t *bh_file_new(const char *path)
@@ -38,12 +38,6 @@ bh_file_t *bh_file_new(const char *path)
return result;
}
-void bh_file_free(bh_file_t *file)
-{
- bh_file_destroy(file);
- free(file);
-}
-
int bh_file_init(bh_file_t *file,
const char *path)
{
@@ -51,8 +45,8 @@ int bh_file_init(bh_file_t *file,
if (!path)
return BH_INVALID;
- /* Initialize base io object */
- bh_io_init(&file->base, &bh_file_table);
+ /* Initialize underlying io object */
+ bh_io_init(&file->base, &bh_file_table, 1);
/* Initialize file io object */
file->handle = -1;
@@ -62,11 +56,12 @@ int bh_file_init(bh_file_t *file,
return BH_OK;
}
-void bh_file_destroy(bh_file_t *file)
+void bh_file_destroy_base(bh_file_t *file)
{
/* Close the file */
bh_file_close(file);
free(file->path);
+ bh_io_destroy_base(&file->base);
}
int bh_file_open_base(bh_file_t *file,
diff --git a/src/file_win.c b/src/file_win.c
index 15d2a61..b4c4730 100644
--- a/src/file_win.c
+++ b/src/file_win.c
@@ -12,7 +12,7 @@ static const bh_io_table_t bh_file_table = {
(bh_off_t (*)(struct bh_io_s *)) bh_file_tell_base,
(bh_off_t (*)(struct bh_io_s *)) bh_file_available_base,
(void (*)(struct bh_io_s *)) bh_file_clear_base,
- (void (*)(struct bh_io_s *)) bh_file_destroy
+ (void (*)(struct bh_io_s *)) bh_file_destroy_base
};
bh_file_t *bh_file_new(const char *path)
@@ -31,13 +31,6 @@ bh_file_t *bh_file_new(const char *path)
return result;
}
-void bh_file_free(bh_file_t *file)
-{
- /* Destroy file object and free allocated memory */
- bh_file_destroy(file);
- free(file);
-}
-
int bh_file_init(bh_file_t *file,
const char *path)
{
@@ -45,20 +38,23 @@ int bh_file_init(bh_file_t *file,
if (!path)
return BH_INVALID;
+ /* Initialize underlying io object */
+ bh_io_init(&file->base, &bh_file_table, 1);
+
/* Fill file structure information */
file->handle = INVALID_HANDLE_VALUE;
file->mode = BH_IO_NONE;
file->path = strdup(path);
- file->base.table = &bh_file_table;
return BH_OK;
}
-void bh_file_destroy(bh_file_t *file)
+void bh_file_destroy_base(bh_file_t *file)
{
/* Close the file and free allocated memory */
bh_file_close(file);
free(file->path);
+ bh_io_destroy_base(&file->base);
}
int bh_file_open_base(bh_file_t *file,
diff --git a/src/io.c b/src/io.c
index 5e94f35..3e18e4a 100644
--- a/src/io.c
+++ b/src/io.c
@@ -1,5 +1,8 @@
#include <bh/internal/io.h>
#include <stdlib.h>
+#include <string.h>
+
+#define BH_IO_BUFFER_STEP 256
/**
* \defgroup io Input/Output
@@ -9,10 +12,338 @@
*/
/**
+ * \internal
+ * Returns pointer to the \a io peek buffer.
+ *
+ * \param io Pointer to the io object
+ *
+ * \return Pointer to the peek buffer.
+ *
+ * \warning Always use this function to get data of the buffer!
+ */
+static char *bh_io_buffer_data(bh_io_t *io)
+{
+ if (io->buffer.capacity)
+ return io->buffer.data;
+
+ return (char *)&io->buffer.data;
+}
+
+/**
+ * \internal
+ * Returns peek buffer capacity of the /a io object.
+ *
+ * \param io Pointer to the io object
+ *
+ * \return Peek buffer capacity.
+ *
+ * \warning Always use this function to get capacity of the buffer!
+ */
+static size_t bh_io_buffer_capacity(bh_io_t *io)
+{
+ if (io->buffer.capacity)
+ return io->buffer.capacity;
+ return sizeof(char *);
+}
+
+/**
+ * \internal
+ * Reduces the capacity of the \a io object peek buffer.
+ *
+ * \param io Pointer to the io object.
+ *
+ * \note This function does not guarantee that the capacity of the buffer will
+ * actually be reduced.
+ */
+static void bh_io_buffer_shrink(bh_io_t *io)
+{
+ size_t capacity;
+ char *data;
+
+ /* Check if buffer is allocated */
+ if (!io->buffer.capacity)
+ return;
+
+ /* Calculate new capacity and check against old capacity */
+ capacity = (io->buffer.size + BH_IO_BUFFER_STEP - 1) / BH_IO_BUFFER_STEP;
+ capacity *= BH_IO_BUFFER_STEP;
+ if (io->buffer.capacity >= capacity)
+ return;
+
+ /* Allocate new buffer space */
+ data = malloc(capacity);
+ if (!data)
+ return;
+
+ /* Copy data */
+ if (io->buffer.size)
+ {
+ size_t block;
+
+ /* Depending on the tail-head positions copy data in two or one go */
+ if (io->buffer.tail <= io->buffer.head)
+ {
+ block = io->buffer.capacity - io->buffer.head;
+ memmove(data, io->buffer.data + io->buffer.head, block);
+ memmove(data + block, io->buffer.data, io->buffer.size - block);
+ }
+ else
+ {
+ block = io->buffer.size;
+ memmove(data, io->buffer.data + io->buffer.head, block);
+ }
+ }
+
+ /* Update fields */
+ free(io->buffer.data);
+ io->buffer.data = data;
+ io->buffer.head = 0;
+ io->buffer.tail = io->buffer.size;
+ io->buffer.capacity = capacity;
+ if (io->buffer.tail >= capacity)
+ io->buffer.tail = 0;
+}
+
+/**
+ * \internal
+ * Reserves the capacity of the \a io object peek buffer.
+ *
+ * \param io Pointer to the io object
+ * \param size New peek buffer capacity
+ *
+ * \return On success, returns zero value.
+ * \return On failure, returns error code.
+ */
+static int bh_io_buffer_reserve(bh_io_t *io,
+ size_t size)
+{
+ size_t capacity;
+ char *data;
+
+ /* Check if entire buffer can fit into a pointer */
+ if (size <= sizeof(char *))
+ return BH_OK;
+
+ /* Check that size can fit into a buffer */
+ if (io->buffer.capacity >= size)
+ return BH_OK;
+
+ /* Calculate new buffer capacity */
+ capacity = (size + BH_IO_BUFFER_STEP - 1) / BH_IO_BUFFER_STEP;
+ capacity *= BH_IO_BUFFER_STEP;
+
+ /* Allocate new buffer space */
+ data = malloc(capacity);
+ if (!data)
+ return BH_OOM;
+
+ /* Copy data */
+ if (io->buffer.size)
+ {
+ size_t block;
+
+ /* Depending on the tail-head positions copy data in two or one go */
+ if (io->buffer.tail <= io->buffer.head)
+ {
+ block = io->buffer.capacity - io->buffer.head;
+ memmove(data, bh_io_buffer_data(io) + io->buffer.head, block);
+ memmove(data + block, bh_io_buffer_data(io), io->buffer.size - block);
+ }
+ else
+ {
+ block = io->buffer.size;
+ memmove(data, bh_io_buffer_data(io) + io->buffer.head, block);
+ }
+ }
+
+ /* Update fields */
+ if (io->buffer.capacity)
+ free(io->buffer.data);
+ io->buffer.data = data;
+ io->buffer.head = 0;
+ io->buffer.tail = io->buffer.size;
+ io->buffer.capacity = capacity;
+ if (io->buffer.tail >= capacity)
+ io->buffer.tail = 0;
+
+ return BH_OK;
+}
+
+/**
+ * \internal
+ * Reads data from the \a io peek buffer.
+ *
+ * \param io Pointer to the io object
+ * \param data Pointer to the memory buffer
+ * \param size Maximum number of bytes to be read
+ * \param peek Reading or peeking flag
+ *
+ * \return On success, returns number of bytes successfuly read.
+ * \return On failure, returns zero.
+ */
+static size_t bh_io_buffer_read(bh_io_t *io,
+ char *data,
+ size_t size,
+ int peek)
+{
+ size_t block;
+
+ /* Check if buffer is empty */
+ if (!io->buffer.size)
+ return 0;
+
+ /* Reading size can't be bigger then buffer size */
+ if (size > io->buffer.size)
+ size = io->buffer.size;
+
+ /* Copy data */
+ if (data)
+ {
+ /* Depending on the tail-head positions copy data in two or one go */
+ if (io->buffer.tail <= io->buffer.head)
+ {
+ block = bh_io_buffer_capacity(io) - io->buffer.head;
+ if (block > size)
+ block = size;
+ memmove(data, bh_io_buffer_data(io) + io->buffer.head, block);
+ memmove(data + block, bh_io_buffer_data(io), size - block);
+ }
+ else
+ {
+ block = size;
+ memmove(data, bh_io_buffer_data(io) + io->buffer.head, block);
+ }
+ }
+
+ /* Adjust head position and size if we are not peeking */
+ if (!peek)
+ {
+ io->buffer.head += size;
+ io->buffer.size -= size;
+
+ if (io->buffer.head >= bh_io_buffer_capacity(io))
+ io->buffer.head -= bh_io_buffer_capacity(io);
+
+ /* Shrink buffer if neccesary*/
+ bh_io_buffer_shrink(io);
+ }
+
+ /* Return readed size */
+ return size;
+}
+
+/**
+ * \internal
+ * Writes data to the \a io peek buffer.
+ *
+ * \param io Pointer to the io object
+ * \param data Pointer to the memory buffer
+ * \param size Maximum number of bytes to be read
+ *
+ * \return On success, returns number of bytes successfuly written.
+ * \return On failure, returns zero.
+ */
+static size_t bh_io_buffer_write(bh_io_t *io,
+ const char *data,
+ size_t size)
+{
+ size_t block;
+
+ /* Reserve capacity in the buffer */
+ if (bh_io_buffer_reserve(io, io->buffer.size + size))
+ return 0;
+
+ /* Depending on the tail-head positions copy data in two or one go */
+ if (io->buffer.tail + size > bh_io_buffer_capacity(io))
+ {
+ block = io->buffer.capacity - io->buffer.tail;
+ memmove(bh_io_buffer_data(io) + io->buffer.tail, data, block);
+ memmove(bh_io_buffer_data(io), data + block, size - block);
+ }
+ else
+ {
+ block = size;
+ memmove(bh_io_buffer_data(io) + io->buffer.tail, data, block);
+ }
+
+ /* Adjust tail and size */
+ io->buffer.tail += size;
+ io->buffer.size += size;
+
+ if (io->buffer.tail >= bh_io_buffer_capacity(io))
+ io->buffer.tail -= bh_io_buffer_capacity(io);
+
+ return size;
+}
+
+/**
+ * \internal
+ * Adjusts \a io object peek buffer according to the specified seek direction
+ * \a dir and \a offset.
+ *
+ * \param io Pointer to the io object
+ * \param offset Number of bytes to seek in specified direciton
+ * \param dir Seeking direction
+ *
+ * \return Returns new offset for the io seek function.
+ */
+static bh_off_t bh_io_buffer_seek(bh_io_t *io,
+ bh_off_t offset,
+ int dir)
+{
+ /* Check if seek is relative to current position */
+ if (dir != BH_IO_CURRENT)
+ {
+ /* It's not - reset peek buffer and return offset as is */
+ io->buffer.size = 0;
+ io->buffer.head = 0;
+ io->buffer.tail = 0;
+ return offset;
+ }
+
+ /* If offset is negative or past peek buffer size */
+ if (offset < 0 || offset >= (bh_off_t)io->buffer.size)
+ {
+ /* It's not - reset peek buffer and adjust offset position */
+ offset -= io->buffer.size;
+ io->buffer.size = 0;
+ io->buffer.head = 0;
+ io->buffer.tail = 0;
+ return offset;
+ }
+
+ /* Skip offset amount of bytes */
+ bh_io_buffer_read(io, NULL, offset, 0);
+ return 0;
+}
+
+/**
+ * Destroys base io object.
+ *
+ * \param io Pointer to the base io object
+ *
+ * \warning This function should be used in context of implementing child
+ * io objects (files, sockets, streaming compression, etc).
+ */
+void bh_io_destroy_base(bh_io_t *io)
+{
+ if (io->buffer.capacity)
+ free(io->buffer.data);
+}
+
+/**
* Creates the new io object with specified \a table and \a size.
*
- * \param table Pointer to the io table
- * \param size Size of the io object
+ * The \a unified flag specifies the behaivor of the internal peek buffer.
+ * If the \a unified flag is set - the io object will assume that read and
+ * write operations are dependant on each other (ex. writing to the file
+ * affects next read operation).
+ * If the \a unified flag is not set - the io object will asusme that read and
+ * write operations are independant.
+ *
+ * \param table Pointer to the io table
+ * \param size Size of the io object
+ * \param unified Unified read/write stream flag
*
* \return On success, returns new semi-initialized io object.
* \return On failure, returns null pointer.
@@ -20,14 +351,15 @@
* \warning This function should be used in context of implementing child
* io objects (files, sockets, streaming compression, etc).
*/
-bh_io_t *bh_io_new(bh_io_table_t *table,
- size_t size)
+bh_io_t *bh_io_new(const bh_io_table_t *table,
+ size_t size,
+ int unified)
{
bh_io_t *result;
result = malloc(size);
if (result)
- bh_io_init(result, table);
+ bh_io_init(result, table, unified);
return result;
}
@@ -46,14 +378,27 @@ void bh_io_free(bh_io_t *io)
/**
* Initializes the \a io object with specified \a table.
*
- * \param io Pointer to the io object to be initialized
- * \param table Pointer to the io table
+ * The \a unified flag specifies the behaivor of the internal peek buffer.
+ * If the \a unified flag is set - the io object will assume that read and
+ * write operations are dependant on each other (ex. writing to the file
+ * affects next read operation).
+ * If the \a unified flag is not set - the io object will asusme that read and
+ * write operations are independant.
+ *
+ * \param io Pointer to the io object to be initialized
+ * \param table Pointer to the io table
+ * \param unified Unified read/write stream flag
*/
void bh_io_init(bh_io_t *io,
- const bh_io_table_t *table)
+ const bh_io_table_t *table,
+ int unified)
{
io->table = table;
- io->flags = 0;
+ io->flags = (unified) ? (BH_IO_UNIFIED) : (0);
+ io->buffer.capacity = 0;
+ io->buffer.head = 0;
+ io->buffer.tail = 0;
+ io->buffer.size = 0;
}
/**
@@ -121,7 +466,50 @@ size_t bh_io_read(bh_io_t *io,
char *data,
size_t size)
{
- return io->table->read(io, data, size);
+
+ size_t result;
+
+ /* Read as much data from peek buffer as possible */
+ result = bh_io_buffer_read(io, data, size, 0);
+
+ /* If that wasn't enough read from the device */
+ if (result != size)
+ result += io->table->read(io, data + result, size - result);
+
+ /* Return amount of bytes read */
+ return result;
+}
+
+/**
+ * Peeks up to \a size amount of bytes from the \a io object into memory buffer
+ * pointed by \a data pointer.
+ *
+ * \param io Pointer to the io object
+ * \param data Pointer to the memory buffer
+ * \param size Maximum number of bytes to be read
+ *
+ * \return On success, returns number of bytes successfuly read.
+ * \return On failure, returns zero.
+ */
+size_t bh_io_peek(bh_io_t *io,
+ char *data,
+ size_t size)
+{
+ /* Fill peek buffer if it's size is less then requested */
+ if (io->buffer.size < size)
+ {
+ size_t read;
+
+ read = io->table->read(io, data, size - io->buffer.size);
+ bh_io_buffer_write(io, data, read);
+ }
+
+ /* Clear EOF flag if peek buffer is not empty */
+ if (io->buffer.size > 0)
+ io->flags &= ~BH_IO_EOF;
+
+ /* Read data from the peek buffer */
+ return bh_io_buffer_read(io, data, size, 1);
}
/**
@@ -138,9 +526,19 @@ size_t bh_io_read(bh_io_t *io,
* \note To check for error see bh_io_error.
*/
size_t bh_io_write(bh_io_t *io,
- const char* data,
+ const char *data,
size_t size)
{
+ /* Clear peek buffer and adjust the position if IO is unified */
+ if (io->buffer.size && (io->flags & BH_IO_UNIFIED))
+ {
+ io->table->seek(io, -(bh_off_t)io->buffer.size, BH_IO_CURRENT);
+ io->buffer.head = 0;
+ io->buffer.tail = 0;
+ io->buffer.size = 0;
+ }
+
+ /* Write data */
return io->table->write(io, data, size);
}
@@ -172,6 +570,7 @@ int bh_io_seek(bh_io_t *io,
bh_off_t offset,
int dir)
{
+ offset = bh_io_buffer_seek(io, offset, dir);
return io->table->seek(io, offset, dir);
}
@@ -198,7 +597,7 @@ bh_off_t bh_io_size(bh_io_t *io)
*/
bh_off_t bh_io_tell(bh_io_t *io)
{
- return io->table->tell(io);
+ return io->table->tell(io) - io->buffer.size;
}
/**
@@ -211,7 +610,7 @@ bh_off_t bh_io_tell(bh_io_t *io)
*/
bh_off_t bh_io_available(bh_io_t *io)
{
- return io->table->available(io);
+ return io->table->available(io) + io->buffer.size;
}
/**