[vlc-devel] [PATCH 1/2] access/stream_filter: add libarchive
Francois Cartegnie
fcvlcdev at free.fr
Thu Jul 24 17:24:43 CEST 2014
Allows decompression and access through rar, lha, tar, ...
Mostly unseekable.
---
configure.ac | 5 +
modules/access/Makefile.am | 4 +
modules/access/archive/access.c | 179 ++++++++++++++++++++
modules/access/archive/archive.h | 36 ++++
modules/access/archive/module.c | 110 ++++++++++++
modules/access/archive/stream.c | 354 +++++++++++++++++++++++++++++++++++++++
po/POTFILES.in | 1 +
7 files changed, 689 insertions(+)
create mode 100644 modules/access/archive/access.c
create mode 100644 modules/access/archive/archive.h
create mode 100644 modules/access/archive/module.c
create mode 100644 modules/access/archive/stream.c
diff --git a/configure.ac b/configure.ac
index de07e28..416b21b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1584,6 +1584,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
AC_ARG_ENABLE(live555,
diff --git a/modules/access/Makefile.am b/modules/access/Makefile.am
index 1094192..0d77c87 100644
--- a/modules/access/Makefile.am
+++ b/modules/access/Makefile.am
@@ -64,6 +64,10 @@ 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/module.c
+libaccess_archive_plugin_la_LIBADD = $(ARCHIVE_LIBS)
+access_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
index 0000000..c8d4532
--- /dev/null
+++ b/modules/access/archive/access.c
@@ -0,0 +1,179 @@
+/*****************************************************************************
+ * 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 <archive.h>
+#include <archive_entry.h>
+
+struct access_sys_t
+{
+ struct archive *p_archive;
+ struct archive_entry *p_entry;
+ bool b_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;
+
+ 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 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:
+ case ACCESS_CAN_FASTSEEK:
+ *va_arg(args, bool *)= p_sys->b_seekable;
+ 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;
+ case ACCESS_SET_PAUSE_STATE:
+ 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, '|'))
+ return VLC_EGENERIC;
+
+ char *psz_base = strdup(p_access->psz_location);
+ if (!psz_base)
+ return VLC_EGENERIC;
+ char *psz_name = strchr(psz_base, '|');
+ *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, archive_error_string(p_sys->p_archive));
+ goto error;
+ }
+
+ EnableArchiveFormats(p_sys->p_archive);
+
+ if (archive_read_open_filename(p_sys->p_archive, psz_base, 4096) != ARCHIVE_OK)
+ {
+ msg_Err(p_access, archive_error_string(p_sys->p_archive));
+ goto error;
+ }
+
+ 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 */
+ 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);
+
+ free(psz_base);
+
+ return VLC_SUCCESS;
+
+error:
+ free(psz_base);
+ 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);
+}
diff --git a/modules/access/archive/archive.h b/modules/access/archive/archive.h
new file mode 100644
index 0000000..e716440
--- /dev/null
+++ b/modules/access/archive/archive.h
@@ -0,0 +1,36 @@
+/*****************************************************************************
+ * 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);
diff --git a/modules/access/archive/module.c b/modules/access/archive/module.c
new file mode 100644
index 0000000..df81ec5
--- /dev/null
+++ b/modules/access/archive/module.c
@@ -0,0 +1,110 @@
+/*****************************************************************************
+ * module.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/stream.c b/modules/access/archive/stream.c
new file mode 100644
index 0000000..9c52b7e
--- /dev/null
+++ b/modules/access/archive/stream.c
@@ -0,0 +1,354 @@
+/*****************************************************************************
+ * 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 <archive.h>
+#include <archive_entry.h>
+
+#define READ_SIZE 8192
+
+struct stream_sys_t
+{
+ struct archive *p_archive;
+ struct archive_entry *p_entry;
+ size_t i_pos;
+ size_t i_len;
+ void *p_peek_buffer;
+ size_t i_peek_buffer;
+ bool b_seekable;
+ bool b_source_canseek;
+ uint8_t buffer[READ_SIZE];
+};
+
+static int Read(stream_t *p_stream, void *p_data, unsigned int i_size)
+{
+ stream_sys_t *p_sys = p_stream->p_sys;
+
+ if (p_sys->i_len && p_sys->i_len - p_sys->i_pos < UINT32_MAX)
+ i_size = __MIN( i_size, p_sys->i_len - p_sys->i_pos );
+
+ unsigned int i_total = 0;
+
+ if (p_sys->p_peek_buffer)
+ {
+ if (likely(i_size >= p_sys->i_peek_buffer))
+ {
+ if(p_data)
+ memcpy(p_data, p_sys->p_peek_buffer, p_sys->i_peek_buffer);
+ i_size -= p_sys->i_peek_buffer;
+ i_total += p_sys->i_peek_buffer;
+ p_sys->i_peek_buffer = 0;
+ FREENULL(p_sys->p_peek_buffer);
+ }
+ else
+ {
+ if (p_data)
+ memcpy(p_data, p_sys->p_peek_buffer, i_size);
+ memmove(p_sys->p_peek_buffer, (uint8_t*)p_sys->p_peek_buffer+i_size, p_sys->i_peek_buffer - i_size);
+ i_total += i_size;
+ p_sys->i_peek_buffer -= i_size;
+ i_size = 0;
+ }
+ }
+
+ if (i_size)
+ {
+ uint8_t *p_dummy_buffer = (p_data) ? NULL : malloc(i_size); /* required for skip reads */
+ uint8_t *p_buffer = (p_data) ? (uint8_t *)p_data + i_total : p_dummy_buffer;
+
+ if (!p_buffer)
+ return 0;
+
+ ssize_t i_read = archive_read_data(p_sys->p_archive, p_buffer, i_size);
+ if (i_read > 0)
+ i_total += i_read;
+
+ free(p_dummy_buffer);
+ }
+
+ p_sys->i_pos += i_total;
+
+ return i_total;
+}
+
+static int Peek(stream_t *p_stream, const uint8_t **pp_peek, unsigned int i_peek)
+{
+ stream_sys_t *p_sys = p_stream->p_sys;
+
+ if (!p_sys->p_peek_buffer || i_peek > p_sys->i_peek_buffer)
+ {
+ void *p_realloced = realloc(p_sys->p_peek_buffer, i_peek);
+ if (!p_realloced)
+ return 0;
+
+ p_sys->p_peek_buffer = p_realloced;
+ }
+
+ if (i_peek > p_sys->i_peek_buffer)
+ {
+ ssize_t i_read = archive_read_data(p_sys->p_archive,
+ (uint8_t*)p_sys->p_peek_buffer + p_sys->i_peek_buffer,
+ i_peek - p_sys->i_peek_buffer);
+ if (i_read < 0)
+ return 0;
+
+ p_sys->i_peek_buffer += i_read;
+ }
+
+ *pp_peek = p_sys->p_peek_buffer;
+
+ return p_sys->i_peek_buffer;
+}
+
+static int Control(stream_t *p_stream, int i_query, va_list args)
+{
+ stream_sys_t *p_sys = p_stream->p_sys;
+
+ switch( i_query )
+ {
+ case STREAM_GET_POSITION:
+ *va_arg( args, uint64_t* ) = p_sys->i_pos;
+ break;
+
+ case STREAM_GET_SIZE:
+ *va_arg( args, uint64_t* ) = p_sys->i_len;
+ break;
+
+ case STREAM_CAN_SEEK:
+ *va_arg( args, bool* ) = p_sys->b_seekable;
+ break;
+
+ case STREAM_CAN_FASTSEEK:
+ if (!p_sys->b_seekable)
+ {
+ *va_arg( args, bool* ) = false;
+ break;
+ }
+ else
+ return stream_vaControl( p_stream->p_source, i_query, args );
+
+ case STREAM_SET_POSITION:
+ {
+ if (!p_sys->b_seekable)
+ return VLC_EGENERIC;
+ uint64_t i_pos = va_arg( args, uint64_t );
+ int64_t i_ret = archive_seek_data( p_sys->p_archive, i_pos, SEEK_SET );
+ if (i_ret < 0)
+ return VLC_EGENERIC;
+ p_sys->i_pos = i_ret;
+ break;
+ }
+
+ 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 int OpenCallback(struct archive *p_archive, void *p_object)
+{
+ VLC_UNUSED(p_archive);
+ VLC_UNUSED(p_object);
+
+ return ARCHIVE_OK;
+}
+
+static int CloseCallback(struct archive *p_archive, void *p_object)
+{
+ VLC_UNUSED(p_archive);
+ VLC_UNUSED(p_object);
+
+ return ARCHIVE_OK;
+}
+
+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, 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);
+}
+
+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 it is 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, OpenCallback, ReadCallback, SkipCallback, CloseCallback) != ARCHIVE_OK)
+ {
+ msg_Err(p_stream, "can't create libarchive instance: %s",
+ archive_error_string(p_sys->p_archive));
+ StreamClose(p_object);
+ return VLC_EGENERIC;
+ }
+
+ char *psz_base = strdup(p_stream->psz_path);
+ if (!psz_base)
+ {
+ archive_read_free(p_sys->p_archive);
+ free(p_sys);
+ return VLC_ENOMEM;
+ }
+ char *psz_name = strchr(psz_base, '|');
+ if (psz_name)
+ *psz_name++ = '\0';
+
+ if (decode_URI(psz_base) == NULL)
+ {
+ free(psz_base);
+ archive_read_free(p_sys->p_archive);
+ free(p_sys);
+ return VLC_EGENERIC;
+ }
+
+ bool b_present = false;
+ while(archive_read_next_header(p_sys->p_archive, &p_sys->p_entry) == ARCHIVE_OK)
+ {
+ if (!psz_name || !strcmp(archive_entry_pathname(p_sys->p_entry), psz_name))
+ {
+ b_present = true;
+ break;
+ }
+ msg_Dbg(p_stream, "skipping entry %s != %s", archive_entry_pathname(p_sys->p_entry), psz_name);
+ }
+
+ if (!b_present)
+ {
+ msg_Err(p_stream, "entry '%s' not found in archive '%s'", psz_name, psz_base);
+ /* entry not found */
+ free(psz_base);
+ archive_read_free(p_sys->p_archive);
+ free(p_sys);
+ return VLC_EGENERIC;
+ }
+ free(psz_base);
+
+ p_sys->b_seekable = p_sys->b_source_canseek &&
+ (archive_seek_data(p_sys->p_archive, 0, SEEK_SET) >= 0);
+
+ p_sys->i_len = archive_entry_size(p_sys->p_entry);
+
+ p_stream->pf_read = Read;
+ p_stream->pf_peek = Peek;
+ p_stream->pf_control = Control;
+
+ 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);
+}
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 09b2369..d10e537 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -179,6 +179,7 @@ lib/vlm.c
# modules
modules/access/alsa.c
+modules/access/archive/module.c
modules/access/attachment.c
modules/access/avio.h
modules/access/bd/bd.c
--
1.9.3
More information about the vlc-devel
mailing list