diff --git a/demux/demux.c b/demux/demux.c index afb5fea2dd..8a1e9b0b82 100644 --- a/demux/demux.c +++ b/demux/demux.c @@ -74,7 +74,6 @@ const demuxer_desc_t *const demuxer_list[] = { #if HAVE_LIBARCHIVE &demuxer_desc_libarchive, #endif - &demuxer_desc_rar, &demuxer_desc_lavf, &demuxer_desc_mf, &demuxer_desc_playlist, diff --git a/demux/demux_rar.c b/demux/demux_rar.c deleted file mode 100644 index 7d9adfc28a..0000000000 --- a/demux/demux_rar.c +++ /dev/null @@ -1,65 +0,0 @@ -/* - * 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 . - */ - -#include "common/common.h" -#include "common/playlist.h" -#include "stream/stream.h" -#include "stream/rar.h" -#include "demux.h" - -static int open_file(struct demuxer *demuxer, enum demux_check check) -{ - if (!demuxer->access_references) - return -1; - - if (RarProbe(demuxer->stream)) - return -1; - - int count; - rar_file_t **files; - if (RarParse(demuxer->stream, &count, &files)) - return -1; - - void *tmp = talloc_new(NULL); - talloc_steal(tmp, files); - - struct playlist *pl = talloc_zero(demuxer, struct playlist); - demuxer->playlist = pl; - - // make it load rar:// - pl->disable_safety = true; - - char *prefix = mp_url_escape(tmp, demuxer->stream->url, "~|"); - for (int n = 0; n < count; n++) { - // stream_rar.c does the real work - playlist_add_file(pl, - talloc_asprintf(tmp, "rar://%s|%s", prefix, files[n]->name)); - RarFileDelete(files[n]); - } - - demuxer->filetype = "rar"; - demuxer->fully_read = true; - - talloc_free(tmp); - return 0; -} - -const struct demuxer_desc demuxer_desc_rar = { - .name = "rar", - .desc = "Rar archive file", - .open = open_file, -}; diff --git a/stream/rar.c b/stream/rar.c deleted file mode 100644 index 9a74097ce7..0000000000 --- a/stream/rar.c +++ /dev/null @@ -1,451 +0,0 @@ -/***************************************************************************** - * rar.c: uncompressed RAR parser - ***************************************************************************** - * Copyright (C) 2008-2010 Laurent Aimar - * $Id: f368245f4260f913f5c211e09b7dd511a96525e6 $ - * - * Author: Laurent Aimar - * - * 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. - *****************************************************************************/ - -/***************************************************************************** - * Preamble - *****************************************************************************/ - -#include -#include -#include - -#include - -#include "mpv_talloc.h" -#include "common/common.h" -#include "stream.h" -#include "rar.h" - -static const uint8_t rar_marker[] = { - 0x52, 0x61, 0x72, 0x21, 0x1a, 0x07, 0x00 -}; -static const int rar_marker_size = sizeof(rar_marker); - -void RarFileDelete(rar_file_t *file) -{ - for (int i = 0; i < file->chunk_count; i++) { - free(file->chunk[i]->mrl); - free(file->chunk[i]); - } - talloc_free(file->chunk); - free(file->name); - free_stream(file->s); - free(file); -} - -typedef struct { - uint16_t crc; - uint8_t type; - uint16_t flags; - uint16_t size; - uint32_t add_size; -} rar_block_t; - -enum { - RAR_BLOCK_MARKER = 0x72, - RAR_BLOCK_ARCHIVE = 0x73, - RAR_BLOCK_FILE = 0x74, - RAR_BLOCK_SUBBLOCK = 0x7a, - RAR_BLOCK_END = 0x7b, -}; -enum { - RAR_BLOCK_END_HAS_NEXT = 0x0001, -}; -enum { - RAR_BLOCK_FILE_HAS_PREVIOUS = 0x0001, - RAR_BLOCK_FILE_HAS_NEXT = 0x0002, - RAR_BLOCK_FILE_HAS_HIGH = 0x0100, -}; - -static int PeekBlock(struct stream *s, rar_block_t *hdr) -{ - bstr data = stream_peek(s, 11); - const uint8_t *peek = (uint8_t *)data.start; - int peek_size = data.len; - - if (peek_size < 7) - return -1; - - hdr->crc = AV_RL16(&peek[0]); - hdr->type = peek[2]; - hdr->flags = AV_RL16(&peek[3]); - hdr->size = AV_RL16(&peek[5]); - hdr->add_size = 0; - if ((hdr->flags & 0x8000) || - hdr->type == RAR_BLOCK_FILE || - hdr->type == RAR_BLOCK_SUBBLOCK) { - if (peek_size < 11) - return -1; - hdr->add_size = AV_RL32(&peek[7]); - } - - if (hdr->size < 7) - return -1; - return 0; -} -static int SkipBlock(struct stream *s, const rar_block_t *hdr) -{ - uint64_t size = (uint64_t)hdr->size + hdr->add_size; - - while (size > 0) { - int skip = MPMIN(size, INT_MAX); - if (!stream_skip(s, skip)) - return -1; - - size -= skip; - } - return 0; -} - -static int IgnoreBlock(struct stream *s, int block) -{ - /* */ - rar_block_t bk; - if (PeekBlock(s, &bk) || bk.type != block) - return -1; - return SkipBlock(s, &bk); -} - -static int SkipEnd(struct stream *s, const rar_block_t *hdr) -{ - if (!(hdr->flags & RAR_BLOCK_END_HAS_NEXT)) - return -1; - - if (SkipBlock(s, hdr)) - return -1; - - /* Now, we need to look for a marker block, - * It seems that there is garbage at EOF */ - for (;;) { - bstr peek = stream_peek(s, rar_marker_size); - - if (peek.len < rar_marker_size) - return -1; - - if (!memcmp(peek.start, rar_marker, rar_marker_size)) - break; - - if (!stream_skip(s, 1)) - return -1; - } - - /* Skip marker and archive blocks */ - if (IgnoreBlock(s, RAR_BLOCK_MARKER)) - return -1; - if (IgnoreBlock(s, RAR_BLOCK_ARCHIVE)) - return -1; - - return 0; -} - -static int SkipFile(struct stream *s, int *count, rar_file_t ***file, - const rar_block_t *hdr, const char *volume_mrl) -{ - int min_size = 7+21; - if (hdr->flags & RAR_BLOCK_FILE_HAS_HIGH) - min_size += 8; - if (hdr->size < (unsigned)min_size) - return -1; - - bstr data = stream_peek(s, min_size); - if (data.len < min_size) - return -1; - const uint8_t *peek = (uint8_t *)data.start; - - /* */ - uint32_t file_size_low = AV_RL32(&peek[7+4]); - uint8_t method = peek[7+18]; - uint16_t name_size = AV_RL16(&peek[7+19]); - uint32_t file_size_high = 0; - if (hdr->flags & RAR_BLOCK_FILE_HAS_HIGH) - file_size_high = AV_RL32(&peek[7+29]); - const uint64_t file_size = ((uint64_t)file_size_high << 32) | file_size_low; - - char *name = calloc(1, name_size + 1); - if (!name) - return -1; - - const int name_offset = (hdr->flags & RAR_BLOCK_FILE_HAS_HIGH) ? (7+33) : (7+25); - if (name_offset + name_size <= hdr->size) { - const int max_size = name_offset + name_size; - bstr namedata = stream_peek(s, max_size); - if (namedata.len < max_size) { - free(name); - return -1; - } - memcpy(name, &namedata.start[name_offset], name_size); - } - - rar_file_t *current = NULL; - if (method != 0x30) { - MP_WARN(s, "Ignoring compressed file %s (method=0x%2.2x)\n", name, method); - goto exit; - } - - /* */ - if( *count > 0 ) - current = (*file)[*count - 1]; - - if (current && - (current->is_complete || - strcmp(current->name, name) || - (hdr->flags & RAR_BLOCK_FILE_HAS_PREVIOUS) == 0)) - current = NULL; - - if (!current) { - if (hdr->flags & RAR_BLOCK_FILE_HAS_PREVIOUS) - goto exit; - current = calloc(1, sizeof(*current)); - if (!current) - goto exit; - MP_TARRAY_APPEND(NULL, *file, *count, current); - - current->name = name; - current->size = file_size; - current->is_complete = false; - current->real_size = 0; - current->chunk_count = 0; - current->chunk = NULL; - - name = NULL; - } - - /* Append chunks */ - rar_file_chunk_t *chunk = malloc(sizeof(*chunk)); - if (chunk) { - chunk->mrl = strdup(volume_mrl); - chunk->offset = stream_tell(s) + hdr->size; - chunk->size = hdr->add_size; - chunk->cummulated_size = 0; - if (current->chunk_count > 0) { - rar_file_chunk_t *previous = current->chunk[current->chunk_count-1]; - - chunk->cummulated_size += previous->cummulated_size + - previous->size; - } - - MP_TARRAY_APPEND(NULL, current->chunk, current->chunk_count, chunk); - - current->real_size += hdr->add_size; - } - if ((hdr->flags & RAR_BLOCK_FILE_HAS_NEXT) == 0) - current->is_complete = true; - -exit: - /* */ - free(name); - - /* We stop on the first non empty file if we cannot seek */ - if (current) { - if (!s->seekable && current->size > 0) - return -1; - } - - if (SkipBlock(s, hdr)) - return -1; - return 0; -} - -int RarProbe(struct stream *s) -{ - bstr peek = stream_peek(s, rar_marker_size); - if (peek.len < rar_marker_size) - return -1; - if (memcmp(peek.start, rar_marker, rar_marker_size)) - return -1; - return 0; -} - -typedef struct { - const char *match; - const char *format; - int start; - int stop; -} rar_pattern_t; - -static const rar_pattern_t *FindVolumePattern(const char *location) -{ - static const rar_pattern_t patterns[] = { - { ".part1.rar", "%s.part%.1d.rar", 2, 9 }, - { ".part01.rar", "%s.part%.2d.rar", 2, 99, }, - { ".part001.rar", "%s.part%.3d.rar", 2, 999 }, - { ".rar", "%s.%c%.2d", 0, 999 }, - { NULL, NULL, 0, 0 }, - }; - - const size_t location_size = strlen(location); - for (int i = 0; patterns[i].match != NULL; i++) { - const size_t match_size = strlen(patterns[i].match); - - if (location_size < match_size) - continue; - if (!strcmp(&location[location_size - match_size], patterns[i].match)) - return &patterns[i]; - } - return NULL; -} - -int RarParse(struct stream *s, int *count, rar_file_t ***file) -{ - *count = 0; - *file = NULL; - - const rar_pattern_t *pattern = FindVolumePattern(s->url); - int volume_offset = 0; - - char *volume_mrl; - if (asprintf(&volume_mrl, "%s", s->url) < 0) - return -1; - - struct stream *vol = s; - for (;;) { - /* Skip marker & archive */ - if (IgnoreBlock(vol, RAR_BLOCK_MARKER) || - IgnoreBlock(vol, RAR_BLOCK_ARCHIVE)) { - if (vol != s) - free_stream(vol); - free(volume_mrl); - return -1; - } - - /* */ - int has_next = -1; - for (;;) { - rar_block_t bk; - int ret; - - if (PeekBlock(vol, &bk)) - break; - - switch(bk.type) { - case RAR_BLOCK_END: - ret = SkipEnd(vol, &bk); - has_next = ret && (bk.flags & RAR_BLOCK_END_HAS_NEXT); - break; - case RAR_BLOCK_FILE: - ret = SkipFile(vol, count, file, &bk, volume_mrl); - break; - default: - ret = SkipBlock(vol, &bk); - break; - } - if (ret) - break; - } - if (has_next < 0 && *count > 0 && !(*file)[*count -1]->is_complete) - has_next = 1; - if (vol != s) - free_stream(vol); - - if (!has_next || !pattern) - goto done; - - /* Open next volume */ - const int volume_index = pattern->start + volume_offset++; - if (volume_index > pattern->stop) - goto done; - - char *volume_base; - if (asprintf(&volume_base, "%.*s", - (int)(strlen(s->url) - strlen(pattern->match)), s->url) < 0) { - goto done; - } - - free(volume_mrl); - if (pattern->start) { - if (asprintf(&volume_mrl, pattern->format, volume_base, volume_index) < 0) - volume_mrl = NULL; - } else { - if (asprintf(&volume_mrl, pattern->format, volume_base, - 'r' + volume_index / 100, volume_index % 100) < 0) - volume_mrl = NULL; - } - free(volume_base); - - if (!volume_mrl) - goto done; - - vol = stream_create(volume_mrl, STREAM_READ, s->cancel, s->global); - - if (!vol) - goto done; - } - -done: - free(volume_mrl); - if (*count == 0) { - talloc_free(*file); - return -1; - } - return 0; -} - -int RarSeek(rar_file_t *file, uint64_t position) -{ - if (position > file->real_size) - position = file->real_size; - - /* Search the chunk */ - const rar_file_chunk_t *old_chunk = file->current_chunk; - for (int i = 0; i < file->chunk_count; i++) { - file->current_chunk = file->chunk[i]; - if (position < file->current_chunk->cummulated_size + file->current_chunk->size) - break; - } - file->i_pos = position; - - const uint64_t offset = file->current_chunk->offset + - (position - file->current_chunk->cummulated_size); - - if (strcmp(old_chunk->mrl, file->current_chunk->mrl)) { - if (file->s) - free_stream(file->s); - file->s = stream_create(file->current_chunk->mrl, STREAM_READ, - file->cancel, file->global); - } - return file->s ? stream_seek(file->s, offset) : 0; -} - -ssize_t RarRead(rar_file_t *file, void *data, size_t size) -{ - size_t total = 0; - while (total < size) { - const uint64_t chunk_end = file->current_chunk->cummulated_size + file->current_chunk->size; - int max = MPMIN(MPMIN((int64_t)(size - total), (int64_t)(chunk_end - file->i_pos)), INT_MAX); - if (max <= 0) - break; - - int r = stream_read(file->s, data, max); - if (r <= 0) - break; - - total += r; - data = (char *)data + r; - file->i_pos += r; - if (file->i_pos >= chunk_end && - RarSeek(file, file->i_pos)) - break; - } - return total; - -} diff --git a/stream/rar.h b/stream/rar.h deleted file mode 100644 index f7f80a8177..0000000000 --- a/stream/rar.h +++ /dev/null @@ -1,61 +0,0 @@ -/***************************************************************************** - * rar.h: uncompressed RAR parser - ***************************************************************************** - * Copyright (C) 2008-2010 Laurent Aimar - * $Id: 4dea45925c2d8f319d692475bc0307fdd9f6cfe7 $ - * - * Author: Laurent Aimar - * - * 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. - *****************************************************************************/ - -#ifndef MP_RAR_H -#define MP_RAR_H - -#include -#include - -typedef struct { - char *mrl; - uint64_t offset; - uint64_t size; - uint64_t cummulated_size; -} rar_file_chunk_t; - -typedef struct { - char *name; - uint64_t size; - bool is_complete; - - int chunk_count; - rar_file_chunk_t **chunk; - uint64_t real_size; /* Gathered size */ - - // When actually reading the data - struct mpv_global *global; - struct mp_cancel *cancel; - uint64_t i_pos; - stream_t *s; - rar_file_chunk_t *current_chunk; -} rar_file_t; - -int RarProbe(struct stream *); -void RarFileDelete(rar_file_t *); -int RarParse(struct stream *, int *, rar_file_t ***); - -int RarSeek(rar_file_t *file, uint64_t position); -ssize_t RarRead(rar_file_t *file, void *data, size_t size); - -#endif diff --git a/stream/stream.c b/stream/stream.c index 273ab06959..8068effc06 100644 --- a/stream/stream.c +++ b/stream/stream.c @@ -59,7 +59,6 @@ extern const stream_info_t stream_info_dvdnav; extern const stream_info_t stream_info_bdmv_dir; extern const stream_info_t stream_info_bluray; extern const stream_info_t stream_info_bdnav; -extern const stream_info_t stream_info_rar; extern const stream_info_t stream_info_edl; extern const stream_info_t stream_info_libarchive; extern const stream_info_t stream_info_cb; @@ -89,12 +88,10 @@ static const stream_info_t *const stream_list[] = { #if HAVE_LIBARCHIVE &stream_info_libarchive, #endif - &stream_info_memory, &stream_info_null, &stream_info_mf, &stream_info_edl, - &stream_info_rar, &stream_info_file, &stream_info_cb, NULL diff --git a/stream/stream.h b/stream/stream.h index 2b91d43bfd..589e6b35cc 100644 --- a/stream/stream.h +++ b/stream/stream.h @@ -54,7 +54,7 @@ enum stream_ctrl { // stream_memory.c STREAM_CTRL_SET_CONTENTS, - // stream_rar.c + // stream_libarchive.c STREAM_CTRL_GET_BASE_FILENAME, // Certain network protocols diff --git a/stream/stream_rar.c b/stream/stream_rar.c deleted file mode 100644 index 3ba689b539..0000000000 --- a/stream/stream_rar.c +++ /dev/null @@ -1,147 +0,0 @@ -// Major parts based on: -/***************************************************************************** - * access.c: uncompressed RAR access - ***************************************************************************** - * Copyright (C) 2008-2010 Laurent Aimar - * $Id: dcd973529e0029abe326d31f8d58cd13bbcc276c $ - * - * Author: Laurent Aimar - * - * 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 -#include -#include -#include -#include -#include - -#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 - - demux_rar.c detects it - - if multi-part, opens file02.rar, file03.rar, etc. as actual streams - - it returns a playlist with entries 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 - - 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_SAFE_ONLY, - 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 }, -}; diff --git a/wscript_build.py b/wscript_build.py index c151d97bce..69d8937ab7 100644 --- a/wscript_build.py +++ b/wscript_build.py @@ -283,7 +283,6 @@ def build(ctx): ( "demux/demux_mkv_timeline.c" ), ( "demux/demux_null.c" ), ( "demux/demux_playlist.c" ), - ( "demux/demux_rar.c" ), ( "demux/demux_raw.c" ), ( "demux/demux_timeline.c" ), ( "demux/ebml.c" ), @@ -354,7 +353,6 @@ def build(ctx): ## Streams ( "stream/cookies.c" ), ( "stream/dvb_tune.c", "dvbin" ), - ( "stream/rar.c" ), ( "stream/stream.c" ), ( "stream/stream_avdevice.c" ), ( "stream/stream_bluray.c", "libbluray" ), @@ -369,7 +367,6 @@ def build(ctx): ( "stream/stream_memory.c" ), ( "stream/stream_mf.c" ), ( "stream/stream_null.c" ), - ( "stream/stream_rar.c" ), ( "stream/stream_smb.c", "libsmbclient" ), ## Subtitles