diff options
author | waker <wakeroid@gmail.com> | 2011-01-31 22:22:21 +0100 |
---|---|---|
committer | waker <wakeroid@gmail.com> | 2011-01-31 22:22:21 +0100 |
commit | 2ded9857eb0e7a37d1a6b2ad1ee2c6f486bf03f3 (patch) | |
tree | c0842386614ebbe98f1d35e7621aa6eb05c8898a | |
parent | 0af105f3e8deb6aba0297f6b51b2d1c57a52d2a8 (diff) |
added new vfs_zip plugin
-rw-r--r-- | configure.ac | 21 | ||||
-rw-r--r-- | plugins/vfs_zip/Makefile.am | 9 | ||||
-rw-r--r-- | plugins/vfs_zip/vfs_zip.c | 248 | ||||
-rwxr-xr-x | scripts/quickinstall.sh | 1 |
4 files changed, 278 insertions, 1 deletions
diff --git a/configure.ac b/configure.ac index 51a1c790..12bd7201 100644 --- a/configure.ac +++ b/configure.ac @@ -101,6 +101,7 @@ AC_ARG_ENABLE(staticlink, [AS_HELP_STRING([--enable-staticlink], [link everythin AC_ARG_ENABLE(portable, [AS_HELP_STRING([--enable-portable ], [make portable build (default: disabled, opts: yes,no,full)])], [enable_portable=$enableval], [enable_portable=no]) AC_ARG_ENABLE(src, [AS_HELP_STRING([--enable-src ], [build libsamplerate (SRC) plugin (default: auto)])], [enable_src=$enableval], [enable_src=yes]) AC_ARG_ENABLE(m3u, [AS_HELP_STRING([--enable-m3u ], [build m3u plugin (default: auto)])], [enable_m3u=$enableval], [enable_m3u=yes]) +AC_ARG_ENABLE(vfs-zip, [AS_HELP_STRING([--enable-vfs-zip ], [build vfs_zip plugin (default: auto)])], [enable_vfs_zip=$enableval], [enable_vfs_zip=yes]) if test "x$enable_staticlink" != "xno" ; then AC_DEFINE_UNQUOTED([STATICLINK], [1], [Define if building static version]) @@ -134,6 +135,15 @@ else fi AC_SUBST(ZLIB_LIBS) +if test "x$enable_staticlink" != "xno" ; then + HAVE_ZIP=yes + ZIP_LIBS="../../$LIB/libzip.a" +else + AC_CHECK_LIB([zip], [main], [HAVE_ZIP=yes]) + ZIP_LIBS="-lzip" +fi +AC_SUBST(ZIP_LIBS) + if test "x$enable_gtkui" != "xno" ; then if test "x$enable_gtk3" == "xyes" ; then PKG_CHECK_MODULES(GTKUI_DEPS, gtk+-3.0 >= 2.90 gthread-2.0 glib-2.0, HAVE_GTK=yes, HAVE_GTK=no) @@ -490,7 +500,13 @@ if test "x$enable_m3u" != "xno" ; then HAVE_M3U=yes fi -PLUGINS_DIRS="plugins/lastfm plugins/mpgmad plugins/vorbis plugins/flac plugins/wavpack plugins/sndfile plugins/vfs_curl plugins/cdda plugins/gtkui plugins/alsa plugins/ffmpeg plugins/hotkeys plugins/oss plugins/artwork plugins/adplug plugins/ffap plugins/sid plugins/nullout plugins/supereq plugins/vtx plugins/gme plugins/pulse plugins/notify plugins/musepack plugins/wildmidi plugins/tta plugins/dca plugins/aac plugins/mms plugins/shellexec plugins/dsp_libsrc plugins/m3u" +if test "x$enable_vfs_zip" != "xno" ; then + if test "x$HAVE_ZLIB" = "xyes" && test "x$HAVE_ZIP" = "xyes" ; then + HAVE_VFS_ZIP=yes + fi +fi + +PLUGINS_DIRS="plugins/lastfm plugins/mpgmad plugins/vorbis plugins/flac plugins/wavpack plugins/sndfile plugins/vfs_curl plugins/cdda plugins/gtkui plugins/alsa plugins/ffmpeg plugins/hotkeys plugins/oss plugins/artwork plugins/adplug plugins/ffap plugins/sid plugins/nullout plugins/supereq plugins/vtx plugins/gme plugins/pulse plugins/notify plugins/musepack plugins/wildmidi plugins/tta plugins/dca plugins/aac plugins/mms plugins/shellexec plugins/dsp_libsrc plugins/m3u plugins/vfs_zip" AM_CONDITIONAL(HAVE_VORBIS, test "x$HAVE_VORBISPLUGIN" = "xyes") AM_CONDITIONAL(HAVE_FLAC, test "x$HAVE_FLACPLUGIN" = "xyes") @@ -527,6 +543,7 @@ AM_CONDITIONAL(PORTABLE, test "x$PORTABLE" = "xyes") AM_CONDITIONAL(PORTABLE_FULL, test "x$PORTABLE_FULL" = "xyes") AM_CONDITIONAL(HAVE_DSP_SRC, test "x$HAVE_DSP_SRC" = "xyes") AM_CONDITIONAL(HAVE_M3U, test "x$HAVE_M3U" = "xyes") +AM_CONDITIONAL(HAVE_VFS_ZIP, test "x$HAVE_VFS_ZIP" = "xyes") AC_SUBST(PLUGINS_DIRS) @@ -586,6 +603,7 @@ PRINT_PLUGIN_INFO([aac],[AAC player (m4a, aac, mp4) based on FAAD2],[test "x$HAV PRINT_PLUGIN_INFO([mms],[mms streaming support],[test "x$HAVE_MMS" = "xyes"]) PRINT_PLUGIN_INFO([dsp_src],[High quality samplerate conversion using libsamplerate],[test "x$HAVE_DSP_SRC" = "xyes"]) PRINT_PLUGIN_INFO([m3u],[M3U and PLS playlist support],[test "x$HAVE_M3U" = "xyes"]) +PRINT_PLUGIN_INFO([vfs_zip],[zip archive support],[test "x$HAVE_VFS_ZIP" = "xyes"]) echo @@ -625,6 +643,7 @@ plugins/aac/Makefile plugins/mms/Makefile plugins/dsp_libsrc/Makefile plugins/m3u/Makefile +plugins/vfs_zip/Makefile intl/Makefile po/Makefile.in deadbeef.desktop diff --git a/plugins/vfs_zip/Makefile.am b/plugins/vfs_zip/Makefile.am new file mode 100644 index 00000000..8a03b68d --- /dev/null +++ b/plugins/vfs_zip/Makefile.am @@ -0,0 +1,9 @@ +if HAVE_VFS_ZIP +pkglib_LTLIBRARIES = vfs_zip.la +vfs_zip_la_SOURCES = vfs_zip.c + +vfs_zip_la_LDFLAGS = -module + +vfs_zip_la_LIBADD = $(LDADD) $(ZLIB_LIBS) $(ZIP_LIBS) +AM_CFLAGS = $(CFLAGS) -std=c99 +endif diff --git a/plugins/vfs_zip/vfs_zip.c b/plugins/vfs_zip/vfs_zip.c new file mode 100644 index 00000000..1a8e9c48 --- /dev/null +++ b/plugins/vfs_zip/vfs_zip.c @@ -0,0 +1,248 @@ +/* + DeaDBeeF - ultimate music player for GNU/Linux systems with X11 + Copyright (C) 2009-2011 Alexey Yakovenko <waker@users.sourceforge.net> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + 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 General Public License for more details. + + You should have received a copy of the GNU 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. +*/ + +#include <string.h> +#include <zip.h> +#include <stdlib.h> +#include <assert.h> +#include "../../deadbeef.h" + +#define trace(...) { fprintf(stderr, __VA_ARGS__); } +//#define trace(fmt,...) + +#define min(x,y) ((x)<(y)?(x):(y)) + +static DB_functions_t *deadbeef; +static DB_vfs_t plugin; + +typedef struct { + DB_FILE file; + struct zip* z; + struct zip_file *zf; + int64_t offset; + int index; + int64_t size; +} zip_file_t; + +static const char *scheme_names[] = { "zip://", NULL }; +static const char *exts[] = { "zip", NULL }; + +const char ** +vfs_zip_get_schemes (void) { + return scheme_names; +} + +int +vfs_zip_is_streaming (void) { + return 0; +} + +const char ** +vfs_zip_get_container_extensions (void) { + return exts; +} + + +// fname must have form of zip://full_filepath.zip:full_filepath_in_zip +DB_FILE* +vfs_zip_open (const char *fname) { + if (strncasecmp (fname, "zip://", 6)) { + return NULL; + } + + fname += 6; + const char *colon = strchr (fname, ':'); + if (!colon) { + return NULL; + } + + + char zipname[colon-fname+1]; + memcpy (zipname, fname, colon-fname); + zipname[colon-fname] = 0; + + fname = colon+1; + + struct zip *z = zip_open (zipname, 0, NULL); + if (!z) { + return NULL; + } + struct zip_stat st; + memset (&st, 0, sizeof (st)); + + int res = zip_stat(z, fname, 0, &st); + if (res != 0) { + zip_close (z); + return NULL; + } + + struct zip_file *zf = zip_fopen_index (z, st.index, 0); + if (!zf) { + zip_close (z); + return NULL; + } + + zip_file_t *f = malloc (sizeof (zip_file_t)); + memset (f, 0, sizeof (zip_file_t)); + f->file.vfs = &plugin; + f->z = z; + f->zf = zf; + f->index = st.index; + f->size = st.size; + return (DB_FILE*)f; +} + +void +vfs_zip_close (DB_FILE *f) { + zip_file_t *zf = (zip_file_t *)f; + if (zf->zf) { + zip_fclose (zf->zf); + } + if (zf->z) { + zip_close (zf->z); + } + free (zf); +} + +size_t +vfs_zip_read (void *ptr, size_t size, size_t nmemb, DB_FILE *f) { + zip_file_t *zf = (zip_file_t *)f; + ssize_t rb = zip_fread (zf->zf, ptr, size * nmemb); + zf->offset += rb; + return rb / size; +} + +int +vfs_zip_seek (DB_FILE *f, int64_t offset, int whence) { + zip_file_t *zf = (zip_file_t *)f; + + if (whence == SEEK_CUR) { + offset = zf->offset + offset; + } + else if (whence == SEEK_END) { + offset = zf->size + offset; + } + + if (offset < zf->offset) { + // reopen + zip_fclose (zf->zf); + zf->zf = zip_fopen_index (zf->z, zf->index, 0); + if (!zf->zf) { + return -1; + } + zf->offset = 0; + } + char buf[4096]; + int64_t n = offset - zf->offset; + while (n > 0) { + int sz = min (n, sizeof (buf)); + ssize_t rb = zip_fread (zf->zf, buf, sz); + n -= rb; + assert (n >= 0); + zf->offset += rb; + if (rb != sz) { + break; + } + } + if (n > 0) { + return -1; + } + return 0; +} + +int64_t +vfs_zip_tell (DB_FILE *f) { + zip_file_t *zf = (zip_file_t *)f; + return zf->offset; +} + +void +vfs_zip_rewind (DB_FILE *f) { + zip_file_t *zf = (zip_file_t *)f; + zip_fclose (zf->zf); + zf->zf = zip_fopen_index (zf->z, zf->index, 0); + assert (zf->zf); // FIXME: better error handling? + zf->offset = 0; +} + +int64_t +vfs_zip_getlength (DB_FILE *f) { + zip_file_t *zf = (zip_file_t *)f; + return zf->size; +} + +int +vfs_zip_scandir (const char *dir, struct dirent ***namelist, int (*selector) (const struct dirent *), int (*cmp) (const struct dirent **, const struct dirent **)) { + struct zip *z = zip_open (dir, ZIP_CHECKCONS, NULL); + if (!z) { + return -1; + } + + int n = zip_get_num_files (z); + *namelist = malloc (sizeof (void *) * n); + for (int i = 0; i < n; i++) { + (*namelist)[i] = malloc (sizeof (struct dirent)); + memset ((*namelist)[i], 0, sizeof (struct dirent)); + const char *nm = zip_get_name (z, i, 0); + snprintf ((*namelist)[i]->d_name, sizeof ((*namelist)[i]->d_name), "zip://%s:%s", dir, nm); + } + + zip_close (z); + return n; +} + +int +vfs_zip_is_container (const char *fname) { + const char *ext = strrchr (fname, '.'); + if (ext && !strcasecmp (ext, ".zip")) { + return 1; + } + return 0; +} + +static DB_vfs_t plugin = { + DB_PLUGIN_SET_API_VERSION + .plugin.version_major = 1, + .plugin.version_minor = 0, + .plugin.type = DB_PLUGIN_VFS, + .plugin.id = "vfs_curl", + .plugin.name = "cURL vfs", + .plugin.descr = "http and ftp streaming module using libcurl, with ICY protocol support", + .plugin.author = "Alexey Yakovenko", + .plugin.email = "waker@users.sourceforge.net", + .plugin.website = "http://deadbeef.sf.net", + .open = vfs_zip_open, + .close = vfs_zip_close, + .read = vfs_zip_read, + .seek = vfs_zip_seek, + .tell = vfs_zip_tell, + .rewind = vfs_zip_rewind, + .getlength = vfs_zip_getlength, + .get_schemes = vfs_zip_get_schemes, + .is_streaming = vfs_zip_is_streaming, + .get_container_extensions = vfs_zip_get_container_extensions, + .is_container = vfs_zip_is_container, + .scandir = vfs_zip_scandir, +}; + +DB_plugin_t * +vfs_zip_load (DB_functions_t *api) { + deadbeef = api; + return DB_PLUGIN (&plugin); +} diff --git a/scripts/quickinstall.sh b/scripts/quickinstall.sh index af44aa51..22a308aa 100755 --- a/scripts/quickinstall.sh +++ b/scripts/quickinstall.sh @@ -40,3 +40,4 @@ cp ./plugins/ddb_input_uade2/ddb_input_uade2.so /usr/local/lib/deadbeef/ cp ./plugins/converter/converter.so /usr/local/lib/deadbeef/ cp ./plugins/converter/converter_gtkui.so /usr/local/lib/deadbeef/ cp ./plugins/dsp_soundtouch/ddb_dsp_soundtouch.so /usr/local/lib/deadbeef/ +cp ./plugins/vfs_zip/.libs/vfs_zip.so /usr/local/lib/deadbeef/ |