fx: implement byte-oriented memory stream class
This commit is contained in:
+283
@@ -0,0 +1,283 @@
|
||||
#include <fx/bytestream.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#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)
|
||||
@@ -0,0 +1,37 @@
|
||||
#ifndef FX_CORE_BYTESTREAM_H_
|
||||
#define FX_CORE_BYTESTREAM_H_
|
||||
|
||||
#include <fx/macros.h>
|
||||
#include <fx/misc.h>
|
||||
#include <fx/status.h>
|
||||
#include <fx/stream.h>
|
||||
#include <stddef.h>
|
||||
|
||||
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
|
||||
Reference in New Issue
Block a user