diff options
Diffstat (limited to 'src/block_dumper.h')
-rw-r--r-- | src/block_dumper.h | 77 |
1 files changed, 77 insertions, 0 deletions
diff --git a/src/block_dumper.h b/src/block_dumper.h new file mode 100644 index 00000000..24fb977c --- /dev/null +++ b/src/block_dumper.h @@ -0,0 +1,77 @@ +// Copyright 2011-2021 David Robillard <d@drobilla.net> +// SPDX-License-Identifier: ISC + +#ifndef SERD_SRC_BLOCK_DUMPER_H +#define SERD_SRC_BLOCK_DUMPER_H + +#include "serd/output_stream.h" +#include "serd/status.h" +#include "zix/attributes.h" + +#include <stddef.h> +#include <string.h> + +typedef struct { + SerdOutputStream* ZIX_ALLOCATED out; ///< Output stream to write to + char* ZIX_ALLOCATED buf; ///< Local buffer if needed + size_t size; ///< Bytes pending for this block + size_t block_size; ///< Block size to write in bytes +} SerdBlockDumper; + +/** + Set up a new output stream wrapper that writes in blocks. + + This allocates a buffer internally, which must be eventually freed by + calling serd_block_dumper_close(). +*/ +SerdStatus +serd_block_dumper_open(SerdBlockDumper* ZIX_NONNULL dumper, + SerdOutputStream* ZIX_NONNULL output, + size_t block_size); + +SerdStatus +serd_block_dumper_flush(SerdBlockDumper* ZIX_NONNULL dumper); + +void +serd_block_dumper_close(SerdBlockDumper* ZIX_NONNULL dumper); + +/** + Write some bytes to the page writer. + + This works like any other SerdWriteFunc, but will append to an internal + buffer and only actually write to the output when a whole block is ready. +*/ +static inline size_t +serd_block_dumper_write(const void* ZIX_NONNULL buf, + const size_t size, + const size_t nmemb, + SerdBlockDumper* ZIX_NONNULL const dumper) +{ + if (dumper->block_size == 1) { + return dumper->out->write(buf, size, nmemb, dumper->out->stream); + } + + size_t len = size * nmemb; + const size_t orig_len = len; + while (len) { + const size_t space = dumper->block_size - dumper->size; + const size_t n = space < len ? space : len; + + // Write as much as possible into the remaining buffer space + memcpy(dumper->buf + dumper->size, buf, n); + dumper->size += n; + buf = (const char*)buf + n; + len -= n; + + // Flush page if buffer is full + if (dumper->size == dumper->block_size) { + dumper->out->write( + dumper->buf, 1, dumper->block_size, dumper->out->stream); + dumper->size = 0; + } + } + + return orig_len; +} + +#endif // SERD_SRC_DUMPER_H |