diff options
Diffstat (limited to 'upb/sink.c')
-rw-r--r-- | upb/sink.c | 89 |
1 files changed, 89 insertions, 0 deletions
diff --git a/upb/sink.c b/upb/sink.c new file mode 100644 index 0000000..e6ede49 --- /dev/null +++ b/upb/sink.c @@ -0,0 +1,89 @@ + +#include "upb/sink.h" + +bool upb_bufsrc_putbuf(const char *buf, size_t len, upb_bytessink *sink) { + void *subc; + bool ret; + upb_bufhandle handle; + upb_bufhandle_init(&handle); + upb_bufhandle_setbuf(&handle, buf, 0); + ret = upb_bytessink_start(sink, len, &subc); + if (ret && len != 0) { + ret = (upb_bytessink_putbuf(sink, subc, buf, len, &handle) >= len); + } + if (ret) { + ret = upb_bytessink_end(sink); + } + upb_bufhandle_uninit(&handle); + return ret; +} + +struct upb_bufsink { + upb_byteshandler handler; + upb_bytessink sink; + upb_env *env; + char *ptr; + size_t len, size; +}; + +static void *upb_bufsink_start(void *_sink, const void *hd, size_t size_hint) { + upb_bufsink *sink = _sink; + UPB_UNUSED(hd); + UPB_UNUSED(size_hint); + sink->len = 0; + return sink; +} + +static size_t upb_bufsink_string(void *_sink, const void *hd, const char *ptr, + size_t len, const upb_bufhandle *handle) { + upb_bufsink *sink = _sink; + size_t new_size = sink->size; + + UPB_ASSERT(new_size > 0); + UPB_UNUSED(hd); + UPB_UNUSED(handle); + + while (sink->len + len > new_size) { + new_size *= 2; + } + + if (new_size != sink->size) { + sink->ptr = upb_env_realloc(sink->env, sink->ptr, sink->size, new_size); + sink->size = new_size; + } + + memcpy(sink->ptr + sink->len, ptr, len); + sink->len += len; + + return len; +} + +upb_bufsink *upb_bufsink_new(upb_env *env) { + upb_bufsink *sink = upb_env_malloc(env, sizeof(upb_bufsink)); + upb_byteshandler_init(&sink->handler); + upb_byteshandler_setstartstr(&sink->handler, upb_bufsink_start, NULL); + upb_byteshandler_setstring(&sink->handler, upb_bufsink_string, NULL); + + upb_bytessink_reset(&sink->sink, &sink->handler, sink); + + sink->env = env; + sink->size = 32; + sink->ptr = upb_env_malloc(env, sink->size); + sink->len = 0; + + return sink; +} + +void upb_bufsink_free(upb_bufsink *sink) { + upb_env_free(sink->env, sink->ptr); + upb_env_free(sink->env, sink); +} + +upb_bytessink *upb_bufsink_sink(upb_bufsink *sink) { + return &sink->sink; +} + +const char *upb_bufsink_getdata(const upb_bufsink *sink, size_t *len) { + *len = sink->len; + return sink->ptr; +} |