diff options
Diffstat (limited to 'src/archive')
-rw-r--r-- | src/archive/bz2_archive_plugin.c | 300 | ||||
-rw-r--r-- | src/archive/bz2_archive_plugin.h | 25 | ||||
-rw-r--r-- | src/archive/bz2_plugin.c | 284 | ||||
-rw-r--r-- | src/archive/iso9660_archive_plugin.c | 284 | ||||
-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 | 241 | ||||
-rw-r--r-- | src/archive/zzip_archive_plugin.h | 25 |
9 files changed, 900 insertions, 719 deletions
diff --git a/src/archive/bz2_archive_plugin.c b/src/archive/bz2_archive_plugin.c new file mode 100644 index 000000000..75b4b1ece --- /dev/null +++ b/src/archive/bz2_archive_plugin.c @@ -0,0 +1,300 @@ +/* + * 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, + G_GNUC_UNUSED 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); + + bis->archive = context; + + bis->base.ready = true; + bis->base.seekable = false; + + if (!bz2_alloc(bis, error_r)) { + 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); + + 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/archive/bz2_archive_plugin.h b/src/archive/bz2_archive_plugin.h new file mode 100644 index 000000000..199049008 --- /dev/null +++ b/src/archive/bz2_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_BZ2_H +#define MPD_ARCHIVE_BZ2_H + +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..38003da94 --- /dev/null +++ b/src/archive/iso9660_archive_plugin.c @@ -0,0 +1,284 @@ +/* + * 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); + + 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); +} + + +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..7e59a0935 --- /dev/null +++ b/src/archive/zzip_archive_plugin.c @@ -0,0 +1,241 @@ +/* + * 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); + + 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); + 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 |