]> git.sesse.net Git - vlc/commitdiff
access/stream_filter: add libarchive
authorFrancois Cartegnie <fcvlcdev@free.fr>
Wed, 16 Jul 2014 04:25:56 +0000 (13:25 +0900)
committerFrancois Cartegnie <fcvlcdev@free.fr>
Tue, 29 Jul 2014 14:01:26 +0000 (23:01 +0900)
Allows decompression and access through rar, lha, tar, ...
Mostly unseekable.

NEWS
configure.ac
modules/MODULES_LIST
modules/access/Makefile.am
modules/access/archive/access.c [new file with mode: 0644]
modules/access/archive/archive.c [new file with mode: 0644]
modules/access/archive/archive.h [new file with mode: 0644]
modules/access/archive/stream.c [new file with mode: 0644]
po/POTFILES.in

diff --git a/NEWS b/NEWS
index 78c10ce6df31f00cb96477f10a8a36f17685ba7a..1088a516757d1242b6a6ac9f5e17d8c42778da76 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -4,6 +4,7 @@ Changes between 2.2.x and 3.0.0-git:
 Access:
  * Support HDS (Http Dynamic Streaming) from Adobe (f4m, f4v, etc.)
  * New SMB access module using libdsm
+ * Can now decompress and extract through libarchive
 
 Service Discovery:
  * New NetBios service discovery using libdsm
index 677cc678518139bbae461de618151b861015df3e..065454160cb755bed8f47693364a63ea975ef9bb 100644 (file)
@@ -1595,6 +1595,11 @@ dnl
 
 EXTEND_HELP_STRING([Input plugins:])
 
+dnl
+dnl  libarchive access module
+dnl
+PKG_ENABLE_MODULES_VLC([ARCHIVE], [access_archive], [libarchive >= 2.8.5], (libarchive support), [auto])
+
 dnl
 dnl  live555 input
 dnl
index ae980e716c06f4094c174863163b0fb9c76d9097..6fb7014ee89a9f3e1bf666f64dd33a121e05db5d 100644 (file)
@@ -36,6 +36,7 @@ $Id$
  * android_surface: video output for Android, based on Surface
  * antiflicker: anti-flicker video filter
  * araw: Pseudo audio decoder for raw PCM
+ * archive: libarchive based access and stream filter
  * asf: ASF demuxer
  * atmo: Ambilight-like video-output
  * attachment: Attachment access module
index 9116ee1b7eb081c375365d2b794ccdfc7c74aa49..c2818432ae1233f35fdc647ce5211a1db320aa37 100644 (file)
@@ -64,6 +64,12 @@ libzip_plugin_la_LIBADD += libunzip.la
 endif
 endif
 
+libaccess_archive_plugin_la_SOURCES = access/archive/access.c access/archive/stream.c \
+                                       access/archive/archive.h access/archive/archive.c
+libaccess_archive_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(accessdir)'
+libaccess_archive_plugin_la_LIBADD = $(ARCHIVE_LIBS)
+access_LTLIBRARIES += $(LTLIBaccess_archive)
+EXTRA_LTLIBRARIES += libaccess_archive_plugin.la
 
 ### Audio capture ###
 
