diff options
Diffstat (limited to 'src/input_stream.c')
-rw-r--r-- | src/input_stream.c | 150 |
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; +} |