aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/block_dumper.c59
-rw-r--r--src/block_dumper.h88
-rw-r--r--src/byte_sink.c124
-rw-r--r--src/byte_sink.h66
-rw-r--r--src/node_syntax.c14
-rw-r--r--src/output_stream.c89
-rw-r--r--src/writer.c31
7 files changed, 264 insertions, 207 deletions
diff --git a/src/block_dumper.c b/src/block_dumper.c
new file mode 100644
index 00000000..6ffb0013
--- /dev/null
+++ b/src/block_dumper.c
@@ -0,0 +1,59 @@
+/*
+ Copyright 2011-2021 David Robillard <d@drobilla.net>
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+#include "block_dumper.h"
+#include "system.h"
+
+#include "serd/serd.h"
+
+#include <stddef.h>
+
+SerdStatus
+serd_block_dumper_open(SerdBlockDumper* const dumper,
+ SerdOutputStream* const output,
+ const size_t block_size)
+{
+ if (!block_size) {
+ return SERD_ERR_BAD_ARG;
+ }
+
+ dumper->out = output;
+ dumper->buf = NULL;
+ dumper->size = 0u;
+ dumper->block_size = block_size;
+
+ if (block_size == 1) {
+ return SERD_SUCCESS;
+ }
+
+ dumper->buf = (char*)serd_allocate_buffer(block_size);
+ return dumper->buf ? SERD_SUCCESS : SERD_ERR_INTERNAL;
+}
+
+void
+serd_block_dumper_flush(SerdBlockDumper* const dumper)
+{
+ if (dumper->out->stream && dumper->block_size > 1 && dumper->size > 0) {
+ dumper->out->write(dumper->buf, 1, dumper->size, dumper->out->stream);
+ dumper->size = 0;
+ }
+}
+
+void
+serd_block_dumper_close(SerdBlockDumper* const dumper)
+{
+ serd_free_aligned(dumper->buf);
+}
diff --git a/src/block_dumper.h b/src/block_dumper.h
new file mode 100644
index 00000000..7c718566
--- /dev/null
+++ b/src/block_dumper.h
@@ -0,0 +1,88 @@
+/*
+ Copyright 2011-2021 David Robillard <d@drobilla.net>
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+#ifndef SERD_BLOCK_DUMPER_H
+#define SERD_BLOCK_DUMPER_H
+
+#include "serd/serd.h"
+
+#include <stddef.h>
+#include <string.h>
+
+typedef struct {
+ SerdOutputStream* SERD_ALLOCATED out; ///< Output stream to write to
+ char* SERD_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* SERD_NONNULL dumper,
+ SerdOutputStream* SERD_NONNULL output,
+ size_t block_size);
+
+void
+serd_block_dumper_flush(SerdBlockDumper* SERD_NONNULL dumper);
+
+void
+serd_block_dumper_close(SerdBlockDumper* SERD_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* SERD_NONNULL buf,
+ const size_t size,
+ const size_t nmemb,
+ SerdBlockDumper* SERD_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_DUMPER_H
diff --git a/src/byte_sink.c b/src/byte_sink.c
deleted file mode 100644
index b5b4039e..00000000
--- a/src/byte_sink.c
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- Copyright 2011-2020 David Robillard <d@drobilla.net>
-
- Permission to use, copy, modify, and/or distribute this software for any
- purpose with or without fee is hereby granted, provided that the above
- copyright notice and this permission notice appear in all copies.
-
- THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-*/
-
-#include "byte_sink.h"
-
-#include "serd_config.h"
-#include "system.h"
-
-#include "serd/serd.h"
-
-#include <assert.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#if USE_POSIX_FADVISE && USE_FILENO
-# include <fcntl.h>
-#endif
-
-SerdByteSink*
-serd_byte_sink_new_buffer(SerdBuffer* const buffer)
-{
- assert(buffer);
-
- return serd_byte_sink_new_function(
- serd_buffer_write, serd_buffer_close, buffer, 1u);
-}
-
-SerdByteSink*
-serd_byte_sink_new_function(const SerdWriteFunc write_func,
- const SerdStreamCloseFunc close_func,
- void* const stream,
- const size_t block_size)
-{
- if (!block_size) {
- return NULL;
- }
-
- SerdByteSink* sink = (SerdByteSink*)calloc(1, sizeof(SerdByteSink));
-
- sink->write_func = write_func;
- sink->close_func = close_func;
- sink->stream = stream;
- sink->block_size = block_size;
-
- if (block_size > 1) {
- sink->buf = (char*)serd_allocate_buffer(block_size);
- }
-
- return sink;
-}
-
-SerdByteSink*
-serd_byte_sink_new_filename(const char* const path, const size_t block_size)
-{
- assert(path);
-
- if (!block_size) {
- return NULL;
- }
-
- FILE* const file = fopen(path, "wb");
- if (!file) {
- return NULL;
- }
-
-#if USE_POSIX_FADVISE && USE_FILENO
- posix_fadvise(fileno(file), 0, 0, POSIX_FADV_SEQUENTIAL);
-#endif
-
- return serd_byte_sink_new_function(
- (SerdWriteFunc)fwrite, (SerdStreamCloseFunc)fclose, file, block_size);
-}
-
-void
-serd_byte_sink_flush(SerdByteSink* sink)
-{
- assert(sink);
-
- if (sink->stream && sink->block_size > 1 && sink->size > 0) {
- sink->write_func(sink->buf, 1, sink->size, sink->stream);
- sink->size = 0;
- }
-}
-
-SerdStatus
-serd_byte_sink_close(SerdByteSink* sink)
-{
- assert(sink);
-
- serd_byte_sink_flush(sink);
-
- if (sink->stream && sink->close_func) {
- const int st = sink->close_func(sink->stream);
- sink->stream = NULL;
- return st ? SERD_ERR_UNKNOWN : SERD_SUCCESS;
- }
-
- sink->stream = NULL;
- return SERD_SUCCESS;
-}
-
-void
-serd_byte_sink_free(SerdByteSink* const sink)
-{
- if (sink) {
- serd_byte_sink_close(sink);
- serd_free_aligned(sink->buf);
- free(sink);
- }
-}
diff --git a/src/byte_sink.h b/src/byte_sink.h
deleted file mode 100644
index d117a589..00000000
--- a/src/byte_sink.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- Copyright 2011-2020 David Robillard <d@drobilla.net>
-
- Permission to use, copy, modify, and/or distribute this software for any
- purpose with or without fee is hereby granted, provided that the above
- copyright notice and this permission notice appear in all copies.
-
- THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-*/
-
-#ifndef SERD_BYTE_SINK_H
-#define SERD_BYTE_SINK_H
-
-#include "serd/serd.h"
-
-#include <stddef.h>
-#include <string.h>
-
-struct SerdByteSinkImpl {
- SerdWriteFunc write_func; ///< User sink for TO_FUNCTION
- SerdStreamCloseFunc close_func; ///< Optional function to close stream
- void* stream; ///< User data for write_func
- char* buf; ///< Local buffer iff block_size > 1
- size_t size; ///< Bytes written so far in this chunk
- size_t block_size; ///< Size of chunks to write
-};
-
-static inline size_t
-serd_byte_sink_write(const void* buf, size_t len, SerdByteSink* const sink)
-{
- if (len == 0) {
- return 0;
- }
-
- if (sink->block_size == 1) {
- return sink->write_func(buf, 1, len, sink->stream);
- }
-
- const size_t orig_len = len;
- while (len) {
- const size_t space = sink->block_size - sink->size;
- const size_t n = space < len ? space : len;
-
- // Write as much as possible into the remaining buffer space
- memcpy(sink->buf + sink->size, buf, n);
- sink->size += n;
- buf = (const char*)buf + n;
- len -= n;
-
- // Flush page if buffer is full
- if (sink->size == sink->block_size) {
- sink->write_func(sink->buf, 1, sink->block_size, sink->stream);
- sink->size = 0;
- }
- }
-
- return orig_len;
-}
-
-#endif // SERD_BYTE_SINK_H
diff --git a/src/node_syntax.c b/src/node_syntax.c
index 1dadc7b8..d2768c3e 100644
--- a/src/node_syntax.c
+++ b/src/node_syntax.c
@@ -98,22 +98,22 @@ serd_node_to_syntax_in(const SerdNode* const node,
const SerdSyntax syntax,
const SerdEnv* const env)
{
- SerdWorld* const world = serd_world_new();
- SerdBuffer buffer = {NULL, 0};
- SerdByteSink* const out = serd_byte_sink_new_buffer(&buffer);
- SerdWriter* const writer = serd_writer_new(world, syntax, 0, env, out);
+ SerdWorld* const world = serd_world_new();
+ SerdBuffer buffer = {NULL, 0};
+ SerdOutputStream out = serd_open_output_buffer(&buffer);
+ SerdWriter* const writer = serd_writer_new(world, syntax, 0, env, &out, 1);
char* result = NULL;
if (!serd_writer_write_node(writer, node) && !serd_writer_finish(writer) &&
- !serd_byte_sink_close(out)) {
+ !serd_close_output(&out)) {
result = (char*)buffer.buf;
} else {
- serd_byte_sink_close(out);
+ serd_close_output(&out);
free(buffer.buf);
}
serd_writer_free(writer);
- serd_byte_sink_free(out);
+ serd_close_output(&out);
serd_world_free(world);
return result;
diff --git a/src/output_stream.c b/src/output_stream.c
new file mode 100644
index 00000000..1254aa4f
--- /dev/null
+++ b/src/output_stream.c
@@ -0,0 +1,89 @@
+/*
+ Copyright 2011-2021 David Robillard <d@drobilla.net>
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+#include "serd_config.h"
+
+#include "serd/serd.h"
+
+// IWYU pragma: no_include <features.h>
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdio.h>
+
+#if USE_POSIX_FADVISE && USE_FILENO
+# include <fcntl.h>
+#endif
+
+SerdOutputStream
+serd_open_output_stream(SerdWriteFunc const write_func,
+ SerdStreamCloseFunc const close_func,
+ void* const stream)
+{
+ assert(write_func);
+
+ SerdOutputStream output = {stream, write_func, close_func};
+ return output;
+}
+
+SerdOutputStream
+serd_open_output_buffer(SerdBuffer* const buffer)
+{
+ assert(buffer);
+
+ return serd_open_output_stream(serd_buffer_write, serd_buffer_close, buffer);
+}
+
+SerdOutputStream
+serd_open_output_file(const char* const path)
+{
+ assert(path);
+
+#ifdef __GLIBC__
+ FILE* const file = fopen(path, "wbe");
+#else
+ FILE* const file = fopen(path, "wb");
+#endif
+
+ if (!file) {
+ const SerdOutputStream failure = {NULL, NULL, NULL};
+ return failure;
+ }
+
+#if USE_POSIX_FADVISE && USE_FILENO
+ posix_fadvise(fileno(file), 0, 0, POSIX_FADV_SEQUENTIAL);
+#endif
+
+ return serd_open_output_stream(
+ (SerdWriteFunc)fwrite, (SerdStreamCloseFunc)fclose, file);
+}
+
+SerdStatus
+serd_close_output(SerdOutputStream* const output)
+{
+ int ret = 0;
+
+ if (output) {
+ if (output->close && output->stream) {
+ ret = output->close(output->stream);
+ output->stream = NULL;
+ }
+
+ output->stream = NULL;
+ }
+
+ return ret ? SERD_ERR_UNKNOWN : SERD_SUCCESS;
+}
diff --git a/src/writer.c b/src/writer.c
index 305c72e1..a9141f78 100644
--- a/src/writer.c
+++ b/src/writer.c
@@ -16,7 +16,7 @@
#include "writer.h"
-#include "byte_sink.h"
+#include "block_dumper.h"
#include "env.h"
#include "node.h"
#include "sink.h"
@@ -128,7 +128,7 @@ struct SerdWriterImpl {
SerdURIView root_uri;
WriteContext* anon_stack;
size_t anon_stack_size;
- SerdByteSink* byte_sink;
+ SerdBlockDumper output;
WriteContext context;
Sep last_sep;
int indent;
@@ -251,7 +251,8 @@ ctx(SerdWriter* writer, const SerdField field)
SERD_WARN_UNUSED_RESULT static size_t
sink(const void* buf, size_t len, SerdWriter* writer)
{
- const size_t written = serd_byte_sink_write(buf, len, writer->byte_sink);
+ const size_t written = serd_block_dumper_write(buf, 1, len, &writer->output);
+
if (written != len) {
if (errno) {
char message[1024] = {0};
@@ -1306,6 +1307,9 @@ serd_writer_finish(SerdWriter* writer)
}
free_context(writer);
+
+ serd_block_dumper_flush(&writer->output);
+
writer->indent = 0;
writer->context = WRITE_CONTEXT_NULL;
writer->empty = true;
@@ -1313,15 +1317,21 @@ serd_writer_finish(SerdWriter* writer)
}
SerdWriter*
-serd_writer_new(SerdWorld* world,
- SerdSyntax syntax,
- SerdWriterFlags flags,
- const SerdEnv* env,
- SerdByteSink* byte_sink)
+serd_writer_new(SerdWorld* world,
+ SerdSyntax syntax,
+ SerdWriterFlags flags,
+ const SerdEnv* env,
+ SerdOutputStream* output,
+ size_t block_size)
{
assert(world);
assert(env);
- assert(byte_sink);
+ assert(output);
+
+ SerdBlockDumper dumper = {NULL, NULL, 0u, 0u};
+ if (serd_block_dumper_open(&dumper, output, block_size)) {
+ return NULL;
+ }
const WriteContext context = WRITE_CONTEXT_NULL;
SerdWriter* writer = (SerdWriter*)calloc(1, sizeof(SerdWriter));
@@ -1332,7 +1342,7 @@ serd_writer_new(SerdWorld* world,
writer->env = env;
writer->root_node = NULL;
writer->root_uri = SERD_URI_NULL;
- writer->byte_sink = byte_sink;
+ writer->output = dumper;
writer->context = context;
writer->empty = true;
@@ -1425,6 +1435,7 @@ serd_writer_free(SerdWriter* writer)
}
serd_writer_finish(writer);
+ serd_block_dumper_close(&writer->output);
free(writer->anon_stack);
serd_node_free(writer->root_node);
free(writer);