diff options
author | David Robillard <d@drobilla.net> | 2021-08-13 19:31:26 -0400 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2023-12-02 18:49:08 -0500 |
commit | 828c1018f38bab9a930cecce64646366d051d39b (patch) | |
tree | 38a60777520efb17017ed62fe3b299ba94aaccf2 /src/block_dumper.h | |
parent | a083c64f506175029280ff76defa0ad7d7ae2ea0 (diff) | |
download | serd-828c1018f38bab9a930cecce64646366d051d39b.tar.gz serd-828c1018f38bab9a930cecce64646366d051d39b.tar.bz2 serd-828c1018f38bab9a930cecce64646366d051d39b.zip |
Simplify output stream API
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 |