60 lines
2.4 KiB
C
60 lines
2.4 KiB
C
#include <c_BufferOutputStream.h>
|
|||
|
|
|
||
|
|
typedef struct {
|
||
|
|
c_OutStream_t base;
|
||
|
|
char* data;
|
||
|
|
c_size_t capacity;
|
||
|
|
c_size_t size;
|
||
|
|
c_Allocator_t allocator;
|
||
|
|
} c_BufferOutImpl_t;
|
||
|
|
|
||
|
|
static c_err_t _BufferOut_Write(c_OutStream_t* self, const void* buf, c_size_t len, c_size_t* written) {
|
||
|
|
c_BufferOutImpl_t* impl = (c_BufferOutImpl_t*)self;
|
||
|
|
if (impl->size + len > impl->capacity) {
|
||
|
|
c_size_t new_cap = impl->capacity == 0 ? 16 : impl->capacity * 2;
|
||
|
|
while (impl->size + len > new_cap) new_cap *= 2;
|
||
|
|
char* new_data = (char*)c_Allocator_Realloc(&impl->allocator, impl->data, impl->capacity, new_cap);
|
||
|
|
if (!new_data) return C_ERR_NOMEM;
|
||
|
|
impl->data = new_data;
|
||
|
|
impl->capacity = new_cap;
|
||
|
|
}
|
||
|
|
memcpy(impl->data + impl->size, buf, len);
|
||
|
|
impl->size += len;
|
||
|
|
if (written) *written = len;
|
||
|
|
return C_SUCCESS;
|
||
|
|
}
|
||
|
|
|
||
|
|
static c_err_t _BufferOut_Flush(c_OutStream_t* self) { (void)self; return C_SUCCESS; }
|
||
|
|
|
||
|
|
static void _BufferOut_Destroy(c_OutStream_t* self) {
|
||
|
|
c_BufferOutImpl_t* impl = (c_BufferOutImpl_t*)self;
|
||
|
|
c_Allocator_t alloc = impl->allocator;
|
||
|
|
if (impl->data) c_Allocator_Free(&alloc, impl->data);
|
||
|
|
c_Allocator_Free(&alloc, impl);
|
||
|
|
}
|
||
|
|
|
||
|
|
static const c_OutStreamVtbl_t g_BufferOutVtbl = { _BufferOut_Write, _BufferOut_Flush, _BufferOut_Destroy };
|
||
|
|
|
||
|
|
c_err_t c_BufferOutputStream_Create(c_OutStream_t** out_stream, c_size_t initial_capacity, c_Allocator_t* allocator) {
|
||
|
|
if (!out_stream) return C_ERR_PARAM;
|
||
|
|
c_Allocator_t alloc = allocator ? *allocator : c_DefaultAllocator;
|
||
|
|
c_BufferOutImpl_t* impl = (c_BufferOutImpl_t*)c_Allocator_Calloc(&alloc, 1, sizeof(c_BufferOutImpl_t));
|
||
|
|
if (!impl) return C_ERR_NOMEM;
|
||
|
|
impl->base.vtbl = &g_BufferOutVtbl;
|
||
|
|
impl->allocator = alloc;
|
||
|
|
if (initial_capacity > 0) {
|
||
|
|
impl->data = (char*)c_Allocator_Calloc(&impl->allocator, initial_capacity, sizeof(char));
|
||
|
|
if (!impl->data) { c_Allocator_Free(&alloc, impl); return C_ERR_NOMEM; }
|
||
|
|
impl->capacity = initial_capacity;
|
||
|
|
}
|
||
|
|
*out_stream = &impl->base;
|
||
|
|
return C_SUCCESS;
|
||
|
|
}
|
||
|
|
|
||
|
|
c_err_t c_BufferOutputStream_GetBuffer(c_OutStream_t* self, const void** out_ptr, c_size_t* out_len) {
|
||
|
|
if (!self || self->vtbl != &g_BufferOutVtbl || !out_ptr || !out_len) return C_ERR_PARAM;
|
||
|
|
c_BufferOutImpl_t* impl = (c_BufferOutImpl_t*)self;
|
||
|
|
*out_ptr = impl->data;
|
||
|
|
*out_len = impl->size;
|
||
|
|
return C_SUCCESS;
|
||
|
|
}
|