summaryrefslogtreecommitdiffstats
path: root/stream/stream_libarchive.c
diff options
context:
space:
mode:
Diffstat (limited to 'stream/stream_libarchive.c')
-rw-r--r--stream/stream_libarchive.c65
1 files changed, 35 insertions, 30 deletions
diff --git a/stream/stream_libarchive.c b/stream/stream_libarchive.c
index 7ae5a8be38..781b34ad0d 100644
--- a/stream/stream_libarchive.c
+++ b/stream/stream_libarchive.c
@@ -27,14 +27,15 @@
struct mp_archive_volume {
struct mp_archive *mpa;
- struct stream *src;
+ int index; // volume number (starting with 0, mp_archive.primary_src)
+ struct stream *src; // NULL => not current volume, or 0 sized dummy stream
int64_t seek_to;
char *url;
};
static bool volume_seek(struct mp_archive_volume *vol)
{
- if (vol->seek_to < 0)
+ if (!vol->src || vol->seek_to < 0)
return true;
bool r = stream_seek(vol->src, vol->seek_to);
vol->seek_to = -1;
@@ -44,6 +45,8 @@ static bool volume_seek(struct mp_archive_volume *vol)
static ssize_t read_cb(struct archive *arch, void *priv, const void **buffer)
{
struct mp_archive_volume *vol = priv;
+ if (!vol->src)
+ return 0;
if (!volume_seek(vol))
return -1;
int res = stream_read_partial(vol->src, vol->mpa->buffer,
@@ -57,6 +60,8 @@ static int64_t seek_cb(struct archive *arch, void *priv,
int64_t offset, int whence)
{
struct mp_archive_volume *vol = priv;
+ if (!vol->src)
+ return 0;
switch (whence) {
case SEEK_SET:
vol->seek_to = offset;
@@ -81,6 +86,8 @@ static int64_t seek_cb(struct archive *arch, void *priv,
static int64_t skip_cb(struct archive *arch, void *priv, int64_t request)
{
struct mp_archive_volume *vol = priv;
+ if (!vol->src)
+ return request;
if (!volume_seek(vol))
return -1;
int64_t old = stream_tell(vol->src);
@@ -93,12 +100,26 @@ static int open_cb(struct archive *arch, void *priv)
struct mp_archive_volume *vol = priv;
vol->seek_to = -1;
if (!vol->src) {
+ // Avoid annoying warnings/latency for known dummy volumes.
+ if (vol->index >= vol->mpa->num_volumes)
+ return ARCHIVE_OK;
vol->src = stream_create(vol->url,
STREAM_READ |
vol->mpa->primary_src->stream_origin,
vol->mpa->primary_src->cancel,
vol->mpa->primary_src->global);
- return vol->src ? ARCHIVE_OK : ARCHIVE_FATAL;
+ // We pretend that failure to open a stream means it was not found,
+ // we assume in turn means that the volume doesn't exist (since
+ // libarchive is too fucking stupid to detect when a multi-volume
+ // archive really ends). libarchive also throws up permanently when
+ // a volume could not be opened (because it's fucking stupid), but
+ // somehow accepts 0-sized volumes (because it's fucking stupid), which
+ // we simulate whenever vol->src==NULL for an opened volume.
+ if (!vol->src) {
+ vol->mpa->num_volumes = MPMIN(vol->mpa->num_volumes, vol->index);
+ MP_INFO(vol->mpa, "Assuming the volume above was not needed.\n");
+ }
+ return ARCHIVE_OK;
}
// just rewind the primary stream
@@ -118,17 +139,9 @@ static int close_cb(struct archive *arch, void *priv)
{
struct mp_archive_volume *vol = priv;
volume_close(vol);
- talloc_free(vol);
return ARCHIVE_OK;
}
-static int switch_cb(struct archive *arch, void *oldpriv, void *newpriv)
-{
- struct mp_archive_volume *oldvol = oldpriv;
- volume_close(oldvol);
- return open_cb(arch, newpriv);
-}
-
static void mp_archive_close(struct mp_archive *mpa)
{
if (mpa && mpa->arch) {
@@ -206,19 +219,9 @@ static char **find_volumes(struct stream *primary_stream)
if (!pattern->match)
goto done;
- struct bstr base = bstr_splice(primary_url, 0, -strlen(pattern->match));
+ struct bstr base = bstr_splice(primary_url, 0, -(int)strlen(pattern->match));
for (int i = pattern->start; i <= pattern->stop; i++) {
char* url = pattern->volume_url(res, pattern->format, base, i);
- struct stream *s = stream_create(url,
- STREAM_READ |
- primary_stream->stream_origin,
- primary_stream->cancel,
- primary_stream->global);
- if (!s) {
- talloc_free(url);
- goto done;
- }
- free_stream(s);
MP_TARRAY_APPEND(res, res, num, url);
}
@@ -229,10 +232,10 @@ done:
static bool add_volume(struct mp_log *log, struct mp_archive *mpa,
- struct stream *src, const char* url)
+ struct stream *src, const char* url, int index)
{
struct mp_archive_volume *vol = talloc_zero(mpa, struct mp_archive_volume);
- mp_verbose(log, "Adding volume %s\n", url);
+ vol->index = index;
vol->mpa = mpa;
vol->src = src;
vol->url = talloc_strdup(vol, url);
@@ -243,7 +246,7 @@ static bool add_volume(struct mp_log *log, struct mp_archive *mpa,
}
struct mp_archive *mp_archive_new(struct mp_log *log, struct stream *src,
- int flags)
+ int flags, int max_volumes)
{
struct mp_archive *mpa = talloc_zero(NULL, struct mp_archive);
mpa->log = log;
@@ -257,15 +260,16 @@ struct mp_archive *mp_archive_new(struct mp_log *log, struct stream *src,
mpa->primary_src = src;
if (!mpa->arch)
goto err;
+ mpa->num_volumes = max_volumes ? max_volumes : INT_MAX;
- // first volume is the primary streame
- if (!add_volume(log ,mpa, src, src->url))
+ // first volume is the primary stream
+ if (!add_volume(log, mpa, src, src->url, 0))
goto err;
// try to open other volumes
char** volumes = find_volumes(src);
for (int i = 0; volumes[i]; i++) {
- if (!add_volume(log, mpa, NULL, volumes[i])) {
+ if (!add_volume(log, mpa, NULL, volumes[i], i + 1)) {
talloc_free(volumes);
goto err;
}
@@ -289,8 +293,8 @@ struct mp_archive *mp_archive_new(struct mp_log *log, struct stream *src,
archive_read_set_read_callback(mpa->arch, read_cb);
archive_read_set_skip_callback(mpa->arch, skip_cb);
- archive_read_set_switch_callback(mpa->arch, switch_cb);
archive_read_set_open_callback(mpa->arch, open_cb);
+ // Allow it to close a volume.
archive_read_set_close_callback(mpa->arch, close_cb);
if (mpa->primary_src->seekable)
archive_read_set_seek_callback(mpa->arch, seek_cb);
@@ -365,9 +369,10 @@ struct priv {
static int reopen_archive(stream_t *s)
{
struct priv *p = s->priv;
+ int num_volumes = p->mpa ? p->mpa->num_volumes : 0;
mp_archive_free(p->mpa);
s->pos = 0;
- p->mpa = mp_archive_new(s->log, p->src, MP_ARCHIVE_FLAG_UNSAFE);
+ p->mpa = mp_archive_new(s->log, p->src, MP_ARCHIVE_FLAG_UNSAFE, num_volumes);
if (!p->mpa)
return STREAM_ERROR;