1
mirror of https://github.com/mpv-player/mpv synced 2024-10-18 10:25:02 +02:00
mpv/demux/demux_libarchive.c
wm4 a48a8a746e demux_libarchive: don't allow probing to read unlimited data
Instead, allow reading 2KB only. This seems to be sufficient for
libarchive to recognize zip, 7z, rar, tar. Good enough.

This is implemented by creating an in-memory stream with a copy of
the file header. If libarchive succeeds opening this, the actual
stream is opened.

Allowing unlimited reading could break unseekable streams, such as
playing from http servers with no range request support or pipes.

Also, we try not to read too much data in the first probe pass. Some
slow network streams like shoutcast services could make probing much
slower if we allow it to read too much. In the second probing pass,
actually allow 200KB.
2015-08-24 22:26:07 +02:00

107 lines
3.1 KiB
C

/*
* This file is part of mpv.
*
* mpv 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.
*
* mpv 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 mpv. If not, see <http://www.gnu.org/licenses/>.
*/
#include <archive.h>
#include <archive_entry.h>
#include "common/common.h"
#include "common/playlist.h"
#include "stream/stream.h"
#include "demux.h"
#include "stream/stream_libarchive.h"
static int cmp_filename(const void *a, const void *b)
{
return strcmp(*(char **)a, *(char **)b);
}
static int open_file(struct demuxer *demuxer, enum demux_check check)
{
int flags = 0;
int probe_size = STREAM_BUFFER_SIZE;
if (check <= DEMUX_CHECK_REQUEST) {
flags |= MP_ARCHIVE_FLAG_UNSAFE;
probe_size *= 100;
}
bstr probe = stream_peek(demuxer->stream, probe_size);
if (probe.len == 0)
return -1;
struct stream *probe_stream = open_memory_stream(probe.start, probe.len);
struct mp_archive *mpa = mp_archive_new(mp_null_log, probe_stream, flags);
bool ok = !!mpa;
free_stream(probe_stream);
mp_archive_free(mpa);
if (!ok)
return -1;
mpa = mp_archive_new(demuxer->log, demuxer->stream, flags);
if (!mpa)
return -1;
struct playlist *pl = talloc_zero(demuxer, struct playlist);
demuxer->playlist = pl;
// make it load archive://
pl->disable_safety = true;
char *prefix = mp_url_escape(mpa, demuxer->stream->url, "~|");
char **files = NULL;
int num_files = 0;
for (;;) {
struct archive_entry *entry;
int r = archive_read_next_header(mpa->arch, &entry);
if (r == ARCHIVE_EOF)
break;
if (r < ARCHIVE_OK)
MP_ERR(demuxer, "libarchive: %s\n", archive_error_string(mpa->arch));
if (r < ARCHIVE_WARN)
break;
if (archive_entry_filetype(entry) != AE_IFREG)
continue;
const char *fn = archive_entry_pathname(entry);
// Some archives may have no filenames.
if (!fn)
fn = talloc_asprintf(mpa, "mpv_unknown#%d\n", num_files);
// stream_libarchive.c does the real work
char *f = talloc_asprintf(mpa, "archive://%s|%s", prefix, fn);
MP_TARRAY_APPEND(mpa, files, num_files, f);
}
if (files)
qsort(files, num_files, sizeof(files[0]), cmp_filename);
for (int n = 0; n < num_files; n++)
playlist_add_file(pl, files[n]);
demuxer->filetype = "archive";
demuxer->fully_read = true;
mp_archive_free(mpa);
return 0;
}
const struct demuxer_desc demuxer_desc_libarchive = {
.name = "libarchive",
.desc = "libarchive wrapper",
.open = open_file,
};