#include #include #include #include #include #define DEFAULT_CAPACITY 15 /*** PRIVATE DATA *************************************************************/ struct fx_stringstream_p { char *ss_buf; size_t ss_ptr; size_t ss_len; size_t ss_max; unsigned char ss_alloc; }; /*** PRIVATE FUNCTIONS ********************************************************/ static enum fx_status __getc(struct fx_stringstream_p *ss, fx_wchar *out) { size_t available = ss->ss_len - ss->ss_ptr; const char *p = ss->ss_buf + ss->ss_ptr; size_t to_copy = fx_wchar_utf8_codepoint_stride(p); if (to_copy > available) { return FX_ERR_BAD_STATE; } fx_wchar c = fx_wchar_utf8_codepoint_decode(p); *out = c; if (c == FX_WCHAR_INVALID) { return FX_ERR_BAD_STATE; } ss->ss_ptr += to_copy; return FX_SUCCESS; } static enum fx_status __gets( struct fx_stringstream_p *ss, char *s, size_t len, size_t *nr_read) { size_t available = ss->ss_len - ss->ss_ptr; size_t to_copy = len; if (available < to_copy) { to_copy = available; } memcpy(s, ss->ss_buf + ss->ss_ptr, to_copy); ss->ss_ptr += to_copy; if (nr_read) { *nr_read = to_copy; } return FX_SUCCESS; } static enum fx_status __puts( struct fx_stringstream_p *ss, const char *s, size_t len, size_t *nr_written) { size_t available = ss->ss_max - ss->ss_len; size_t to_copy = len; if (to_copy > available && ss->ss_alloc == 1) { char *new_buf = realloc(ss->ss_buf, ss->ss_len + to_copy + 1); if (!new_buf) { return FX_ERR_NO_MEMORY; } ss->ss_buf = new_buf; ss->ss_max = ss->ss_len + to_copy; available = ss->ss_max - ss->ss_len; } if (available < to_copy) { to_copy = available; } memcpy(ss->ss_buf + ss->ss_len, s, to_copy); /* increment the length by the full string length, even if only a * portion was copied */ ss->ss_len += len; if (nr_written) { *nr_written = to_copy; } return FX_SUCCESS; } static enum fx_status stringstream_reset(struct fx_stringstream_p *ss) { ss->ss_len = 0; if (ss->ss_buf) { *ss->ss_buf = 0; } return FX_SUCCESS; } static enum fx_status stringstream_reset_with_buffer( struct fx_stringstream_p *ss, char *buf, size_t max) { ss->ss_len = 0; if (ss->ss_buf && ss->ss_alloc) { free(ss->ss_buf); } ss->ss_buf = buf; ss->ss_max = max; ss->ss_alloc = 0; return FX_SUCCESS; } static size_t stringstream_get_length(const struct fx_stringstream_p *strv) { return strv->ss_len; } static const char *stringstream_ptr(const struct fx_stringstream_p *ss) { return ss->ss_buf; } static char *stringstream_steal(struct fx_stringstream_p *ss) { char *out = ss->ss_buf; memset(ss, 0x0, sizeof *ss); ss->ss_alloc = 1; return out; } /*** PUBLIC FUNCTIONS *********************************************************/ fx_stringstream *fx_stringstream_create_with_buffer(char *buf, size_t max) { fx_stringstream *s = fx_object_create(FX_TYPE_STRINGSTREAM); if (!s) { return NULL; } fx_stream_cfg *cfg = fx_object_get_protected(s, FX_TYPE_STREAM); struct fx_stringstream_p *p = fx_object_get_private(s, FX_TYPE_STRINGSTREAM); cfg->s_mode = FX_STREAM_READ | FX_STREAM_WRITE | Z__FX_STREAM_STATIC; p->ss_buf = buf; p->ss_max = max; p->ss_len = 0; p->ss_alloc = 0; return s; } fx_stringstream *fx_stringstream_create(void) { fx_stringstream *s = fx_object_create(FX_TYPE_STRINGSTREAM); if (!s) { return NULL; } fx_stream_cfg *cfg = fx_object_get_protected(s, FX_TYPE_STREAM); struct fx_stringstream_p *p = fx_object_get_private(s, FX_TYPE_STRINGSTREAM); cfg->s_mode = FX_STREAM_READ | FX_STREAM_WRITE | Z__FX_STREAM_STATIC; p->ss_buf = malloc(DEFAULT_CAPACITY + 1); if (!p->ss_buf) { fx_stringstream_unref(s); return NULL; } memset(p->ss_buf, 0x0, DEFAULT_CAPACITY + 1); p->ss_max = DEFAULT_CAPACITY; p->ss_len = 0; p->ss_alloc = 1; return s; } size_t fx_stringstream_get_length(const fx_stringstream *strv) { FX_CLASS_DISPATCH_STATIC_0( FX_TYPE_STRINGSTREAM, stringstream_get_length, strv); } enum fx_status fx_stringstream_reset(fx_stringstream *strv) { FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_STRINGSTREAM, stringstream_reset, strv); } enum fx_status fx_stringstream_reset_with_buffer( fx_stringstream *strv, char *buf, size_t max) { FX_CLASS_DISPATCH_STATIC( FX_TYPE_STRINGSTREAM, stringstream_reset_with_buffer, strv, buf, max); } const char *fx_stringstream_ptr(const fx_stringstream *ss) { FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_STRINGSTREAM, stringstream_ptr, ss); } char *fx_stringstream_steal(fx_stringstream *ss) { FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_STRINGSTREAM, stringstream_steal, ss); } /*** PUBLIC ALIAS FUNCTIONS ***************************************************/ /*** VIRTUAL FUNCTIONS ********************************************************/ static void stringstream_init(fx_object *obj, void *priv) { struct fx_stringstream_p *stream = priv; } static void stringstream_fini(fx_object *obj, void *priv) { struct fx_stringstream_p *stream = priv; if (stream->ss_alloc && stream->ss_buf) { free(stream->ss_buf); } } enum fx_status stream_getc(fx_stream *stream, fx_wchar *c) { struct fx_stringstream_p *s = fx_object_get_private(stream, FX_TYPE_STRINGSTREAM); enum fx_status status = __getc(s, c); return status; } enum fx_status stream_read(fx_stream *stream, void *buf, size_t count, size_t *nr_read) { struct fx_stringstream_p *s = fx_object_get_private(stream, FX_TYPE_STRINGSTREAM); enum fx_status status = __gets(s, buf, count, nr_read); return status; } enum fx_status stream_write( fx_stream *stream, const void *buf, size_t count, size_t *nr_written) { struct fx_stringstream_p *s = fx_object_get_private(stream, FX_TYPE_STRINGSTREAM); enum fx_status status = __puts(s, (const char *)buf, count, nr_written); return status; } /*** CLASS DEFINITION *********************************************************/ FX_TYPE_CLASS_DEFINITION_BEGIN(fx_stringstream) FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT) FX_INTERFACE_ENTRY(to_string) = NULL; FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT) FX_TYPE_CLASS_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) = stream_getc; FX_INTERFACE_ENTRY(s_read) = stream_read; FX_INTERFACE_ENTRY(s_write) = stream_write; FX_INTERFACE_ENTRY(s_reserve) = NULL; FX_TYPE_CLASS_INTERFACE_END(fx_stream, FX_TYPE_STREAM) FX_TYPE_CLASS_DEFINITION_END(fx_stringstream) FX_TYPE_DEFINITION_BEGIN(fx_stringstream) FX_TYPE_ID(0x508a609a, 0xfac5, 0x4d31, 0x843a, 0x44b68ad329f3); FX_TYPE_EXTENDS(FX_TYPE_STREAM); FX_TYPE_CLASS(fx_stringstream_class); FX_TYPE_INSTANCE_PRIVATE(struct fx_stringstream_p); FX_TYPE_INSTANCE_INIT(stringstream_init); FX_TYPE_INSTANCE_FINI(stringstream_fini); FX_TYPE_DEFINITION_END(fx_stringstream)