#include #include #include #include #include #define DEFAULT_CAPACITY 15 /*** PRIVATE DATA *************************************************************/ struct b_stringstream_p { char *ss_buf; size_t ss_len; size_t ss_max; unsigned char ss_alloc; }; /*** PRIVATE FUNCTIONS ********************************************************/ static enum b_status __puts( struct b_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 B_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 B_SUCCESS; } static enum b_status stringstream_reset(struct b_stringstream_p *ss) { ss->ss_len = 0; if (ss->ss_buf) { *ss->ss_buf = 0; } return B_SUCCESS; } static enum b_status stringstream_reset_with_buffer( struct b_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 B_SUCCESS; } static size_t stringstream_get_length(const struct b_stringstream_p *strv) { return strv->ss_len; } static const char *stringstream_ptr(const struct b_stringstream_p *ss) { return ss->ss_buf; } static char *stringstream_steal(struct b_stringstream_p *ss) { char *out = ss->ss_buf; memset(ss, 0x0, sizeof *ss); ss->ss_alloc = 1; return out; } /*** PUBLIC FUNCTIONS *********************************************************/ b_stringstream *b_stringstream_create_with_buffer(char *buf, size_t max) { b_stringstream *s = b_object_create(B_TYPE_STRINGSTREAM); if (!s) { return NULL; } b_stream_cfg *cfg = b_object_get_protected(s, B_TYPE_STREAM); struct b_stringstream_p *p = b_object_get_private(s, B_TYPE_STRINGSTREAM); cfg->s_mode = B_STREAM_WRITE | Z__B_STREAM_STATIC; p->ss_buf = buf; p->ss_max = max; p->ss_len = 0; p->ss_alloc = 0; return s; } b_stringstream *b_stringstream_create(void) { b_stringstream *s = b_object_create(B_TYPE_STRINGSTREAM); if (!s) { return NULL; } b_stream_cfg *cfg = b_object_get_protected(s, B_TYPE_STREAM); struct b_stringstream_p *p = b_object_get_private(s, B_TYPE_STRINGSTREAM); cfg->s_mode = B_STREAM_WRITE | Z__B_STREAM_STATIC; p->ss_buf = malloc(DEFAULT_CAPACITY + 1); if (!p->ss_buf) { b_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 b_stringstream_get_length(const b_stringstream *strv) { B_CLASS_DISPATCH_STATIC_0( B_TYPE_STRINGSTREAM, stringstream_get_length, strv); } enum b_status b_stringstream_reset(b_stringstream *strv) { B_CLASS_DISPATCH_STATIC_0(B_TYPE_STRINGSTREAM, stringstream_reset, strv); } enum b_status b_stringstream_reset_with_buffer( b_stringstream *strv, char *buf, size_t max) { B_CLASS_DISPATCH_STATIC( B_TYPE_STRINGSTREAM, stringstream_reset_with_buffer, strv, buf, max); } const char *b_stringstream_ptr(const b_stringstream *ss) { B_CLASS_DISPATCH_STATIC_0(B_TYPE_STRINGSTREAM, stringstream_ptr, ss); } char *b_stringstream_steal(b_stringstream *ss) { B_CLASS_DISPATCH_STATIC_0(B_TYPE_STRINGSTREAM, stringstream_steal, ss); } /*** PUBLIC ALIAS FUNCTIONS ***************************************************/ /*** VIRTUAL FUNCTIONS ********************************************************/ static void stringstream_init(b_object *obj, void *priv) { struct b_stringstream_p *stream = priv; } static void stringstream_fini(b_object *obj, void *priv) { struct b_stringstream_p *stream = priv; if (stream->ss_alloc && stream->ss_buf) { free(stream->ss_buf); } } enum b_status stream_write( b_stream *stream, const void *buf, size_t count, size_t *nr_written) { struct b_stringstream_p *s = b_object_get_private(stream, B_TYPE_STRINGSTREAM); enum b_status status = __puts(s, (const char *)buf, count, nr_written); return status; } /*** CLASS DEFINITION *********************************************************/ B_TYPE_CLASS_DEFINITION_BEGIN(b_stringstream) B_TYPE_CLASS_INTERFACE_BEGIN(b_object, B_TYPE_OBJECT) B_INTERFACE_ENTRY(to_string) = NULL; B_TYPE_CLASS_INTERFACE_END(b_object, B_TYPE_OBJECT) B_TYPE_CLASS_INTERFACE_BEGIN(b_stream, B_TYPE_STREAM) B_INTERFACE_ENTRY(s_close) = NULL; B_INTERFACE_ENTRY(s_seek) = NULL; B_INTERFACE_ENTRY(s_tell) = NULL; B_INTERFACE_ENTRY(s_getc) = NULL; B_INTERFACE_ENTRY(s_read) = NULL; B_INTERFACE_ENTRY(s_write) = stream_write; B_INTERFACE_ENTRY(s_reserve) = NULL; B_TYPE_CLASS_INTERFACE_END(b_stream, B_TYPE_STREAM) B_TYPE_CLASS_DEFINITION_END(b_stringstream) B_TYPE_DEFINITION_BEGIN(b_stringstream) B_TYPE_ID(0x508a609a, 0xfac5, 0x4d31, 0x843a, 0x44b68ad329f3); B_TYPE_EXTENDS(B_TYPE_STREAM); B_TYPE_CLASS(b_stringstream_class); B_TYPE_INSTANCE_PRIVATE(struct b_stringstream_p); B_TYPE_INSTANCE_INIT(stringstream_init); B_TYPE_INSTANCE_FINI(stringstream_fini); B_TYPE_DEFINITION_END(b_stringstream)