diff --git a/modules/access/archive/access.c b/modules/access/archive/access.c
new file mode 100644 (file)
index 0000000..789d347
--- /dev/null
@@ -0,0 +1,303 @@
+/*****************************************************************************
+ * access.c: libarchive based access
+ *****************************************************************************
+ * Copyright (C) 2014 Videolan Team
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#include "archive.h"
+
+#include <vlc_access.h>
+#include <vlc_url.h>
+#include <vlc_stream.h>
+
+#include <archive.h>
+#include <archive_entry.h>
+
+struct access_sys_t
+{
+    struct archive *p_archive;
+    bool b_source_canseek;
+    uint8_t buffer[ARCHIVE_READ_SIZE];
+
+    struct archive_entry *p_entry;
+    stream_t *p_stream;
+    char *psz_uri;
+    bool b_seekable; /* Is our archive type seekable ? */
+};
+
+static ssize_t Read(access_t *p_access, uint8_t *p_data, size_t i_size)
+{
+    access_sys_t *p_sys = p_access->p_sys;
+
+    size_t i_read = 0;
+
+    i_read = archive_read_data(p_sys->p_archive, p_data, i_size);
+
+    if (i_read > 0)
+        p_access->info.i_pos += i_read;
+
+    if (i_size > 0 && i_read <= 0)
+        p_access->info.b_eof = true;
+
+    return i_read;
+}
+
+static int Seek(access_t *p_access, uint64_t i_pos)
+{
+    access_sys_t *p_sys = p_access->p_sys;
+
+    if (!p_sys->b_seekable)
+        return VLC_EGENERIC;
+
+    int64_t i_ret = archive_seek_data(p_sys->p_archive, i_pos, SEEK_SET);
+    if ( i_ret < ARCHIVE_OK )
+        return VLC_EGENERIC;
+    p_access->info.i_pos = i_ret;
+
+    return VLC_SUCCESS;
+}
+
+static ssize_t ReadCallback(struct archive *p_archive, void *p_object, const void **pp_buffer)
+{
+    VLC_UNUSED(p_archive);
+    access_t *p_access = (access_t*)p_object;
+    access_sys_t *p_sys = p_access->p_sys;
+
+    *pp_buffer = &p_sys->buffer;
+    return stream_Read(p_sys->p_stream, &p_sys->buffer, ARCHIVE_READ_SIZE);
+}
+
+static ssize_t SkipCallback(struct archive *p_archive, void *p_object, ssize_t i_request)
+{
+    VLC_UNUSED(p_archive);
+    access_t *p_access = (access_t*)p_object;
+    access_sys_t *p_sys = p_access->p_sys;
+    ssize_t i_skipped = 0;
+
+    /* be smart as small seeks converts to reads */
+    if (p_sys->b_source_canseek)
+    {
+        int64_t i_pos = stream_Tell(p_sys->p_stream);
+        if (i_pos >=0)
+            stream_Seek(p_sys->p_stream, i_pos + i_request);
+        i_skipped = stream_Tell(p_sys->p_stream) - i_pos;
+    }
+    else while(i_request)
+    {
+        int i_skip = __MIN(INT32_MAX, i_request);
+        int i_read = stream_Read(p_sys->p_stream, NULL, i_skip);
+        if (i_read > 0)
+            i_skipped += i_read;
+        else
+            break;
+        i_request -= i_read;
+    }
+
+    return i_skipped;
+}
+
+static ssize_t SeekCallback(struct archive *p_archive, void *p_object, ssize_t i_offset, int i_whence)
+{
+    VLC_UNUSED(p_archive);
+    access_t *p_access = (access_t*)p_object;
+    access_sys_t *p_sys = p_access->p_sys;
+
+    ssize_t i_pos;
+
+    switch(i_whence)
+    {
+    case SEEK_CUR:
+        i_pos = stream_Tell(p_sys->p_stream);
+        break;
+    case SEEK_SET:
+        i_pos = 0;
+        break;
+    case SEEK_END:
+        i_pos = stream_Size(p_sys->p_stream) - 1;
+        break;
+    default:
+        return -1;
+    }
+
+    if (i_pos < 0)
+        return -1;
+
+    stream_Seek(p_sys->p_stream, i_pos + i_offset); /* We don't care about return val */
+    return stream_Tell(p_sys->p_stream);
+}
+
+static int OpenCallback(struct archive *p_archive, void *p_object)
+{
+    VLC_UNUSED(p_archive);
+    access_t *p_access = (access_t*)p_object;
+    access_sys_t *p_sys = p_access->p_sys;
+
+    p_sys->p_stream = stream_UrlNew( p_access, p_sys->psz_uri );
+    if(!p_sys->p_stream)
+        return ARCHIVE_FATAL;
+
+    /* Seek callback must only be set if calls are guaranteed to succeed */
+    stream_Control(p_sys->p_stream, STREAM_CAN_SEEK, &p_sys->b_source_canseek);
+    if(p_sys->b_source_canseek)
+        archive_read_set_seek_callback(p_sys->p_archive, SeekCallback);
+
+    return ARCHIVE_OK;
+}
+
+static int CloseCallback(struct archive *p_archive, void *p_object)
+{
+    VLC_UNUSED(p_archive);
+    access_t *p_access = (access_t*)p_object;
+
+    if (p_access->p_sys->p_stream)
+        stream_Delete(p_access->p_sys->p_stream);
+
+    return ARCHIVE_OK;
+}
+
+static int Control(access_t *p_access, int i_query, va_list args)
+{
+    access_sys_t *p_sys = p_access->p_sys;
+
+    switch (i_query)
+    {
+
+    case ACCESS_CAN_SEEK:
+        *va_arg(args, bool *)= p_sys->b_seekable;
+        break;
+
+    case ACCESS_CAN_FASTSEEK:
+        if (!p_sys->b_seekable || !p_sys->p_stream)
+        {
+            *va_arg( args, bool* ) = false;
+            break;
+        }
+        else
+            return stream_vaControl( p_sys->p_stream, i_query, args );
+
+    case ACCESS_SET_PAUSE_STATE:
+        break;
+
+    case ACCESS_CAN_PAUSE:
+    case ACCESS_CAN_CONTROL_PACE:
+        *va_arg(args, bool *) = true;
+        break;
+
+    case ACCESS_GET_SIZE:
+        *va_arg(args, uint64_t *) = archive_entry_size(p_sys->p_entry);
+        break;
+
+    case ACCESS_GET_PTS_DELAY:
+        *va_arg(args, int64_t *) = DEFAULT_PTS_DELAY;
+        break;
+
+    default:
+        return VLC_EGENERIC;
+    }
+    return VLC_SUCCESS;
+}
+
+int AccessOpen(vlc_object_t *p_object)
+{
+    access_t *p_access = (access_t*)p_object;
+
+    if (!strchr(p_access->psz_location, ARCHIVE_SEP_CHAR))
+        return VLC_EGENERIC;
+
+    char *psz_base = strdup(p_access->psz_location);
+    if (!psz_base)
+        return VLC_EGENERIC;
+    char *psz_name = strchr(psz_base, ARCHIVE_SEP_CHAR);
+    *psz_name++ = '\0';
+
+    if (decode_URI(psz_base) == NULL)
+    {
+        free(psz_base);
+        return VLC_EGENERIC;
+    }
+
+    access_sys_t *p_sys = p_access->p_sys = calloc(1, sizeof(access_sys_t));
+    p_sys->p_archive = archive_read_new();
+    if (!p_sys->p_archive)
+    {
+        msg_Err(p_access, "can't create libarchive instance: %s",
+                archive_error_string(p_sys->p_archive));
+        free(psz_base);
+        goto error;
+    }
+
+    EnableArchiveFormats(p_sys->p_archive);
+
+    p_sys->psz_uri = psz_base;
+
+    if (archive_read_open2(p_sys->p_archive, p_access, OpenCallback, ReadCallback, SkipCallback, CloseCallback) != ARCHIVE_OK)
+    {
+        msg_Err(p_access, "can't open archive: %s",
+                archive_error_string(p_sys->p_archive));
+        AccessClose(p_object);
+        return VLC_EGENERIC;
+    }
+
+    bool b_present = false;
+    while(archive_read_next_header(p_sys->p_archive, &p_sys->p_entry) == ARCHIVE_OK)
+    {
+        if (!strcmp(archive_entry_pathname(p_sys->p_entry), psz_name))
+        {
+            b_present = true;
+            break;
+        }
+        msg_Dbg(p_access, "skipping entry %s != %s", archive_entry_pathname(p_sys->p_entry), psz_name);
+    }
+
+    if (!b_present)
+    {
+        msg_Err(p_access, "entry '%s' not found in archive", psz_name);
+        /* entry not found */
+        goto error;
+    }
+
+    msg_Dbg(p_access, "reading entry %s %"PRId64, archive_entry_pathname(p_sys->p_entry),
+                                                  archive_entry_size(p_sys->p_entry));
+
+    /* try to guess if it is seekable or not (does not depend on backend) */
+    p_sys->b_seekable = (archive_seek_data(p_sys->p_archive, 0, SEEK_SET) >= 0);
+
+    p_access->pf_read    = Read;
+    p_access->pf_block   = NULL; /* libarchive's zerocopy keeps owning block :/ */
+    p_access->pf_control = Control;
+    p_access->pf_seek    = Seek;
+
+    access_InitFields(p_access);
+
+    return VLC_SUCCESS;
+
+error:
+    AccessClose(p_object);
+    return VLC_EGENERIC;
+}
+
+void AccessClose(vlc_object_t *p_object)
+{
+    access_t *p_access = (access_t*)p_object;
+    access_sys_t *p_sys = p_access->p_sys;
+
+    if (p_sys->p_archive)
+        archive_read_free(p_sys->p_archive);
+
+    free(p_sys->psz_uri);
+    free(p_sys);
+}
diff --git a/modules/access/archive/archive.c b/modules/access/archive/archive.c
new file mode 100644 (file)
index 0000000..212937a
--- /dev/null
@@ -0,0 +1,111 @@
+/*****************************************************************************
+ * archive.c: libarchive based stream filter
+ *****************************************************************************
+ * Copyright (C) 2014 Videolan Team
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#include "archive.h"
+
+#include <vlc_plugin.h>
+#include <vlc_stream.h>
+
+#include <archive.h>
+
+/****************************************************************************
+ * Module descriptor
+ *****************************************************************************/
+vlc_module_begin()
+    set_shortname( "libarchive" )
+    set_category( CAT_INPUT )
+    set_subcategory( SUBCAT_INPUT_ACCESS )
+    set_description( N_( "libarchive access" ) )
+    set_capability( "access", 0 )
+    add_shortcut( "archive" )
+    set_callbacks( AccessOpen, AccessClose )
+    add_submodule()
+        set_shortname( "libarchive" )
+        set_subcategory( SUBCAT_INPUT_STREAM_FILTER )
+        set_description( N_( "libarchive stream filter" ) )
+        set_capability( "stream_filter", 14 ) /* less than rar and gzip */
+        set_callbacks( StreamOpen, StreamClose )
+vlc_module_end()
+
+bool ProbeArchiveFormat(stream_t *p_stream)
+{
+    struct
+    {
+        const uint16_t i_offset;
+        const uint8_t  i_length;
+        const char * const p_bytes;
+    } const magicbytes[9] = {
+        /* keep heaviest at top */
+        { 257, 5, "ustar" },        //TAR
+        { 0,   7, "Rar!\x1A\x07" }, //RAR
+        { 0,   4, "xar!" },         //XAR
+        { 2,   3, "-lh" },          //LHA/LHZ
+        { 0,   3, "PAX" },          //PAX
+        { 0,   6, "070707" },       //CPIO
+        { 0,   6, "070701" },       //CPIO
+        { 0,   6, "070702" },       //CPIO
+        { 0,   4, "MSCH" },         //CAB
+    };
+
+    const uint8_t *p_peek;
+    int i_peek = stream_Peek(p_stream, &p_peek, magicbytes[0].i_offset + magicbytes[0].i_length);
+
+    for(int i=0; i<9;i++)
+    {
+        if (i_peek <= magicbytes[i].i_offset + magicbytes[i].i_length)
+            continue;
+        else if ( !memcmp(p_peek + magicbytes[i].i_offset,
+                          magicbytes[i].p_bytes,
+                          magicbytes[i].i_length) )
+            return true;
+    }
+
+    return false;
+}
+
+void EnableArchiveFormats(struct archive *p_archive)
+{
+    //    archive_read_support_filter_bzip2(p_archive);
+    //    archive_read_support_filter_compress(p_archive);
+    //    archive_read_support_filter_gzip(p_archive);
+    //    archive_read_support_filter_grzip(p_archive);
+    //    archive_read_support_filter_lrzip(p_archive);
+    //    archive_read_support_filter_lzip(p_archive);
+    archive_read_support_filter_lzma(p_archive);
+    archive_read_support_filter_lzop(p_archive);
+    archive_read_support_filter_none(p_archive);
+    archive_read_support_filter_rpm(p_archive);
+    archive_read_support_filter_uu(p_archive);
+    archive_read_support_filter_xz(p_archive);
+
+    //    archive_read_support_format_7zip(p_archive);
+    archive_read_support_format_ar(p_archive);
+    archive_read_support_format_cab(p_archive);
+    archive_read_support_format_cpio(p_archive);
+    archive_read_support_format_gnutar(p_archive);
+    //    archive_read_support_format_iso9660(p_archive);
+    archive_read_support_format_lha(p_archive);
+    archive_read_support_format_mtree(p_archive);
+    archive_read_support_format_rar(p_archive);
+    archive_read_support_format_raw(p_archive);
+    archive_read_support_format_tar(p_archive);
+    archive_read_support_format_xar(p_archive);
+    //    archive_read_support_format_zip(p_archive);
+}
diff --git a/modules/access/archive/archive.h b/modules/access/archive/archive.h
new file mode 100644 (file)
index 0000000..4e6d7cc
--- /dev/null
@@ -0,0 +1,39 @@
+/*****************************************************************************
+ * archive.h: libarchive access & stream filter
+ *****************************************************************************
+ * Copyright (C) 2014 Videolan Team
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <vlc_common.h>
+
+int AccessOpen(vlc_object_t *object);
+void AccessClose(vlc_object_t *object);
+
+int StreamOpen(vlc_object_t *object);
+void StreamClose(vlc_object_t *object);
+
+bool ProbeArchiveFormat(stream_t *p_stream);
+
+struct archive;
+void EnableArchiveFormats(struct archive *p_archive);
+
+#define ARCHIVE_READ_SIZE 8192
+#define ARCHIVE_SEP_CHAR '|'
diff --git a/modules/access/archive/stream.c b/modules/access/archive/stream.c
new file mode 100644 (file)
index 0000000..f39b46e
--- /dev/null
@@ -0,0 +1,223 @@
+/*****************************************************************************
+ * stream.c: libarchive based stream filter
+ *****************************************************************************
+ * Copyright (C) 2014 Videolan Team
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#include "archive.h"
+
+#include <vlc_stream.h>
+#include <vlc_url.h>
+#include <vlc_input_item.h>
+
+#include <archive.h>
+#include <archive_entry.h>
+
+struct stream_sys_t
+{
+    struct archive *p_archive;
+    bool b_source_canseek;
+    uint8_t buffer[ARCHIVE_READ_SIZE];
+};
+
+static int Peek(stream_t *p_stream, const uint8_t **pp_peek, unsigned int i_peek)
+{
+    VLC_UNUSED(p_stream);
+    VLC_UNUSED(pp_peek);
+    VLC_UNUSED(i_peek);
+    return 0;
+}
+
+static int Control(stream_t *p_stream, int i_query, va_list args)
+{
+    switch( i_query )
+    {
+        case STREAM_IS_DIRECTORY:
+            *va_arg( args, bool* ) = true;
+            break;
+
+        case STREAM_CAN_SEEK:
+        case STREAM_CAN_FASTSEEK:
+        case STREAM_GET_SIZE:
+        case STREAM_GET_POSITION:
+        case STREAM_SET_POSITION:
+        case STREAM_UPDATE_SIZE:
+        case STREAM_SET_RECORD_STATE:
+        case STREAM_GET_CONTENT_TYPE:
+            return VLC_EGENERIC;
+
+        default:
+            return stream_vaControl( p_stream->p_source, i_query, args );
+    }
+
+    return VLC_SUCCESS;
+}
+
+static ssize_t ReadCallback(struct archive *p_archive, void *p_object, const void **pp_buffer)
+{
+    VLC_UNUSED(p_archive);
+    stream_t *p_stream = (stream_t*)p_object;
+
+    *pp_buffer = &p_stream->p_sys->buffer;
+    return stream_Read(p_stream->p_source, &p_stream->p_sys->buffer, ARCHIVE_READ_SIZE);
+}
+
+static ssize_t SkipCallback(struct archive *p_archive, void *p_object, ssize_t i_request)
+{
+    VLC_UNUSED(p_archive);
+    stream_t *p_stream = (stream_t*)p_object;
+    ssize_t i_skipped = 0;
+
+    /* be smart as small seeks converts to reads */
+    if (p_stream->p_sys->b_source_canseek)
+    {
+        int64_t i_pos = stream_Tell(p_stream->p_source);
+        if (i_pos >=0)
+            stream_Seek(p_stream->p_source, i_pos + i_request);
+        i_skipped = stream_Tell(p_stream->p_source) - i_pos;
+    }
+    else while(i_request)
+    {
+        int i_skip = __MIN(INT32_MAX, i_request);
+        int i_read = stream_Read(p_stream->p_source, NULL, i_skip);
+        if (i_read > 0)
+            i_skipped += i_read;
+        else
+            break;
+        i_request -= i_read;
+    }
+
+    return i_skipped;
+}
+
+static ssize_t SeekCallback(struct archive *p_archive, void *p_object, ssize_t i_offset, int i_whence)
+{
+    VLC_UNUSED(p_archive);
+    stream_t *p_stream = (stream_t*)p_object;
+    ssize_t i_pos;
+
+    switch(i_whence)
+    {
+    case SEEK_CUR:
+        i_pos = stream_Tell(p_stream->p_source);
+        break;
+    case SEEK_SET:
+        i_pos = 0;
+        break;
+    case SEEK_END:
+        i_pos = stream_Size(p_stream->p_source) - 1;
+        break;
+    default:
+        return -1;
+    }
+
+    if (i_pos < 0)
+        return -1;
+
+    stream_Seek(p_stream->p_source, i_pos + i_offset); /* We don't care about return val */
+    return stream_Tell(p_stream->p_source);
+}
+
+static int Browse(stream_t *p_stream, input_item_node_t *p_node)
+{
+    stream_sys_t *p_sys = p_stream->p_sys;
+    struct archive_entry *p_entry;
+
+    while(archive_read_next_header(p_sys->p_archive, &p_entry) == ARCHIVE_OK)
+    {
+        char *psz_uri = NULL;
+        char *psz_access_uri = NULL;
+        int i_ret = asprintf(&psz_access_uri, "%s://%s%c%s", p_stream->psz_access,
+                             p_stream->psz_path, ARCHIVE_SEP_CHAR, archive_entry_pathname(p_entry));
+        if (i_ret == -1)
+            goto error;
+        i_ret = asprintf(&psz_uri, "archive://%s", psz_access_uri);
+        free(psz_access_uri);
+        if( i_ret == -1 )
+            goto error;
+
+        input_item_t *p_item = input_item_New(psz_uri, archive_entry_pathname(p_entry));
+        free( psz_uri );
+        if(p_item == NULL)
+            goto error;
+
+        input_item_CopyOptions(p_node->p_item, p_item);
+        input_item_node_AppendItem(p_node, p_item);
+        msg_Dbg(p_stream, "declaring playlist entry %s", archive_entry_pathname(p_entry));
+        input_item_Release(p_item);
+    }
+
+    return VLC_SUCCESS;
+
+error:
+    return VLC_ENOITEM;
+}
+
+int StreamOpen(vlc_object_t *p_object)
+{
+    stream_t *p_stream = (stream_t*) p_object;
+    stream_sys_t *p_sys = p_stream->p_sys;
+
+    if (!ProbeArchiveFormat(p_stream->p_source))
+        return VLC_EGENERIC;
+
+    p_stream->p_sys = p_sys = calloc( 1, sizeof( *p_sys ) );
+    if( !p_sys )
+        return VLC_ENOMEM;
+
+    p_sys->p_archive = archive_read_new();
+    if (!p_sys->p_archive)
+    {
+        msg_Err(p_stream, "can't create libarchive instance: %s",
+                archive_error_string(p_sys->p_archive));
+        StreamClose(p_object);
+        return VLC_EGENERIC;
+    }
+
+    EnableArchiveFormats(p_sys->p_archive);
+
+    /* Seek callback must only be set if calls are guaranteed to succeed */
+    stream_Control(p_stream->p_source, STREAM_CAN_SEEK, &p_sys->b_source_canseek);
+    if(p_sys->b_source_canseek)
+        archive_read_set_seek_callback(p_sys->p_archive, SeekCallback);
+
+    if (archive_read_open2(p_sys->p_archive, p_stream, NULL, ReadCallback, SkipCallback, NULL) != ARCHIVE_OK)
+    {
+        msg_Err(p_stream, "can't open archive: %s",
+                archive_error_string(p_sys->p_archive));
+        StreamClose(p_object);
+        return VLC_EGENERIC;
+    }
+
+    p_stream->pf_read = NULL;
+    p_stream->pf_peek = Peek;
+    p_stream->pf_control = Control;
+    p_stream->pf_readdir = Browse;
+
+    return VLC_SUCCESS;
+}
+
+void StreamClose(vlc_object_t *object)
+{
+    stream_t *p_stream = (stream_t*)object;
+    stream_sys_t *p_sys = p_stream->p_sys;
+
+    if (p_sys->p_archive)
+        archive_read_free(p_sys->p_archive);
+
+    free(p_sys);
+}
index 09b236979e4a95ec12196bf36b30aece2a2abce9..5d4742d87f0b88a687d1fcccd9a771d1099f3d00 100644 (file)
@@ -179,6 +179,7 @@ lib/vlm.c
 
 # modules
 modules/access/alsa.c
+modules/access/archive/archive.c
 modules/access/attachment.c
 modules/access/avio.h
 modules/access/bd/bd.c