mirror of https://github.com/mpv-player/mpv
152 lines
4.5 KiB
C
152 lines
4.5 KiB
C
// Major parts based on:
|
|
/*****************************************************************************
|
|
* access.c: uncompressed RAR access
|
|
*****************************************************************************
|
|
* Copyright (C) 2008-2010 Laurent Aimar
|
|
* $Id: dcd973529e0029abe326d31f8d58cd13bbcc276c $
|
|
*
|
|
* Author: Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
|
|
*
|
|
* 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 "config.h"
|
|
|
|
#include <stdio.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include <errno.h>
|
|
|
|
#include "osdep/io.h"
|
|
|
|
#include "common/msg.h"
|
|
#include "stream.h"
|
|
#include "options/m_option.h"
|
|
#include "rar.h"
|
|
|
|
/*
|
|
This works as follows:
|
|
|
|
- stream_open() with file01.rar
|
|
- is opened as normal file (stream_file.c or others) first
|
|
- the rar code in demux_playlist.c detects it
|
|
- if multi-part, opens file02.rar, file03.rar, etc. as actual streams
|
|
(recursive opening is prevented with the STREAM_NO_FILTERS flag)
|
|
- it returns a playlist like this to the player:
|
|
rar://bla01.rar|subfile.mkv
|
|
(one such entry for each file contained in the rar)
|
|
- stream_open() with the playlist entry, e.g. rar://bla01.rar|subfile.mkv
|
|
- leads to rar_entry_open()
|
|
- opens bla01.rar etc. again as actual streams
|
|
(again, STREAM_NO_FILTERS to open the actual files)
|
|
- read accesses go into subfile.mkv contained in the rar file(s)
|
|
*/
|
|
|
|
static int rar_entry_fill_buffer(stream_t *s, char *buffer, int max_len)
|
|
{
|
|
rar_file_t *rar_file = s->priv;
|
|
return RarRead(rar_file, buffer, max_len);
|
|
}
|
|
|
|
static int rar_entry_seek(stream_t *s, int64_t newpos)
|
|
{
|
|
rar_file_t *rar_file = s->priv;
|
|
return RarSeek(rar_file, newpos);
|
|
}
|
|
|
|
static void rar_entry_close(stream_t *s)
|
|
{
|
|
rar_file_t *rar_file = s->priv;
|
|
RarFileDelete(rar_file);
|
|
}
|
|
|
|
static int rar_entry_control(stream_t *s, int cmd, void *arg)
|
|
{
|
|
rar_file_t *rar_file = s->priv;
|
|
switch (cmd) {
|
|
case STREAM_CTRL_GET_BASE_FILENAME:
|
|
*(char **)arg = talloc_strdup(NULL, rar_file->s->url);
|
|
return STREAM_OK;
|
|
case STREAM_CTRL_GET_SIZE:
|
|
*(int64_t *)arg = rar_file->size;
|
|
return STREAM_OK;
|
|
}
|
|
return STREAM_UNSUPPORTED;
|
|
}
|
|
|
|
static int rar_entry_open(stream_t *stream)
|
|
{
|
|
if (!strchr(stream->path, '|'))
|
|
return STREAM_ERROR;
|
|
|
|
char *base = talloc_strdup(stream, stream->path);
|
|
char *name = strchr(base, '|');
|
|
*name++ = '\0';
|
|
mp_url_unescape_inplace(base);
|
|
|
|
struct stream *rar = stream_create(base, STREAM_READ, stream->cancel,
|
|
stream->global);
|
|
if (!rar)
|
|
return STREAM_ERROR;
|
|
|
|
int count;
|
|
rar_file_t **files;
|
|
if (RarProbe(rar) || RarParse(rar, &count, &files)) {
|
|
free_stream(rar);
|
|
return STREAM_ERROR;
|
|
}
|
|
|
|
rar_file_t *file = NULL;
|
|
for (int i = 0; i < count; i++) {
|
|
if (!file && strcmp(files[i]->name, name) == 0)
|
|
file = files[i];
|
|
else
|
|
RarFileDelete(files[i]);
|
|
}
|
|
talloc_free(files);
|
|
if (!file) {
|
|
free_stream(rar);
|
|
return STREAM_ERROR;
|
|
}
|
|
|
|
rar_file_chunk_t dummy = {
|
|
.mrl = base,
|
|
};
|
|
file->current_chunk = &dummy;
|
|
file->s = rar; // transfer ownership
|
|
file->cancel = stream->cancel;
|
|
file->global = stream->global;
|
|
RarSeek(file, 0);
|
|
|
|
stream->priv = file;
|
|
stream->fill_buffer = rar_entry_fill_buffer;
|
|
stream->seek = rar_entry_seek;
|
|
stream->seekable = true;
|
|
stream->close = rar_entry_close;
|
|
stream->control = rar_entry_control;
|
|
|
|
return STREAM_OK;
|
|
}
|
|
|
|
const stream_info_t stream_info_rar = {
|
|
.name = "rar",
|
|
.open = rar_entry_open,
|
|
.protocols = (const char*const[]){ "rar", NULL },
|
|
.is_safe = true,
|
|
.is_network = true, // safe over network
|
|
};
|