fx: implement byte-oriented memory stream class

This commit is contained in:
2026-07-05 15:59:41 +01:00
parent 50706084eb
commit dbd2135998
2 changed files with 320 additions and 0 deletions
+283
View File
@@ -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)
+37
View File
@@ -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