diff --git a/fx/bytestream.c b/fx/bytestream.c new file mode 100644 index 0000000..44ccedf --- /dev/null +++ b/fx/bytestream.c @@ -0,0 +1,283 @@ +#include +#include +#include +#include + +#define DEFAULT_CAPACITY 128 + +/*** PRIVATE DATA *************************************************************/ + +struct fx_bytestream_p { + unsigned char *s_buf; + size_t s_ptr; + size_t s_len; + size_t s_max; + unsigned char s_alloc; +}; + +/*** PRIVATE FUNCTIONS ********************************************************/ + +static enum fx_status __gets( + struct fx_bytestream_p *s, + unsigned char *buf, + size_t len, + size_t *nr_read) +{ + size_t available = s->s_len - s->s_ptr; + size_t to_copy = len; + + if (available < to_copy) { + to_copy = available; + } + + memcpy(buf, s->s_buf + s->s_ptr, to_copy); + + s->s_ptr += to_copy; + + if (s->s_ptr == s->s_len) { + s->s_ptr = s->s_len = 0; + } + + if (nr_read) { + *nr_read = to_copy; + } + + return FX_SUCCESS; +} + +static enum fx_status __puts( + struct fx_bytestream_p *s, + const unsigned char *buf, + size_t len, + size_t *nr_written) +{ + size_t available = s->s_max - s->s_len; + size_t to_copy = len; + + if (to_copy > available && s->s_alloc == 1) { + unsigned char *new_buf + = realloc(s->s_buf, s->s_len + to_copy + 1); + if (!new_buf) { + return FX_ERR_NO_MEMORY; + } + + s->s_buf = new_buf; + s->s_max = s->s_len + to_copy; + available = s->s_max - s->s_len; + } + + if (available < to_copy) { + to_copy = available; + } + + memcpy(s->s_buf + s->s_len, buf, to_copy); + s->s_buf[s->s_len + to_copy] = 0; + + /* increment the length by the full byte length, even if only a + * portion was copied */ + s->s_len += len; + + if (nr_written) { + *nr_written = to_copy; + } + + return FX_SUCCESS; +} + +static enum fx_status bytestream_reset(struct fx_bytestream_p *s) +{ + s->s_len = 0; + + if (s->s_buf) { + *s->s_buf = 0; + } + + return FX_SUCCESS; +} + +static size_t bytestream_get_length(const struct fx_bytestream_p *strv) +{ + return strv->s_len; +} + +static const unsigned char *bytestream_get_ptr(const struct fx_bytestream_p *s) +{ + return s->s_buf; +} + +static unsigned char *bytestream_steal(struct fx_bytestream_p *s) +{ + unsigned char *out = s->s_buf; + + memset(s, 0x0, sizeof *s); + + s->s_alloc = 1; + + return out; +} + +/*** PUBLIC FUNCTIONS *********************************************************/ + +fx_bytestream *fx_bytestream_create_view(unsigned char *buf, size_t max) +{ + fx_bytestream *s = fx_object_create(FX_TYPE_BYTESTREAM); + if (!s) { + return NULL; + } + + fx_stream_cfg *cfg = fx_object_get_protected(s, FX_TYPE_STREAM); + struct fx_bytestream_p *p + = fx_object_get_private(s, FX_TYPE_BYTESTREAM); + + cfg->s_mode = FX_STREAM_READ | FX_STREAM_WRITE | FX_STREAM_BINARY + | Z__FX_STREAM_STATIC; + + p->s_buf = buf; + p->s_max = max; + p->s_len = max; + p->s_alloc = 0; + + return s; +} + +fx_bytestream *fx_bytestream_create_readonly_view( + const unsigned char *buf, + size_t max) +{ + fx_bytestream *s = fx_object_create(FX_TYPE_BYTESTREAM); + if (!s) { + return NULL; + } + + fx_stream_cfg *cfg = fx_object_get_protected(s, FX_TYPE_STREAM); + struct fx_bytestream_p *p + = fx_object_get_private(s, FX_TYPE_BYTESTREAM); + + cfg->s_mode = FX_STREAM_READ | FX_STREAM_BINARY | Z__FX_STREAM_STATIC; + + p->s_buf = (unsigned char *)buf; + p->s_max = max; + p->s_len = max; + p->s_alloc = 0; + + return s; +} + +fx_bytestream *fx_bytestream_create(void) +{ + fx_bytestream *s = fx_object_create(FX_TYPE_BYTESTREAM); + if (!s) { + return NULL; + } + + fx_stream_cfg *cfg = fx_object_get_protected(s, FX_TYPE_STREAM); + struct fx_bytestream_p *p + = fx_object_get_private(s, FX_TYPE_BYTESTREAM); + + cfg->s_mode = FX_STREAM_READ | FX_STREAM_WRITE | FX_STREAM_BINARY + | Z__FX_STREAM_STATIC; + + p->s_buf = malloc(DEFAULT_CAPACITY + 1); + if (!p->s_buf) { + fx_bytestream_unref(s); + return NULL; + } + + memset(p->s_buf, 0x0, DEFAULT_CAPACITY + 1); + p->s_max = DEFAULT_CAPACITY; + p->s_len = 0; + p->s_alloc = 1; + + return s; +} + +size_t fx_bytestream_get_length(const fx_bytestream *strv) +{ + FX_CLASS_DISPATCH_STATIC_0( + FX_TYPE_BYTESTREAM, + bytestream_get_length, + strv); +} + +enum fx_status fx_bytestream_reset(fx_bytestream *strv) +{ + FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_BYTESTREAM, bytestream_reset, strv); +} + +const unsigned char *fx_bytestream_get_ptr(const fx_bytestream *s) +{ + FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_BYTESTREAM, bytestream_get_ptr, s); +} + +unsigned char *fx_bytestream_steal(fx_bytestream *s) +{ + FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_BYTESTREAM, bytestream_steal, s); +} + +/*** VIRTUAL FUNCTIONS ********************************************************/ + +static void bytestream_init(fx_object *obj, void *priv) +{ + struct fx_bytestream_p *stream = priv; +} + +static void bytestream_fini(fx_object *obj, void *priv) +{ + struct fx_bytestream_p *stream = priv; + + if (stream->s_alloc && stream->s_buf) { + free(stream->s_buf); + } +} + +static enum fx_status stream_read( + fx_stream *stream, + void *buf, + size_t count, + size_t *nr_read) +{ + struct fx_bytestream_p *s + = fx_object_get_private(stream, FX_TYPE_BYTESTREAM); + + enum fx_status status = __gets(s, buf, count, nr_read); + + return status; +} + +static enum fx_status stream_write( + fx_stream *stream, + const void *buf, + size_t count, + size_t *nr_written) +{ + struct fx_bytestream_p *s + = fx_object_get_private(stream, FX_TYPE_BYTESTREAM); + + enum fx_status status + = __puts(s, (const unsigned char *)buf, count, nr_written); + + return status; +} + +/*** CLASS DEFINITION *********************************************************/ + +FX_TYPE_CLASS_BEGIN(fx_bytestream) + FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_stream, FX_TYPE_STREAM) + FX_INTERFACE_ENTRY(s_close) = NULL; + FX_INTERFACE_ENTRY(s_seek) = NULL; + FX_INTERFACE_ENTRY(s_tell) = NULL; + FX_INTERFACE_ENTRY(s_getc) = NULL; + FX_INTERFACE_ENTRY(s_read) = stream_read; + FX_INTERFACE_ENTRY(s_write) = stream_write; + FX_INTERFACE_ENTRY(s_reserve) = NULL; + FX_TYPE_VTABLE_INTERFACE_END(fx_stream, FX_TYPE_STREAM) +FX_TYPE_CLASS_END(fx_bytestream) + +FX_TYPE_DEFINITION_BEGIN(fx_bytestream) + FX_TYPE_ID(0xdcb7fb3a, 0xc476, 0x4c0b, 0xad5a, 0x039d1190a5b7); + FX_TYPE_EXTENDS(FX_TYPE_STREAM); + FX_TYPE_CLASS(fx_bytestream_class); + FX_TYPE_INSTANCE_PRIVATE(struct fx_bytestream_p); + FX_TYPE_INSTANCE_INIT(bytestream_init); + FX_TYPE_INSTANCE_FINI(bytestream_fini); +FX_TYPE_DEFINITION_END(fx_bytestream) diff --git a/fx/include/fx/bytestream.h b/fx/include/fx/bytestream.h new file mode 100644 index 0000000..1cf5868 --- /dev/null +++ b/fx/include/fx/bytestream.h @@ -0,0 +1,37 @@ +#ifndef FX_CORE_BYTESTREAM_H_ +#define FX_CORE_BYTESTREAM_H_ + +#include +#include +#include +#include +#include + +FX_DECLS_BEGIN; + +#define FX_TYPE_BYTESTREAM (fx_bytestream_get_type()) + +FX_DECLARE_TYPE(fx_bytestream); + +FX_TYPE_CLASS_DECLARATION_BEGIN(fx_bytestream) +FX_TYPE_CLASS_DECLARATION_END(fx_bytestream) + +FX_API fx_type_id fx_bytestream_get_type(void); + +FX_API fx_bytestream *fx_bytestream_create(void); +FX_API fx_bytestream *fx_bytestream_create_view(unsigned char *buf, size_t max); +FX_API fx_bytestream *fx_bytestream_create_readonly_view( + const unsigned char *buf, + size_t max); + +FX_API fx_status fx_bytestream_reset(fx_bytestream *strv); + +FX_API const unsigned char *fx_bytestream_get_ptr(const fx_bytestream *strv); +FX_API unsigned char *fx_bytestream_steal(fx_bytestream *strv); + +FX_API size_t fx_bytestream_get_length(const fx_bytestream *strv); +FX_API size_t fx_bytestream_get_available(const fx_bytestream *strv); + +FX_DECLS_END; + +#endif