diff options
Diffstat (limited to '')
-rw-r--r-- | src/archive/bz2_archive_plugin.c | 301 | ||||
-rw-r--r-- | src/archive/bz2_archive_plugin.h (renamed from src/input/lastfm_input_plugin.h) | 8 | ||||
-rw-r--r-- | src/archive/bz2_plugin.c | 284 | ||||
-rw-r--r-- | src/archive/iso9660_archive_plugin.c | 287 | ||||
-rw-r--r-- | src/archive/iso9660_archive_plugin.h | 25 | ||||
-rw-r--r-- | src/archive/iso_plugin.c | 239 | ||||
-rw-r--r-- | src/archive/zip_plugin.c | 196 | ||||
-rw-r--r-- | src/archive/zzip_archive_plugin.c | 242 | ||||
-rw-r--r-- | src/archive/zzip_archive_plugin.h | 25 | ||||
-rw-r--r-- | src/archive_api.c | 7 | ||||
-rw-r--r-- | src/archive_api.h | 65 | ||||
-rw-r--r-- | src/archive_internal.h | 11 | ||||
-rw-r--r-- | src/archive_list.c | 44 | ||||
-rw-r--r-- | src/archive_list.h | 4 | ||||
-rw-r--r-- | src/archive_plugin.c | 92 | ||||
-rw-r--r-- | src/archive_plugin.h | 107 |
16 files changed, 1118 insertions, 819 deletions
diff --git a/src/archive/bz2_archive_plugin.c b/src/archive/bz2_archive_plugin.c new file mode 100644 index 000000000..2414eb519 --- /dev/null +++ b/src/archive/bz2_archive_plugin.c @@ -0,0 +1,301 @@ +/* + * Copyright (C) 2003-2010 The Music Player Daemon Project + * http://www.musicpd.org + * + * 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. + */ + +/** + * single bz2 archive handling (requires libbz2) + */ + +#include "config.h" +#include "archive/bz2_archive_plugin.h" +#include "archive_api.h" +#include "input_plugin.h" +#include "refcount.h" + +#include <stdint.h> +#include <stddef.h> +#include <string.h> +#include <glib.h> +#include <bzlib.h> + +#ifdef HAVE_OLDER_BZIP2 +#define BZ2_bzDecompressInit bzDecompressInit +#define BZ2_bzDecompress bzDecompress +#endif + +struct bz2_archive_file { + struct archive_file base; + + struct refcount ref; + + char *name; + bool reset; + struct input_stream *istream; +}; + +struct bz2_input_stream { + struct input_stream base; + + struct bz2_archive_file *archive; + + bool eof; + + bz_stream bzstream; + + char buffer[5000]; +}; + +static const struct input_plugin bz2_inputplugin; + +static inline GQuark +bz2_quark(void) +{ + return g_quark_from_static_string("bz2"); +} + +/* single archive handling allocation helpers */ + +static bool +bz2_alloc(struct bz2_input_stream *data, GError **error_r) +{ + int ret; + + data->bzstream.bzalloc = NULL; + data->bzstream.bzfree = NULL; + data->bzstream.opaque = NULL; + + data->bzstream.next_in = (void *) data->buffer; + data->bzstream.avail_in = 0; + + ret = BZ2_bzDecompressInit(&data->bzstream, 0, 0); + if (ret != BZ_OK) { + g_free(data); + + g_set_error(error_r, bz2_quark(), ret, + "BZ2_bzDecompressInit() has failed"); + return false; + } + + return true; +} + +static void +bz2_destroy(struct bz2_input_stream *data) +{ + BZ2_bzDecompressEnd(&data->bzstream); +} + +/* archive open && listing routine */ + +static struct archive_file * +bz2_open(const char *pathname, GError **error_r) +{ + struct bz2_archive_file *context; + int len; + + context = g_malloc(sizeof(*context)); + archive_file_init(&context->base, &bz2_archive_plugin); + refcount_init(&context->ref); + + //open archive + context->istream = input_stream_open(pathname, error_r); + if (context->istream == NULL) { + g_free(context); + return NULL; + } + + context->name = g_path_get_basename(pathname); + + //remove suffix + len = strlen(context->name); + if (len > 4) { + context->name[len - 4] = 0; //remove .bz2 suffix + } + + return &context->base; +} + +static void +bz2_scan_reset(struct archive_file *file) +{ + struct bz2_archive_file *context = (struct bz2_archive_file *) file; + context->reset = true; +} + +static char * +bz2_scan_next(struct archive_file *file) +{ + struct bz2_archive_file *context = (struct bz2_archive_file *) file; + char *name = NULL; + + if (context->reset) { + name = context->name; + context->reset = false; + } + + return name; +} + +static void +bz2_close(struct archive_file *file) +{ + struct bz2_archive_file *context = (struct bz2_archive_file *) file; + + if (!refcount_dec(&context->ref)) + return; + + g_free(context->name); + + input_stream_close(context->istream); + g_free(context); +} + +/* single archive handling */ + +static struct input_stream * +bz2_open_stream(struct archive_file *file, const char *path, GError **error_r) +{ + struct bz2_archive_file *context = (struct bz2_archive_file *) file; + struct bz2_input_stream *bis = g_new(struct bz2_input_stream, 1); + + input_stream_init(&bis->base, &bz2_inputplugin, path); + + bis->archive = context; + + bis->base.ready = true; + bis->base.seekable = false; + + if (!bz2_alloc(bis, error_r)) { + input_stream_deinit(&bis->base); + g_free(bis); + return NULL; + } + + bis->eof = false; + + refcount_inc(&context->ref); + + return &bis->base; +} + +static void +bz2_is_close(struct input_stream *is) +{ + struct bz2_input_stream *bis = (struct bz2_input_stream *)is; + + bz2_destroy(bis); + + bz2_close(&bis->archive->base); + + input_stream_deinit(&bis->base); + g_free(bis); +} + +static bool +bz2_fillbuffer(struct bz2_input_stream *bis, GError **error_r) +{ + size_t count; + bz_stream *bzstream; + + bzstream = &bis->bzstream; + + if (bzstream->avail_in > 0) + return true; + + count = input_stream_read(bis->archive->istream, + bis->buffer, sizeof(bis->buffer), + error_r); + if (count == 0) + return false; + + bzstream->next_in = bis->buffer; + bzstream->avail_in = count; + return true; +} + +static size_t +bz2_is_read(struct input_stream *is, void *ptr, size_t length, + GError **error_r) +{ + struct bz2_input_stream *bis = (struct bz2_input_stream *)is; + bz_stream *bzstream; + int bz_result; + size_t nbytes = 0; + + if (bis->eof) + return 0; + + bzstream = &bis->bzstream; + bzstream->next_out = ptr; + bzstream->avail_out = length; + + do { + if (!bz2_fillbuffer(bis, error_r)) + return 0; + + bz_result = BZ2_bzDecompress(bzstream); + + if (bz_result == BZ_STREAM_END) { + bis->eof = true; + break; + } + + if (bz_result != BZ_OK) { + g_set_error(error_r, bz2_quark(), bz_result, + "BZ2_bzDecompress() has failed"); + return 0; + } + } while (bzstream->avail_out == length); + + nbytes = length - bzstream->avail_out; + is->offset += nbytes; + + return nbytes; +} + +static bool +bz2_is_eof(struct input_stream *is) +{ + struct bz2_input_stream *bis = (struct bz2_input_stream *)is; + + return bis->eof; +} + +/* exported structures */ + +static const char *const bz2_extensions[] = { + "bz2", + NULL +}; + +static const struct input_plugin bz2_inputplugin = { + .close = bz2_is_close, + .read = bz2_is_read, + .eof = bz2_is_eof, +}; + +const struct archive_plugin bz2_archive_plugin = { + .name = "bz2", + .open = bz2_open, + .scan_reset = bz2_scan_reset, + .scan_next = bz2_scan_next, + .open_stream = bz2_open_stream, + .close = bz2_close, + .suffixes = bz2_extensions +}; + diff --git a/src/input/lastfm_input_plugin.h b/src/archive/bz2_archive_plugin.h index d0eaf5a55..199049008 100644 --- a/src/input/lastfm_input_plugin.h +++ b/src/archive/bz2_archive_plugin.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2009 The Music Player Daemon Project + * Copyright (C) 2003-2010 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -17,9 +17,9 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#ifndef LASTFM_INPUT_PLUGIN_H -#define LASTFM_INPUT_PLUGIN_H +#ifndef MPD_ARCHIVE_BZ2_H +#define MPD_ARCHIVE_BZ2_H -extern const struct input_plugin lastfm_input_plugin; +extern const struct archive_plugin bz2_archive_plugin; #endif diff --git a/src/archive/bz2_plugin.c b/src/archive/bz2_plugin.c deleted file mode 100644 index 0ef042e90..000000000 --- a/src/archive/bz2_plugin.c +++ /dev/null @@ -1,284 +0,0 @@ -/* - * Copyright (C) 2003-2009 The Music Player Daemon Project - * http://www.musicpd.org - * - * 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. - */ - -/** - * single bz2 archive handling (requires libbz2) - */ - -#include "archive_api.h" -#include "input_plugin.h" -#include "config.h" - -#include <stdint.h> -#include <stddef.h> -#include <string.h> -#include <glib.h> -#include <bzlib.h> - -#ifdef HAVE_OLDER_BZIP2 -#define BZ2_bzDecompressInit bzDecompressInit -#define BZ2_bzDecompress bzDecompress -#endif - -#define BZ_BUFSIZE 5000 - -typedef struct { - char *name; - bool reset; - struct input_stream istream; - int last_bz_result; - int last_parent_result; - bz_stream bzstream; - char *buffer; -} bz2_context; - - -static const struct input_plugin bz2_inputplugin; - -/* single archive handling allocation helpers */ - -static bool -bz2_alloc(bz2_context *data) -{ - data->bzstream.bzalloc = NULL; - data->bzstream.bzfree = NULL; - data->bzstream.opaque = NULL; - - data->buffer = g_malloc(BZ_BUFSIZE); - data->bzstream.next_in = (void *) data->buffer; - data->bzstream.avail_in = 0; - - if (BZ2_bzDecompressInit(&data->bzstream, 0, 0) != BZ_OK) { - g_free(data->buffer); - g_free(data); - return false; - } - - data->last_bz_result = BZ_OK; - data->last_parent_result = 0; - return true; -} - -static void -bz2_destroy(bz2_context *data) -{ - BZ2_bzDecompressEnd(&data->bzstream); - g_free(data->buffer); -} - -/* archive open && listing routine */ - -static struct archive_file * -bz2_open(char * pathname) -{ - bz2_context *context; - char *name; - int len; - - context = g_malloc(sizeof(bz2_context)); - if (!context) { - return NULL; - } - //open archive - if (!input_stream_open(&context->istream, pathname)) { - g_warning("failed to open an bzip2 archive %s\n",pathname); - g_free(context); - return NULL; - } - //capture filename - name = strrchr(pathname, '/'); - if (name == NULL) { - g_warning("failed to get bzip2 name from %s\n",pathname); - g_free(context); - return NULL; - } - context->name = g_strdup(name+1); - //remove suffix - len = strlen(context->name); - if (len > 4) { - context->name[len-4] = 0; //remove .bz2 suffix - } - return (struct archive_file *) context; -} - -static void -bz2_scan_reset(struct archive_file *file) -{ - bz2_context *context = (bz2_context *) file; - context->reset = true; -} - -static char * -bz2_scan_next(struct archive_file *file) -{ - bz2_context *context = (bz2_context *) file; - char *name = NULL; - if (context->reset) { - name = context->name; - context->reset = false; - } - return name; -} - -static void -bz2_close(struct archive_file *file) -{ - bz2_context *context = (bz2_context *) file; - - g_free(context->name); - - input_stream_close(&context->istream); - g_free(context); -} - -/* single archive handling */ - -static bool -bz2_open_stream(struct archive_file *file, struct input_stream *is, - G_GNUC_UNUSED const char *path) -{ - bz2_context *context = (bz2_context *) file; - //setup file ops - is->plugin = &bz2_inputplugin; - //insert back reference - is->data = context; - is->seekable = false; - - if (!bz2_alloc(context)) { - g_warning("alloc bz2 failed\n"); - return false; - } - return true; -} - -static void -bz2_is_close(struct input_stream *is) -{ - bz2_context *context = (bz2_context *) is->data; - bz2_destroy(context); - is->data = NULL; - - bz2_close((struct archive_file *)context); -} - -static int -bz2_fillbuffer(bz2_context *context, - size_t numBytes) -{ - size_t count; - bz_stream *bzstream; - - bzstream = &context->bzstream; - - if (bzstream->avail_in > 0) - return 0; - - count = input_stream_read(&context->istream, - context->buffer, BZ_BUFSIZE); - - if (count == 0) { - if (bzstream->avail_out == numBytes) - return -1; - if (!input_stream_eof(&context->istream)) - context->last_parent_result = 1; - } else { - bzstream->next_in = context->buffer; - bzstream->avail_in = count; - } - - return 0; -} - -static size_t -bz2_is_read(struct input_stream *is, void *ptr, size_t size) -{ - bz2_context *context = (bz2_context *) is->data; - bz_stream *bzstream; - int bz_result; - size_t numBytes = size; - size_t bytesRead = 0; - - if (context->last_bz_result != BZ_OK) - return 0; - if (context->last_parent_result != 0) - return 0; - - bzstream = &context->bzstream; - bzstream->next_out = ptr; - bzstream->avail_out = numBytes; - - while (bzstream->avail_out != 0) { - if (bz2_fillbuffer(context, numBytes) != 0) - break; - - bz_result = BZ2_bzDecompress(bzstream); - - if (context->last_bz_result != BZ_OK - && bzstream->avail_out == numBytes) { - context->last_bz_result = bz_result; - break; - } - - if (bz_result == BZ_STREAM_END) { - context->last_bz_result = bz_result; - break; - } - } - - bytesRead = numBytes - bzstream->avail_out; - is->offset += bytesRead; - - return bytesRead; -} - -static bool -bz2_is_eof(struct input_stream *is) -{ - bz2_context *context = (bz2_context *) is->data; - - if (context->last_bz_result == BZ_STREAM_END) { - return true; - } - - return false; -} - -/* exported structures */ - -static const char *const bz2_extensions[] = { - "bz2", - NULL -}; - -static const struct input_plugin bz2_inputplugin = { - .close = bz2_is_close, - .read = bz2_is_read, - .eof = bz2_is_eof, -}; - -const struct archive_plugin bz2_plugin = { - .name = "bz2", - .open = bz2_open, - .scan_reset = bz2_scan_reset, - .scan_next = bz2_scan_next, - .open_stream = bz2_open_stream, - .close = bz2_close, - .suffixes = bz2_extensions -}; - diff --git a/src/archive/iso9660_archive_plugin.c b/src/archive/iso9660_archive_plugin.c new file mode 100644 index 000000000..142fa10e0 --- /dev/null +++ b/src/archive/iso9660_archive_plugin.c @@ -0,0 +1,287 @@ +/* + * Copyright (C) 2003-2010 The Music Player Daemon Project + * http://www.musicpd.org + * + * 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. + */ + +/** + * iso archive handling (requires cdio, and iso9660) + */ + +#include "config.h" +#include "archive/iso9660_archive_plugin.h" +#include "archive_api.h" +#include "input_plugin.h" +#include "refcount.h" + +#include <cdio/cdio.h> +#include <cdio/iso9660.h> + +#include <glib.h> +#include <string.h> + +#define CEILING(x, y) ((x+(y-1))/y) + +struct iso9660_archive_file { + struct archive_file base; + + struct refcount ref; + + iso9660_t *iso; + GSList *list; + GSList *iter; +}; + +static const struct input_plugin iso9660_input_plugin; + +static inline GQuark +iso9660_quark(void) +{ + return g_quark_from_static_string("iso9660"); +} + +/* archive open && listing routine */ + +static void +listdir_recur(const char *psz_path, struct iso9660_archive_file *context) +{ + iso9660_t *iso = context->iso; + CdioList_t *entlist; + CdioListNode_t *entnode; + iso9660_stat_t *statbuf; + char pathname[4096]; + + entlist = iso9660_ifs_readdir (iso, psz_path); + if (!entlist) { + return; + } + /* Iterate over the list of nodes that iso9660_ifs_readdir gives */ + _CDIO_LIST_FOREACH (entnode, entlist) { + statbuf = (iso9660_stat_t *) _cdio_list_node_data (entnode); + + strcpy(pathname, psz_path); + strcat(pathname, statbuf->filename); + + if (_STAT_DIR == statbuf->type ) { + if (strcmp(statbuf->filename, ".") && strcmp(statbuf->filename, "..")) { + strcat(pathname, "/"); + listdir_recur(pathname, context); + } + } else { + //remove leading / + context->list = g_slist_prepend( context->list, + g_strdup(pathname + 1)); + } + } + _cdio_list_free (entlist, true); +} + +static struct archive_file * +iso9660_archive_open(const char *pathname, GError **error_r) +{ + struct iso9660_archive_file *context = + g_new(struct iso9660_archive_file, 1); + + archive_file_init(&context->base, &iso9660_archive_plugin); + refcount_init(&context->ref); + + context->list = NULL; + + /* open archive */ + context->iso = iso9660_open (pathname); + if (context->iso == NULL) { + g_set_error(error_r, iso9660_quark(), 0, + "Failed to open ISO9660 file %s", pathname); + return NULL; + } + + listdir_recur("/", context); + + return &context->base; +} + +static void +iso9660_archive_scan_reset(struct archive_file *file) +{ + struct iso9660_archive_file *context = + (struct iso9660_archive_file *)file; + + //reset iterator + context->iter = context->list; +} + +static char * +iso9660_archive_scan_next(struct archive_file *file) +{ + struct iso9660_archive_file *context = + (struct iso9660_archive_file *)file; + + char *data = NULL; + if (context->iter != NULL) { + ///fetch data and goto next + data = context->iter->data; + context->iter = g_slist_next(context->iter); + } + return data; +} + +static void +iso9660_archive_close(struct archive_file *file) +{ + struct iso9660_archive_file *context = + (struct iso9660_archive_file *)file; + GSList *tmp; + + if (!refcount_dec(&context->ref)) + return; + + if (context->list) { + //free list + for (tmp = context->list; tmp != NULL; tmp = g_slist_next(tmp)) + g_free(tmp->data); + g_slist_free(context->list); + } + //close archive + iso9660_close(context->iso); + + g_free(context); +} + +/* single archive handling */ + +struct iso9660_input_stream { + struct input_stream base; + + struct iso9660_archive_file *archive; + + iso9660_stat_t *statbuf; + size_t max_blocks; +}; + +static struct input_stream * +iso9660_archive_open_stream(struct archive_file *file, + const char *pathname, GError **error_r) +{ + struct iso9660_archive_file *context = + (struct iso9660_archive_file *)file; + struct iso9660_input_stream *iis; + + iis = g_new(struct iso9660_input_stream, 1); + input_stream_init(&iis->base, &iso9660_input_plugin, pathname); + + iis->archive = context; + iis->statbuf = iso9660_ifs_stat_translate(context->iso, pathname); + if (iis->statbuf == NULL) { + g_free(iis); + g_set_error(error_r, iso9660_quark(), 0, + "not found in the ISO file: %s", pathname); + return NULL; + } + + iis->base.ready = true; + //we are not seekable + iis->base.seekable = false; + + iis->base.size = iis->statbuf->size; + + iis->max_blocks = CEILING(iis->statbuf->size, ISO_BLOCKSIZE); + + refcount_inc(&context->ref); + + return &iis->base; +} + +static void +iso9660_input_close(struct input_stream *is) +{ + struct iso9660_input_stream *iis = (struct iso9660_input_stream *)is; + + g_free(iis->statbuf); + + iso9660_archive_close(&iis->archive->base); + + input_stream_deinit(&iis->base); + g_free(iis); +} + + +static size_t +iso9660_input_read(struct input_stream *is, void *ptr, size_t size, GError **error_r) +{ + struct iso9660_input_stream *iis = (struct iso9660_input_stream *)is; + int toread, readed = 0; + int no_blocks, cur_block; + size_t left_bytes = iis->statbuf->size - is->offset; + + size = (size * ISO_BLOCKSIZE) / ISO_BLOCKSIZE; + + if (left_bytes < size) { + toread = left_bytes; + no_blocks = CEILING(left_bytes,ISO_BLOCKSIZE); + } else { + toread = size; + no_blocks = toread / ISO_BLOCKSIZE; + } + if (no_blocks > 0) { + + cur_block = is->offset / ISO_BLOCKSIZE; + + readed = iso9660_iso_seek_read (iis->archive->iso, ptr, + iis->statbuf->lsn + cur_block, no_blocks); + + if (readed != no_blocks * ISO_BLOCKSIZE) { + g_set_error(error_r, iso9660_quark(), 0, + "error reading ISO file at lsn %lu", + (long unsigned int) cur_block); + return 0; + } + if (left_bytes < size) { + readed = left_bytes; + } + + is->offset += readed; + } + return readed; +} + +static bool +iso9660_input_eof(struct input_stream *is) +{ + return is->offset == is->size; +} + +/* exported structures */ + +static const char *const iso9660_archive_extensions[] = { + "iso", + NULL +}; + +static const struct input_plugin iso9660_input_plugin = { + .close = iso9660_input_close, + .read = iso9660_input_read, + .eof = iso9660_input_eof, +}; + +const struct archive_plugin iso9660_archive_plugin = { + .name = "iso", + .open = iso9660_archive_open, + .scan_reset = iso9660_archive_scan_reset, + .scan_next = iso9660_archive_scan_next, + .open_stream = iso9660_archive_open_stream, + .close = iso9660_archive_close, + .suffixes = iso9660_archive_extensions +}; diff --git a/src/archive/iso9660_archive_plugin.h b/src/archive/iso9660_archive_plugin.h new file mode 100644 index 000000000..2a3864cee --- /dev/null +++ b/src/archive/iso9660_archive_plugin.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2003-2010 The Music Player Daemon Project + * http://www.musicpd.org + * + * 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. + */ + +#ifndef MPD_ARCHIVE_ISO9660_H +#define MPD_ARCHIVE_ISO9660_H + +extern const struct archive_plugin iso9660_archive_plugin; + +#endif diff --git a/src/archive/iso_plugin.c b/src/archive/iso_plugin.c deleted file mode 100644 index 9063af0fc..000000000 --- a/src/archive/iso_plugin.c +++ /dev/null @@ -1,239 +0,0 @@ -/* - * Copyright (C) 2003-2009 The Music Player Daemon Project - * http://www.musicpd.org - * - * 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. - */ - -/** - * iso archive handling (requires cdio, and iso9660) - */ - -#include "archive_api.h" -#include "input_plugin.h" - -#include <cdio/cdio.h> -#include <cdio/iso9660.h> - -#include <glib.h> -#include <string.h> - -#define CEILING(x, y) ((x+(y-1))/y) - -typedef struct { - iso9660_t *iso; - iso9660_stat_t *statbuf; - size_t cur_ofs; - size_t max_blocks; - GSList *list; - GSList *iter; -} iso_context; - -static const struct input_plugin iso_inputplugin; - -/* archive open && listing routine */ - -static void -listdir_recur(const char *psz_path, iso_context *context) -{ - iso9660_t *iso = context->iso; - CdioList_t *entlist; - CdioListNode_t *entnode; - iso9660_stat_t *statbuf; - char pathname[4096]; - - entlist = iso9660_ifs_readdir (iso, psz_path); - if (!entlist) { - return; - } - /* Iterate over the list of nodes that iso9660_ifs_readdir gives */ - _CDIO_LIST_FOREACH (entnode, entlist) { - statbuf = (iso9660_stat_t *) _cdio_list_node_data (entnode); - - strcpy(pathname, psz_path); - strcat(pathname, statbuf->filename); - - if (_STAT_DIR == statbuf->type ) { - if (strcmp(statbuf->filename, ".") && strcmp(statbuf->filename, "..")) { - strcat(pathname, "/"); - listdir_recur(pathname, context); - } - } else { - //remove leading / - context->list = g_slist_prepend( context->list, - g_strdup(pathname + 1)); - } - } - _cdio_list_free (entlist, true); -} - -static struct archive_file * -iso_open(char * pathname) -{ - iso_context *context = g_malloc(sizeof(iso_context)); - - context->list = NULL; - - /* open archive */ - context->iso = iso9660_open (pathname); - if (context->iso == NULL) { - g_warning("iso %s open failed\n", pathname); - return NULL; - } - - listdir_recur("/", context); - - return (struct archive_file *)context; -} - -static void -iso_scan_reset(struct archive_file *file) -{ - iso_context *context = (iso_context *) file; - //reset iterator - context->iter = context->list; -} - -static char * -iso_scan_next(struct archive_file *file) -{ - iso_context *context = (iso_context *) file; - char *data = NULL; - if (context->iter != NULL) { - ///fetch data and goto next - data = context->iter->data; - context->iter = g_slist_next(context->iter); - } - return data; -} - -static void -iso_close(struct archive_file *file) -{ - iso_context *context = (iso_context *) file; - GSList *tmp; - if (context->list) { - //free list - for (tmp = context->list; tmp != NULL; tmp = g_slist_next(tmp)) - g_free(tmp->data); - g_slist_free(context->list); - } - //close archive - iso9660_close(context->iso); - - g_free(context); -} - -/* single archive handling */ - -static bool -iso_open_stream(struct archive_file *file, struct input_stream *is, - const char *pathname) -{ - iso_context *context = (iso_context *) file; - //setup file ops - is->plugin = &iso_inputplugin; - //insert back reference - is->data = context; - //we are not seekable - is->seekable = false; - - context->statbuf = iso9660_ifs_stat_translate (context->iso, pathname); - - if (context->statbuf == NULL) { - g_warning("file %s not found in iso\n", pathname); - return false; - } - context->cur_ofs = 0; - context->max_blocks = CEILING(context->statbuf->size, ISO_BLOCKSIZE); - return true; -} - -static void -iso_is_close(struct input_stream *is) -{ - iso_context *context = (iso_context *) is->data; - g_free(context->statbuf); - - iso_close((struct archive_file *)context); -} - - -static size_t -iso_is_read(struct input_stream *is, void *ptr, size_t size) -{ - iso_context *context = (iso_context *) is->data; - int toread, readed = 0; - int no_blocks, cur_block; - size_t left_bytes = context->statbuf->size - context->cur_ofs; - - size = (size * ISO_BLOCKSIZE) / ISO_BLOCKSIZE; - - if (left_bytes < size) { - toread = left_bytes; - no_blocks = CEILING(left_bytes,ISO_BLOCKSIZE); - } else { - toread = size; - no_blocks = toread / ISO_BLOCKSIZE; - } - if (no_blocks > 0) { - - cur_block = context->cur_ofs / ISO_BLOCKSIZE; - - readed = iso9660_iso_seek_read (context->iso, ptr, - context->statbuf->lsn + cur_block, no_blocks); - - if (readed != no_blocks * ISO_BLOCKSIZE) { - g_warning("error reading ISO file at lsn %lu\n", - (long unsigned int) cur_block ); - return -1; - } - if (left_bytes < size) { - readed = left_bytes; - } - context->cur_ofs += readed; - } - return readed; -} - -static bool -iso_is_eof(struct input_stream *is) -{ - iso_context *context = (iso_context *) is->data; - return (context->cur_ofs == context->statbuf->size); -} - -/* exported structures */ - -static const char *const iso_extensions[] = { - "iso", - NULL -}; - -static const struct input_plugin iso_inputplugin = { - .close = iso_is_close, - .read = iso_is_read, - .eof = iso_is_eof, -}; - -const struct archive_plugin iso_plugin = { - .name = "iso", - .open = iso_open, - .scan_reset = iso_scan_reset, - .scan_next = iso_scan_next, - .open_stream = iso_open_stream, - .close = iso_close, - .suffixes = iso_extensions -}; diff --git a/src/archive/zip_plugin.c b/src/archive/zip_plugin.c deleted file mode 100644 index 243d46418..000000000 --- a/src/archive/zip_plugin.c +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Copyright (C) 2003-2009 The Music Player Daemon Project - * http://www.musicpd.org - * - * 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. - */ - -/** - * zip archive handling (requires zziplib) - */ - -#include "archive_api.h" -#include "archive_api.h" -#include "input_plugin.h" - -#include <zzip/zzip.h> -#include <glib.h> -#include <string.h> - -typedef struct { - ZZIP_DIR *dir; - ZZIP_FILE *file; - size_t length; - GSList *list; - GSList *iter; -} zip_context; - -static const struct input_plugin zip_inputplugin; - -/* archive open && listing routine */ - -static struct archive_file * -zip_open(char * pathname) -{ - zip_context *context = g_malloc(sizeof(zip_context)); - ZZIP_DIRENT dirent; - - // open archive - context->list = NULL; - context->dir = zzip_dir_open(pathname, NULL); - if (context->dir == NULL) { - g_warning("zipfile %s open failed\n", pathname); - return NULL; - } - - while (zzip_dir_read(context->dir, &dirent)) { - //add only files - if (dirent.st_size > 0) { - context->list = g_slist_prepend(context->list, - g_strdup(dirent.d_name)); - } - } - - return (struct archive_file *)context; -} - -static void -zip_scan_reset(struct archive_file *file) -{ - zip_context *context = (zip_context *) file; - //reset iterator - context->iter = context->list; -} - -static char * -zip_scan_next(struct archive_file *file) -{ - zip_context *context = (zip_context *) file; - char *data = NULL; - if (context->iter != NULL) { - ///fetch data and goto next - data = context->iter->data; - context->iter = g_slist_next(context->iter); - } - return data; -} - -static void -zip_close(struct archive_file *file) -{ - zip_context *context = (zip_context *) file; - if (context->list) { - //free list - for (GSList *tmp = context->list; tmp != NULL; tmp = g_slist_next(tmp)) - g_free(tmp->data); - g_slist_free(context->list); - } - //close archive - zzip_dir_close (context->dir); - - g_free(context); -} - -/* single archive handling */ - -static bool -zip_open_stream(struct archive_file *file, struct input_stream *is, - const char *pathname) -{ - zip_context *context = (zip_context *) file; - ZZIP_STAT z_stat; - - //setup file ops - is->plugin = &zip_inputplugin; - //insert back reference - is->data = context; - //we are seekable (but its not recommendent to do so) - is->seekable = true; - - context->file = zzip_file_open(context->dir, pathname, 0); - if (!context->file) { - g_warning("file %s not found in the zipfile\n", pathname); - return false; - } - zzip_file_stat(context->file, &z_stat); - context->length = z_stat.st_size; - return true; -} - -static void -zip_is_close(struct input_stream *is) -{ - zip_context *context = (zip_context *) is->data; - zzip_file_close (context->file); - - zip_close((struct archive_file *)context); -} - -static size_t -zip_is_read(struct input_stream *is, void *ptr, size_t size) -{ - zip_context *context = (zip_context *) is->data; - int ret; - ret = zzip_file_read(context->file, ptr, size); - if (ret < 0) { - g_warning("error %d reading zipfile\n", ret); - return 0; - } - return ret; -} - -static bool -zip_is_eof(struct input_stream *is) -{ - zip_context *context = (zip_context *) is->data; - return ((size_t) zzip_tell(context->file) == context->length); -} - -static bool -zip_is_seek(G_GNUC_UNUSED struct input_stream *is, - G_GNUC_UNUSED off_t offset, G_GNUC_UNUSED int whence) -{ - zip_context *context = (zip_context *) is->data; - zzip_off_t ofs = zzip_seek(context->file, offset, whence); - if (ofs != -1) { - is->offset = ofs; - return true; - } - return false; -} - -/* exported structures */ - -static const char *const zip_extensions[] = { - "zip", - NULL -}; - -static const struct input_plugin zip_inputplugin = { - .close = zip_is_close, - .read = zip_is_read, - .eof = zip_is_eof, - .seek = zip_is_seek, -}; - -const struct archive_plugin zip_plugin = { - .name = "zip", - .open = zip_open, - .scan_reset = zip_scan_reset, - .scan_next = zip_scan_next, - .open_stream = zip_open_stream, - .close = zip_close, - .suffixes = zip_extensions -}; diff --git a/src/archive/zzip_archive_plugin.c b/src/archive/zzip_archive_plugin.c new file mode 100644 index 000000000..3c2b80318 --- /dev/null +++ b/src/archive/zzip_archive_plugin.c @@ -0,0 +1,242 @@ +/* + * Copyright (C) 2003-2010 The Music Player Daemon Project + * http://www.musicpd.org + * + * 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. + */ + +/** + * zip archive handling (requires zziplib) + */ + +#include "config.h" +#include "archive/zzip_archive_plugin.h" +#include "archive_api.h" +#include "archive_api.h" +#include "input_plugin.h" +#include "refcount.h" + +#include <zzip/zzip.h> +#include <glib.h> +#include <string.h> + +struct zzip_archive { + struct archive_file base; + + struct refcount ref; + + ZZIP_DIR *dir; + GSList *list; + GSList *iter; +}; + +static const struct input_plugin zzip_input_plugin; + +static inline GQuark +zzip_quark(void) +{ + return g_quark_from_static_string("zzip"); +} + +/* archive open && listing routine */ + +static struct archive_file * +zzip_archive_open(const char *pathname, GError **error_r) +{ + struct zzip_archive *context = g_malloc(sizeof(*context)); + ZZIP_DIRENT dirent; + + archive_file_init(&context->base, &zzip_archive_plugin); + refcount_init(&context->ref); + + // open archive + context->list = NULL; + context->dir = zzip_dir_open(pathname, NULL); + if (context->dir == NULL) { + g_set_error(error_r, zzip_quark(), 0, + "Failed to open ZIP file %s", pathname); + return NULL; + } + + while (zzip_dir_read(context->dir, &dirent)) { + //add only files + if (dirent.st_size > 0) { + context->list = g_slist_prepend(context->list, + g_strdup(dirent.d_name)); + } + } + + return &context->base; +} + +static void +zzip_archive_scan_reset(struct archive_file *file) +{ + struct zzip_archive *context = (struct zzip_archive *) file; + //reset iterator + context->iter = context->list; +} + +static char * +zzip_archive_scan_next(struct archive_file *file) +{ + struct zzip_archive *context = (struct zzip_archive *) file; + char *data = NULL; + if (context->iter != NULL) { + ///fetch data and goto next + data = context->iter->data; + context->iter = g_slist_next(context->iter); + } + return data; +} + +static void +zzip_archive_close(struct archive_file *file) +{ + struct zzip_archive *context = (struct zzip_archive *) file; + + if (!refcount_dec(&context->ref)) + return; + + if (context->list) { + //free list + for (GSList *tmp = context->list; tmp != NULL; tmp = g_slist_next(tmp)) + g_free(tmp->data); + g_slist_free(context->list); + } + //close archive + zzip_dir_close (context->dir); + + g_free(context); +} + +/* single archive handling */ + +struct zzip_input_stream { + struct input_stream base; + + struct zzip_archive *archive; + + ZZIP_FILE *file; +}; + +static struct input_stream * +zzip_archive_open_stream(struct archive_file *file, + const char *pathname, GError **error_r) +{ + struct zzip_archive *context = (struct zzip_archive *) file; + struct zzip_input_stream *zis; + ZZIP_STAT z_stat; + + zis = g_new(struct zzip_input_stream, 1); + input_stream_init(&zis->base, &zzip_input_plugin, pathname); + + zis->archive = context; + zis->file = zzip_file_open(context->dir, pathname, 0); + if (zis->file == NULL) { + g_free(zis); + g_set_error(error_r, zzip_quark(), 0, + "not found in the ZIP file: %s", pathname); + return NULL; + } + + zis->base.ready = true; + //we are seekable (but its not recommendent to do so) + zis->base.seekable = true; + + zzip_file_stat(zis->file, &z_stat); + zis->base.size = z_stat.st_size; + + refcount_inc(&context->ref); + + return &zis->base; +} + +static void +zzip_input_close(struct input_stream *is) +{ + struct zzip_input_stream *zis = (struct zzip_input_stream *)is; + + zzip_file_close(zis->file); + zzip_archive_close(&zis->archive->base); + input_stream_deinit(&zis->base); + g_free(zis); +} + +static size_t +zzip_input_read(struct input_stream *is, void *ptr, size_t size, + GError **error_r) +{ + struct zzip_input_stream *zis = (struct zzip_input_stream *)is; + int ret; + + ret = zzip_file_read(zis->file, ptr, size); + if (ret < 0) { + g_set_error(error_r, zzip_quark(), ret, + "zzip_file_read() has failed"); + return 0; + } + + is->offset = zzip_tell(zis->file); + + return ret; +} + +static bool +zzip_input_eof(struct input_stream *is) +{ + struct zzip_input_stream *zis = (struct zzip_input_stream *)is; + + return (goffset)zzip_tell(zis->file) == is->size; +} + +static bool +zzip_input_seek(struct input_stream *is, + goffset offset, int whence, GError **error_r) +{ + struct zzip_input_stream *zis = (struct zzip_input_stream *)is; + zzip_off_t ofs = zzip_seek(zis->file, offset, whence); + if (ofs != -1) { + g_set_error(error_r, zzip_quark(), ofs, + "zzip_seek() has failed"); + is->offset = ofs; + return true; + } + return false; +} + +/* exported structures */ + +static const char *const zzip_archive_extensions[] = { + "zip", + NULL +}; + +static const struct input_plugin zzip_input_plugin = { + .close = zzip_input_close, + .read = zzip_input_read, + .eof = zzip_input_eof, + .seek = zzip_input_seek, +}; + +const struct archive_plugin zzip_archive_plugin = { + .name = "zzip", + .open = zzip_archive_open, + .scan_reset = zzip_archive_scan_reset, + .scan_next = zzip_archive_scan_next, + .open_stream = zzip_archive_open_stream, + .close = zzip_archive_close, + .suffixes = zzip_archive_extensions +}; diff --git a/src/archive/zzip_archive_plugin.h b/src/archive/zzip_archive_plugin.h new file mode 100644 index 000000000..6d5037eef --- /dev/null +++ b/src/archive/zzip_archive_plugin.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2003-2010 The Music Player Daemon Project + * http://www.musicpd.org + * + * 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. + */ + +#ifndef MPD_ARCHIVE_ZZIP_H +#define MPD_ARCHIVE_ZZIP_H + +extern const struct archive_plugin zzip_archive_plugin; + +#endif diff --git a/src/archive_api.c b/src/archive_api.c index 153afa361..b15810f1b 100644 --- a/src/archive_api.c +++ b/src/archive_api.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2009 The Music Player Daemon Project + * Copyright (C) 2003-2010 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -17,6 +17,9 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include "config.h" /* must be first for large file support */ +#include "archive_api.h" + #include <stdio.h> #include <string.h> @@ -26,8 +29,6 @@ #include <errno.h> #include <glib.h> -#include "archive_api.h" - /** * * archive_lookup is used to determine if part of pathname refers to an regular diff --git a/src/archive_api.h b/src/archive_api.h index 2efcc1e6a..f08960c72 100644 --- a/src/archive_api.h +++ b/src/archive_api.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2009 The Music Player Daemon Project + * Copyright (C) 2003-2010 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -27,72 +27,11 @@ */ #include "archive_internal.h" +#include "archive_plugin.h" #include "input_stream.h" #include <stdbool.h> -struct archive_file; - -struct archive_plugin { - const char *name; - - /** - * optional, set this to NULL if the archive plugin doesn't - * have/need one this must false if there is an error and - * true otherwise - */ - bool (*init)(void); - - /** - * optional, set this to NULL if the archive plugin doesn't - * have/need one - */ - void (*finish)(void); - - /** - * tryes to open archive file and associates handle with archive - * returns pointer to handle used is all operations with this archive - * or NULL when opening fails - */ - struct archive_file *(*open)(char * pathname); - - /** - * reset routine will move current read index in archive to default - * position and then the filenames from archives can be read - * via scan_next routine - */ - void (*scan_reset)(struct archive_file *); - - /** - * the read method will return corresponding files from archive - * (as pathnames) and move read index to next file. When there is no - * next file it return NULL. - */ - char *(*scan_next)(struct archive_file *); - - /** - * Opens an input_stream of a file within the archive. - * - * If this function succeeds, then the #input_stream "owns" - * the archive file and will automatically close it. - * - * @param path the path within the archive - */ - bool (*open_stream)(struct archive_file *, struct input_stream *is, - const char *path); - - /** - * closes archive file. - */ - void (*close)(struct archive_file *); - - /** - * suffixes handled by this plugin. - * last element in these arrays must always be a NULL - */ - const char *const*suffixes; -}; - bool archive_lookup(char *pathname, char **archive, char **inpath, char **suffix); #endif diff --git a/src/archive_internal.h b/src/archive_internal.h index 130d25d65..03439e826 100644 --- a/src/archive_internal.h +++ b/src/archive_internal.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2009 The Music Player Daemon Project + * Copyright (C) 2003-2010 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -21,7 +21,14 @@ #define MPD_ARCHIVE_INTERNAL_H struct archive_file { - int placeholder; + const struct archive_plugin *plugin; }; +static inline void +archive_file_init(struct archive_file *archive_file, + const struct archive_plugin *plugin) +{ + archive_file->plugin = plugin; +} + #endif diff --git a/src/archive_list.c b/src/archive_list.c index 8228fc961..2656726b5 100644 --- a/src/archive_list.c +++ b/src/archive_list.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2009 The Music Player Daemon Project + * Copyright (C) 2003-2010 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -17,50 +17,44 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include "config.h" #include "archive_list.h" -#include "archive_api.h" +#include "archive_plugin.h" #include "utils.h" -#include "config.h" +#include "archive/bz2_archive_plugin.h" +#include "archive/iso9660_archive_plugin.h" +#include "archive/zzip_archive_plugin.h" #include <string.h> #include <glib.h> -extern const struct archive_plugin bz2_plugin; -extern const struct archive_plugin zip_plugin; -extern const struct archive_plugin iso_plugin; - static const struct archive_plugin *const archive_plugins[] = { #ifdef HAVE_BZ2 - &bz2_plugin, + &bz2_archive_plugin, #endif -#ifdef HAVE_ZIP - &zip_plugin, +#ifdef HAVE_ZZIP + &zzip_archive_plugin, #endif -#ifdef HAVE_ISO - &iso_plugin, +#ifdef HAVE_ISO9660 + &iso9660_archive_plugin, #endif NULL }; -enum { - num_archive_plugins = G_N_ELEMENTS(archive_plugins)-1, -}; - /** which plugins have been initialized successfully? */ -static bool archive_plugins_enabled[num_archive_plugins+1]; +static bool archive_plugins_enabled[G_N_ELEMENTS(archive_plugins) - 1]; const struct archive_plugin * archive_plugin_from_suffix(const char *suffix) { - unsigned i; - if (suffix == NULL) return NULL; - for (i=0; i < num_archive_plugins; ++i) { + for (unsigned i = 0; archive_plugins[i] != NULL; ++i) { const struct archive_plugin *plugin = archive_plugins[i]; if (archive_plugins_enabled[i] && - stringFoundInStringArray(plugin->suffixes, suffix)) { + plugin->suffixes != NULL && + string_array_contains(plugin->suffixes, suffix)) { ++i; return plugin; } @@ -71,7 +65,7 @@ archive_plugin_from_suffix(const char *suffix) const struct archive_plugin * archive_plugin_from_name(const char *name) { - for (unsigned i = 0; i < num_archive_plugins; ++i) { + for (unsigned i = 0; archive_plugins[i] != NULL; ++i) { const struct archive_plugin *plugin = archive_plugins[i]; if (archive_plugins_enabled[i] && strcmp(plugin->name, name) == 0) @@ -84,7 +78,7 @@ void archive_plugin_print_all_suffixes(FILE * fp) { const char *const*suffixes; - for (unsigned i = 0; i < num_archive_plugins; ++i) { + for (unsigned i = 0; archive_plugins[i] != NULL; ++i) { const struct archive_plugin *plugin = archive_plugins[i]; if (!archive_plugins_enabled[i]) continue; @@ -101,7 +95,7 @@ void archive_plugin_print_all_suffixes(FILE * fp) void archive_plugin_init_all(void) { - for (unsigned i = 0; i < num_archive_plugins; ++i) { + for (unsigned i = 0; archive_plugins[i] != NULL; ++i) { const struct archive_plugin *plugin = archive_plugins[i]; if (plugin->init == NULL || archive_plugins[i]->init()) archive_plugins_enabled[i] = true; @@ -110,7 +104,7 @@ void archive_plugin_init_all(void) void archive_plugin_deinit_all(void) { - for (unsigned i = 0; i < num_archive_plugins; ++i) { + for (unsigned i = 0; archive_plugins[i] != NULL; ++i) { const struct archive_plugin *plugin = archive_plugins[i]; if (archive_plugins_enabled[i] && plugin->finish != NULL) archive_plugins[i]->finish(); diff --git a/src/archive_list.h b/src/archive_list.h index 55278fbc4..b65245ce9 100644 --- a/src/archive_list.h +++ b/src/archive_list.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2009 The Music Player Daemon Project + * Copyright (C) 2003-2010 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -20,8 +20,6 @@ #ifndef MPD_ARCHIVE_LIST_H #define MPD_ARCHIVE_LIST_H -#include "archive_api.h" - #include <stdio.h> struct archive_plugin; diff --git a/src/archive_plugin.c b/src/archive_plugin.c new file mode 100644 index 000000000..60da4d283 --- /dev/null +++ b/src/archive_plugin.c @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2003-2010 The Music Player Daemon Project + * http://www.musicpd.org + * + * 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 "archive_plugin.h" +#include "archive_internal.h" + +#include <assert.h> + +struct archive_file * +archive_file_open(const struct archive_plugin *plugin, const char *path, + GError **error_r) +{ + struct archive_file *file; + + assert(plugin != NULL); + assert(plugin->open != NULL); + assert(path != NULL); + assert(error_r == NULL || *error_r == NULL); + + file = plugin->open(path, error_r); + + if (file != NULL) { + assert(file->plugin != NULL); + assert(file->plugin->close != NULL); + assert(file->plugin->scan_reset != NULL); + assert(file->plugin->scan_next != NULL); + assert(file->plugin->open_stream != NULL); + assert(error_r == NULL || *error_r == NULL); + } else { + assert(error_r == NULL || *error_r != NULL); + } + + return file; +} + +void +archive_file_close(struct archive_file *file) +{ + assert(file != NULL); + assert(file->plugin != NULL); + assert(file->plugin->close != NULL); + + file->plugin->close(file); +} + +void +archive_file_scan_reset(struct archive_file *file) +{ + assert(file != NULL); + assert(file->plugin != NULL); + assert(file->plugin->scan_reset != NULL); + assert(file->plugin->scan_next != NULL); + + file->plugin->scan_reset(file); +} + +char * +archive_file_scan_next(struct archive_file *file) +{ + assert(file != NULL); + assert(file->plugin != NULL); + assert(file->plugin->scan_next != NULL); + + return file->plugin->scan_next(file); +} + +struct input_stream * +archive_file_open_stream(struct archive_file *file, + const char *path, GError **error_r) +{ + assert(file != NULL); + assert(file->plugin != NULL); + assert(file->plugin->open_stream != NULL); + + return file->plugin->open_stream(file, path, error_r); +} diff --git a/src/archive_plugin.h b/src/archive_plugin.h new file mode 100644 index 000000000..b08c93389 --- /dev/null +++ b/src/archive_plugin.h @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2003-2010 The Music Player Daemon Project + * http://www.musicpd.org + * + * 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. + */ + +#ifndef MPD_ARCHIVE_PLUGIN_H +#define MPD_ARCHIVE_PLUGIN_H + +#include <glib.h> + +#include <stdbool.h> + +struct input_stream; +struct archive_file; + +struct archive_plugin { + const char *name; + + /** + * optional, set this to NULL if the archive plugin doesn't + * have/need one this must false if there is an error and + * true otherwise + */ + bool (*init)(void); + + /** + * optional, set this to NULL if the archive plugin doesn't + * have/need one + */ + void (*finish)(void); + + /** + * tryes to open archive file and associates handle with archive + * returns pointer to handle used is all operations with this archive + * or NULL when opening fails + */ + struct archive_file *(*open)(const char *path_fs, GError **error_r); + + /** + * reset routine will move current read index in archive to default + * position and then the filenames from archives can be read + * via scan_next routine + */ + void (*scan_reset)(struct archive_file *); + + /** + * the read method will return corresponding files from archive + * (as pathnames) and move read index to next file. When there is no + * next file it return NULL. + */ + char *(*scan_next)(struct archive_file *); + + /** + * Opens an input_stream of a file within the archive. + * + * @param path the path within the archive + * @param error_r location to store the error occuring, or + * NULL to ignore errors + */ + struct input_stream *(*open_stream)(struct archive_file *af, + const char *path, + GError **error_r); + + /** + * closes archive file. + */ + void (*close)(struct archive_file *); + + /** + * suffixes handled by this plugin. + * last element in these arrays must always be a NULL + */ + const char *const*suffixes; +}; + +struct archive_file * +archive_file_open(const struct archive_plugin *plugin, const char *path, + GError **error_r); + +void +archive_file_close(struct archive_file *file); + +void +archive_file_scan_reset(struct archive_file *file); + +char * +archive_file_scan_next(struct archive_file *file); + +struct input_stream * +archive_file_open_stream(struct archive_file *file, + const char *path, GError **error_r); + +#endif |