From 27ef52ae81bf0e7127198add7ad9712567955e9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Denis-Courmont?= Date: Wed, 7 Sep 2016 12:41:14 +0300 Subject: [PATCH] memstream: helper for in-memory formatted output stream --- include/vlc_memstream.h | 65 ++++++++++++++ src/Makefile.am | 2 + src/libvlccore.sym | 8 ++ src/text/memstream.c | 189 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 264 insertions(+) create mode 100644 include/vlc_memstream.h create mode 100644 src/text/memstream.c diff --git a/include/vlc_memstream.h b/include/vlc_memstream.h new file mode 100644 index 0000000000..9086f1b9e6 --- /dev/null +++ b/include/vlc_memstream.h @@ -0,0 +1,65 @@ +/***************************************************************************** + * vlc_memstream.h: + ***************************************************************************** + * Copyright (C) 2016 Rémi Denis-Courmont + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + *****************************************************************************/ + +#ifndef VLC_MEMSTREAM_H +# define VLC_MEMSREAM_H 1 + +# include +# include + +struct vlc_memstream +{ + union + { + FILE *stream; + int error; + }; + char *ptr; + size_t length; +}; + +VLC_API +int vlc_memstream_open(struct vlc_memstream *ms); + +VLC_API +int vlc_memstream_flush(struct vlc_memstream *ms) VLC_USED; + +VLC_API +int vlc_memstream_close(struct vlc_memstream *ms) VLC_USED; + +VLC_API +size_t vlc_memstream_write(struct vlc_memstream *ms, + const void *ptr, size_t len); + +VLC_API +int vlc_memstream_putc(struct vlc_memstream *ms, int c); + +VLC_API +int vlc_memstream_puts(struct vlc_memstream *ms, const char *str); + +VLC_API +int vlc_memstream_vprintf(struct vlc_memstream *ms, const char *fmt, + va_list args); + +VLC_API +int vlc_memstream_printf(struct vlc_memstream *s, const char *fmt, + ...) VLC_FORMAT(2,3); + +#endif /* VLC_MEMSTREAM_H */ diff --git a/src/Makefile.am b/src/Makefile.am index eea70cae6c..74be803718 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -66,6 +66,7 @@ pluginsinclude_HEADERS = \ ../include/vlc_meta.h \ ../include/vlc_meta_fetcher.h \ ../include/vlc_media_library.h \ + ../include/vlc_memstream.h \ ../include/vlc_mime.h \ ../include/vlc_modules.h \ ../include/vlc_mouse.h \ @@ -423,6 +424,7 @@ SOURCES_libvlc_common = \ network/rootbind.c \ network/tls.c \ text/charset.c \ + text/memstream.c \ text/strings.c \ text/unicode.c \ text/url.c \ diff --git a/src/libvlccore.sym b/src/libvlccore.sym index ae86025580..9d96c2fdc1 100644 --- a/src/libvlccore.sym +++ b/src/libvlccore.sym @@ -273,6 +273,14 @@ module_provides module_unneed vlc_module_load vlc_module_unload +vlc_memstream_open +vlc_memstream_flush +vlc_memstream_close +vlc_memstream_write +vlc_memstream_putc +vlc_memstream_puts +vlc_memstream_vprintf +vlc_memstream_printf vlc_Log vlc_LogSet vlc_vaLog diff --git a/src/text/memstream.c b/src/text/memstream.c new file mode 100644 index 0000000000..8d734f4f2d --- /dev/null +++ b/src/text/memstream.c @@ -0,0 +1,189 @@ +/***************************************************************************** + * memstream.c: heap-based output streams + ***************************************************************************** + * Copyright (C) 2016 Rémi Denis-Courmont + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + *****************************************************************************/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include + +#ifdef HAVE_OPEN_MEMSTREAM +int vlc_memstream_open(struct vlc_memstream *ms) +{ + ms->stream = open_memstream(&ms->ptr, &ms->length); + return likely(ms->stream != NULL) ? 0 : EOF; +} + +int vlc_memstream_flush(struct vlc_memstream *ms) +{ + if (unlikely(ms->stream == NULL)) + return EOF; + + if (ferror(ms->stream)) + return EOF; + + return fflush(ms->stream); +} + +int vlc_memstream_close(struct vlc_memstream *ms) +{ + FILE *stream = ms->stream; + int ret; + + if (unlikely(stream == NULL)) + return EOF; + + ms->stream = NULL; + ret = ferror(stream); + + if (fclose(stream)) + return EOF; + + if (unlikely(ret)) + { + free(ms->ptr); + return EOF; + } + return 0; +} + +size_t vlc_memstream_write(struct vlc_memstream *ms, const void *ptr, + size_t len) +{ + if (unlikely(ms->stream == NULL)) + return 0; + + return fwrite(ptr, 1, len, ms->stream); +} + +int vlc_memstream_putc(struct vlc_memstream *ms, int c) +{ + if (unlikely(ms->stream == NULL)) + return EOF; + + return fputc(c, ms->stream); +} + +int vlc_memstream_puts(struct vlc_memstream *ms, const char *str) +{ + if (unlikely(ms->stream == NULL)) + return EOF; + + return fputs(str, ms->stream); +} + +int vlc_memstream_vprintf(struct vlc_memstream *ms, const char *fmt, + va_list args) +{ + if (unlikely(ms->stream == NULL)) + return EOF; + + return vfprintf(ms->stream, fmt, args); +} + +#else +#include + +int vlc_memstream_open(struct vlc_memstream *ms) +{ + ms->error = 0; + ms->ptr = NULL; + ms->length = 0; + return 0; +} + +int vlc_memstream_flush(struct vlc_memstream *ms) +{ + return ms->error; +} + +int vlc_memstream_close(struct vlc_memstream *ms) +{ + if (ms->error) + free(ms->ptr); + return ms->error; +} + +size_t vlc_memstream_write(struct vlc_memstream *ms, const void *ptr, + size_t len) +{ + char *base = realloc(ms->ptr, ms->length + len + 1u); + if (ptr == NULL) + goto error; + + memcpy(base + ms->length, ptr, len); + ms->ptr = base; + ms->length += len; + base[ms->length] = '\0'; + return len; + +error: + ms->error = EOF; + return EOF; +} + +int vlc_memstream_putc(struct vlc_memstream *ms, int c) +{ + return (vlc_memstream_write(ms, &(unsigned char){ c }, 1u) == 1) ? c : EOF; +} + +int vlc_memstream_puts(struct vlc_memstream *ms, const char *str) +{ + size_t len = strlen(str); + return (vlc_memstream_write(ms, str, len) == len) ? 0 : EOF; +} + +int vlc_memstream_vprintf(struct vlc_memstream *ms, const char *fmt, + va_list args) +{ + va_list ap; + char *ptr; + int len; + + va_copy(ap, args); + len = vsnprintf(NULL, 0, fmt, ap); + va_end(ap); + + ptr = realloc(ms->ptr, ms->length + len + 1); + if (ptr == NULL) + goto error; + + vsnprintf(ptr + ms->length, len + 1, fmt, args); + ms->ptr = ptr; + ms->length += len; + return len; + +error: + ms->error = EOF; + return EOF; +} +#endif + +int vlc_memstream_printf(struct vlc_memstream *ms, const char *fmt, ...) +{ + va_list ap; + int ret; + + va_start(ap, fmt); + ret = vlc_memstream_vprintf(ms, fmt, ap); + va_end(ap); + return ret; +}