aboutsummaryrefslogtreecommitdiffstats
path: root/src/input_stream.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/input_stream.c')
-rw-r--r--src/input_stream.c150
1 files changed, 150 insertions, 0 deletions
diff --git a/src/input_stream.c b/src/input_stream.c
new file mode 100644
index 00000000..42dfc6f8
--- /dev/null
+++ b/src/input_stream.c
@@ -0,0 +1,150 @@
+/*
+ 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"
+
+#include <sys/stat.h>
+
+#if USE_POSIX_FADVISE && USE_FILENO
+# include <fcntl.h>
+#endif
+
+// IWYU pragma: no_include <features.h>
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdio.h>
+
+static size_t
+serd_string_read(void* const buf,
+ const size_t size,
+ const size_t nmemb,
+ void* const stream)
+{
+ const char** position = (const char**)stream;
+
+ size_t n_read = 0u;
+ const size_t len = size * nmemb;
+ while (n_read < len && **position) {
+ ((char*)buf)[n_read++] = **position;
+
+ ++(*position);
+ }
+
+ return n_read;
+}
+
+static int
+serd_string_error(void* const stream)
+{
+ (void)stream;
+ return 0;
+}
+
+static int
+serd_string_close(void* const stream)
+{
+ (void)stream;
+ return 0;
+}
+
+SerdInputStream
+serd_open_input_stream(SerdReadFunc SERD_NONNULL read_func,
+ SerdStreamErrorFunc SERD_NONNULL error_func,
+ SerdStreamCloseFunc SERD_NULLABLE close_func,
+ void* const stream)
+{
+ assert(read_func);
+ assert(error_func);
+
+ SerdInputStream input = {stream, read_func, error_func, close_func};
+ return input;
+}
+
+static bool
+is_directory(const char* const path)
+{
+#ifdef _MSC_VER
+ struct stat st;
+ return !stat(path, &st) && (st.st_mode & _S_IFDIR);
+#else
+ struct stat st;
+ return !stat(path, &st) && S_ISDIR(st.st_mode);
+#endif
+}
+
+SerdInputStream
+serd_open_input_string(const char** const position)
+{
+ assert(position);
+ assert(*position);
+
+ const SerdInputStream input = {
+ position, serd_string_read, serd_string_error, serd_string_close};
+
+ return input;
+}
+
+SerdInputStream
+serd_open_input_file(const char* const path)
+{
+ assert(path);
+
+ SerdInputStream input = {NULL, NULL, NULL, NULL};
+ if (is_directory(path)) {
+ return input;
+ }
+
+#ifdef __GLIBC__
+ FILE* const file = fopen(path, "rbe");
+#else
+ FILE* const file = fopen(path, "rb");
+#endif
+
+ if (!file) {
+ return input;
+ }
+
+#if USE_POSIX_FADVISE && USE_FILENO
+ posix_fadvise(fileno(file), 0, 0, POSIX_FADV_SEQUENTIAL);
+#endif
+
+ input.stream = file;
+ input.read = (SerdReadFunc)fread;
+ input.error = (SerdStreamErrorFunc)ferror;
+ input.close = (SerdStreamCloseFunc)fclose;
+
+ return input;
+}
+
+SerdStatus
+serd_close_input(SerdInputStream* const input)
+{
+ int ret = 0;
+
+ if (input) {
+ if (input->close && input->stream) {
+ ret = input->close(input->stream);
+ input->stream = NULL;
+ }
+
+ input->stream = NULL;
+ }
+
+ return ret ? SERD_ERR_UNKNOWN : SERD_SUCCESS;
+}