Commit bd068763 authored by Filip Roséen's avatar Filip Roséen Committed by Jean-Baptiste Kempf

modules/access: remove legacy rar access

rar extraction is now handled by the libarchive based
modules/stream_extractor/archive.c, as such these files/modules are no
longer needed.
Signed-off-by: Jean-Baptiste Kempf's avatarJean-Baptiste Kempf <jb@videolan.org>
parent 5d020c46
......@@ -280,6 +280,7 @@ Removed modules
* BD access module (use libbluray)
* Direct2D module (use Direct3D11)
* EyeTV access module
* Rar access and stream filter: use libarchive
Changes between 2.2.0 and 2.2.1:
......
......@@ -310,7 +310,6 @@ $Id$
* pva: PVA demuxer
* qsv: QuickSyncVideo Encoder for Intel hardware
* qt: interface module using the cross-platform Qt widget library
* rar: RAR access and stream filter
* rawaud: raw audio input module for vlc
* rawdv: Raw DV demuxer
* rawvid: raw video input module for vlc
......
......@@ -36,11 +36,6 @@ access_LTLIBRARIES += libimem_plugin.la
libaccess_imem_plugin_la_SOURCES = access/imem.c
access_LTLIBRARIES += libaccess_imem_plugin.la
librar_plugin_la_SOURCES = access/rar/rar.c access/rar/rar.h \
access/rar/access.c access/rar/stream.c access/rar/module.c
librar_plugin_la_CPPFLAGS = $(AM_CPPFLAGS)
access_LTLIBRARIES += librar_plugin.la
libsdp_plugin_la_SOURCES = access/sdp.c
access_LTLIBRARIES += libsdp_plugin.la
......
/*****************************************************************************
* access.c: uncompressed RAR access
*****************************************************************************
* Copyright (C) 2008-2010 Laurent Aimar
* $Id$
*
* 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.
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <vlc_common.h>
#include <vlc_plugin.h>
#include <vlc_access.h>
#include <vlc_stream.h>
#include <vlc_url.h>
#include <assert.h>
#include <limits.h>
#include "rar.h"
struct access_sys_t {
stream_t *s;
rar_file_t *file;
const rar_file_chunk_t *chunk;
uint64_t position;
};
static int Seek(access_t *access, uint64_t position)
{
access_sys_t *sys = access->p_sys;
const rar_file_t *file = sys->file;
if (position > file->real_size)
position = file->real_size;
sys->position = position;
/* Search the chunk */
const rar_file_chunk_t *old_chunk = sys->chunk;
for (int i = 0; i < file->chunk_count; i++) {
sys->chunk = file->chunk[i];
if (position < sys->chunk->cummulated_size + sys->chunk->size)
break;
}
const uint64_t offset = sys->chunk->offset +
(position - sys->chunk->cummulated_size);
if (strcmp(old_chunk->mrl, sys->chunk->mrl)) {
if (sys->s)
vlc_stream_Delete(sys->s);
sys->s = vlc_stream_NewURL(access, sys->chunk->mrl);
}
return sys->s ? vlc_stream_Seek(sys->s, offset) : VLC_EGENERIC;
}
static ssize_t Read(access_t *access, void *data, size_t size)
{
access_sys_t *sys = access->p_sys;
size_t total = 0;
while (total < size) {
const uint64_t chunk_end = sys->chunk->cummulated_size + sys->chunk->size;
int max = __MIN(__MIN((int64_t)(size - total), (int64_t)(chunk_end - sys->position)), INT_MAX);
if (max <= 0)
break;
int r = sys->s ? vlc_stream_Read(sys->s, data, max) : -1;
if (r <= 0)
break;
total += r;
if( data )
data = ((char *)data) + r;
sys->position += r;
if (sys->position >= chunk_end &&
Seek(access, sys->position))
break;
}
return total;
}
static int Control(access_t *access, int query, va_list args)
{
access_sys_t *sys = access->p_sys;
stream_t *s = sys->s;
if (!s)
return VLC_EGENERIC;
switch (query) {
case STREAM_CAN_SEEK: {
bool *b = va_arg(args, bool *);
return vlc_stream_Control(s, STREAM_CAN_SEEK, b);
}
case STREAM_CAN_FASTSEEK: {
bool *b = va_arg(args, bool *);
return vlc_stream_Control(s, STREAM_CAN_FASTSEEK, b);
}
/* FIXME the following request should ask the underlying access object */
case STREAM_CAN_PAUSE:
case STREAM_CAN_CONTROL_PACE: {
bool *b = va_arg(args, bool *);
*b = true;
return VLC_SUCCESS;
}
case STREAM_GET_SIZE:
*va_arg(args, uint64_t *) = sys->file->size;
return VLC_SUCCESS;
case STREAM_GET_PTS_DELAY: {
int64_t *delay = va_arg(args, int64_t *);
*delay = DEFAULT_PTS_DELAY;
return VLC_SUCCESS;
}
case STREAM_SET_PAUSE_STATE:
return VLC_SUCCESS;
default:
return VLC_EGENERIC;
}
}
int RarAccessOpen(vlc_object_t *object)
{
access_t *access = (access_t*)object;
const char *name = strchr(access->psz_location, '|');
if (name == NULL)
return VLC_EGENERIC;
char *base = strndup(access->psz_location, name - access->psz_location);
if (unlikely(base == NULL))
return VLC_ENOMEM;
name++;
vlc_uri_decode(base);
stream_t *s = vlc_stream_NewURL(access, base);
if (!s || RarProbe(s))
goto error;
struct
{
int filescount;
rar_file_t **files;
unsigned int i_nbvols;
} newscheme = { 0, NULL, 0 }, oldscheme = { 0, NULL, 0 }, *p_scheme;
if (RarParse(s, &newscheme.filescount, &newscheme.files, &newscheme.i_nbvols, false)
|| newscheme.filescount < 1 || newscheme.i_nbvols < 2 )
{
/* We might want to lookup old naming scheme, could be a part1.rar,part1.r00 */
vlc_stream_Seek(s, 0);
RarParse(s, &oldscheme.filescount, &oldscheme.files, &oldscheme.i_nbvols, true);
}
if (oldscheme.filescount >= newscheme.filescount && oldscheme.i_nbvols > newscheme.i_nbvols)
{
for (int i = 0; i < newscheme.filescount; i++)
RarFileDelete(newscheme.files[i]);
free(newscheme.files);
p_scheme = &oldscheme;
msg_Dbg(s, "using rar old naming for %d files nbvols %u", p_scheme->filescount, oldscheme.i_nbvols);
}
else if (newscheme.filescount)
{
for (int i = 0; i < oldscheme.filescount; i++)
RarFileDelete(oldscheme.files[i]);
free(oldscheme.files);
p_scheme = &newscheme;
msg_Dbg(s, "using rar new naming for %d files nbvols %u", p_scheme->filescount, oldscheme.i_nbvols);
}
else
{
msg_Info(s, "Invalid or unsupported RAR archive");
for (int i = 0; i < oldscheme.filescount; i++)
RarFileDelete(oldscheme.files[i]);
free(oldscheme.files);
for (int i = 0; i < newscheme.filescount; i++)
RarFileDelete(newscheme.files[i]);
free(newscheme.files);
goto error;
}
rar_file_t *file = NULL;
for (int i = 0; i < p_scheme->filescount; i++) {
if (!file && !strcmp(p_scheme->files[i]->name, name))
file = p_scheme->files[i];
else
RarFileDelete(p_scheme->files[i]);
}
free(p_scheme->files);
if (!file)
goto error;
access_sys_t *sys = access->p_sys = malloc(sizeof(*sys));
sys->s = s;
sys->file = file;
access->pf_read = Read;
access->pf_block = NULL;
access->pf_control = Control;
access->pf_seek = Seek;
rar_file_chunk_t dummy = {
.mrl = base,
};
sys->chunk = &dummy;
Seek(access, 0);
free(base);
return VLC_SUCCESS;
error:
if (s)
vlc_stream_Delete(s);
free(base);
return VLC_EGENERIC;
}
void RarAccessClose(vlc_object_t *object)
{
access_t *access = (access_t*)object;
access_sys_t *sys = access->p_sys;
if (sys->s)
vlc_stream_Delete(sys->s);
RarFileDelete(sys->file);
free(sys);
}
/*****************************************************************************
* stream.c: uncompressed RAR stream filter
*****************************************************************************
* Copyright (C) 2008-2010 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.
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <vlc_common.h>
#include <vlc_plugin.h>
#include "rar.h"
vlc_module_begin()
set_category(CAT_INPUT)
set_subcategory(SUBCAT_INPUT_STREAM_FILTER)
set_description(N_("Uncompressed RAR"))
set_capability("access", 0)
set_callbacks(RarAccessOpen, RarAccessClose)
add_submodule()
set_capability("stream_filter", 15)
set_callbacks(RarStreamOpen, RarStreamClose)
vlc_module_end()
/*****************************************************************************
* rar.c: uncompressed RAR parser
*****************************************************************************
* Copyright (C) 2008-2010 Laurent Aimar
* $Id$
*
* 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.
*****************************************************************************/
/*****************************************************************************
* Preamble
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <vlc_common.h>
#include <vlc_plugin.h>
#include <vlc_stream.h>
#include <assert.h>
#include <limits.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]);
}
free(file->chunk);
free(file->name);
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(stream_t *s, rar_block_t *hdr)
{
const uint8_t *peek;
int peek_size = vlc_stream_Peek(s, &peek, 11);
if (peek_size < 7)
return VLC_EGENERIC;
hdr->crc = GetWLE(&peek[0]);
hdr->type = peek[2];
hdr->flags = GetWLE(&peek[3]);
hdr->size = GetWLE(&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 VLC_EGENERIC;
hdr->add_size = GetDWLE(&peek[7]);
}
if (hdr->size < 7)
return VLC_EGENERIC;
return VLC_SUCCESS;
}
static int SkipBlock(stream_t *s, const rar_block_t *hdr)
{
uint64_t size = (uint64_t)hdr->size + hdr->add_size;
while (size > 0) {
int skip = __MIN(size, INT_MAX);
if (vlc_stream_Read(s, NULL, skip) < skip)
return VLC_EGENERIC;
size -= skip;
}
return VLC_SUCCESS;
}
static int IgnoreBlock(stream_t *s, int block)
{
/* */
rar_block_t bk;
if (PeekBlock(s, &bk) || bk.type != block)
return VLC_EGENERIC;
return SkipBlock(s, &bk);
}
static int SkipEnd(stream_t *s, const rar_block_t *hdr)
{
if (!(hdr->flags & RAR_BLOCK_END_HAS_NEXT))
return VLC_EGENERIC;
if (SkipBlock(s, hdr))
return VLC_EGENERIC;
/* Now, we need to look for a marker block,
* It seems that there is garbage at EOF */
for (;;) {
const uint8_t *peek;
if (vlc_stream_Peek(s, &peek, rar_marker_size) < rar_marker_size)
return VLC_EGENERIC;
if (!memcmp(peek, rar_marker, rar_marker_size))
break;
if (vlc_stream_Read(s, NULL, 1) != 1)
return VLC_EGENERIC;
}
/* Skip marker and archive blocks */
if (IgnoreBlock(s, RAR_BLOCK_MARKER))
return VLC_EGENERIC;
if (IgnoreBlock(s, RAR_BLOCK_ARCHIVE))
return VLC_EGENERIC;
return VLC_SUCCESS;
}
static int SkipFile(stream_t *s, int *count, rar_file_t ***file,
const rar_block_t *hdr, const char *volume_mrl)
{
const uint8_t *peek;
int min_size = 7+21;
if (hdr->flags & RAR_BLOCK_FILE_HAS_HIGH)
min_size += 8;
if (hdr->size < (unsigned)min_size)
return VLC_EGENERIC;
if (vlc_stream_Peek(s, &peek, min_size) < min_size)
return VLC_EGENERIC;
/* */
uint32_t file_size_low = GetDWLE(&peek[7+4]);
uint8_t method = peek[7+18];
uint16_t name_size = GetWLE(&peek[7+19]);
uint32_t file_size_high = 0;
if (hdr->flags & RAR_BLOCK_FILE_HAS_HIGH)
file_size_high = GetDWLE(&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 VLC_EGENERIC;
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;
if (vlc_stream_Peek(s, &peek, max_size) < max_size) {
free(name);
return VLC_EGENERIC;
}
memcpy(name, &peek[name_offset], name_size);
}
rar_file_t *current = NULL;
if (method != 0x30) {
msg_Dbg(s, "Ignoring compressed file %s (method=0x%2.2x)", 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 = malloc(sizeof(*current));
if (!current)
goto exit;
TAB_APPEND(*count, *file, current);
current->name = name;
current->size = file_size;
current->is_complete = false;
current->real_size = 0;
TAB_INIT(current->chunk_count, current->chunk);
name = NULL;
}
/* Append chunks */
rar_file_chunk_t *chunk = malloc(sizeof(*chunk));
if (chunk) {
chunk->mrl = strdup(volume_mrl);
chunk->offset = vlc_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;
}
TAB_APPEND(current->chunk_count, current->chunk, 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) {
bool can_seek = false;
vlc_stream_Control(s, STREAM_CAN_SEEK, &can_seek);
if (!can_seek && current->size > 0)
return VLC_EGENERIC;
}
if (SkipBlock(s, hdr))
return VLC_EGENERIC;
return VLC_SUCCESS;
}
int RarProbe(stream_t *s)
{
const uint8_t *peek;
if (vlc_stream_Peek(s, &peek, rar_marker_size) < rar_marker_size)
return VLC_EGENERIC;
if (memcmp(peek, rar_marker, rar_marker_size))
return VLC_EGENERIC;
return VLC_SUCCESS;
}
typedef struct {
const char *match;
const char *format;
int start;
int stop;
bool b_extonly;
} rar_pattern_t;
static const rar_pattern_t *FindVolumePattern(const char *location, bool b_extonly )
{
static const rar_pattern_t patterns[] = {
{ ".part1.rar", "%s.part%.1d.rar", 2, 9, false }, // new naming
{ ".part01.rar", "%s.part%.2d.rar", 2, 99, false }, // new
{ ".part001.rar", "%s.part%.3d.rar", 2, 999, false }, // new
{ ".rar", "%s.%c%.2d", 0, 999, true }, // old
{ NULL, NULL, 0, 0, false },
};
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 ( b_extonly && !patterns[i].b_extonly )
continue;
if (!strcmp(&location[location_size - match_size], patterns[i].match))
return &patterns[i];
}
return NULL;
}
int RarParse(stream_t *s, int *count, rar_file_t ***file, unsigned int *pi_nbvols,
bool b_extonly)
{
*count = 0;
*file = NULL;
*pi_nbvols = 1;
if( s->psz_url == NULL )
return VLC_EGENERIC;
const rar_pattern_t *pattern = FindVolumePattern(s->psz_url, b_extonly);
int volume_offset = 0;
char *volume_mrl = strdup(s->psz_url);
if (volume_mrl == NULL)
return VLC_ENOMEM;
stream_t *vol = s;
for (;;) {
/* Skip marker & archive */
if (IgnoreBlock(vol, RAR_BLOCK_MARKER) ||
IgnoreBlock(vol, RAR_BLOCK_ARCHIVE)) {
if (vol != s)
vlc_stream_Delete(vol);
free(volume_mrl);
return VLC_EGENERIC;
}
/* */
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)
vlc_stream_Delete(vol);
free(volume_mrl);
if (!has_next || !pattern)
return VLC_SUCCESS;
/* Open next volume */
const int volume_index = pattern->start + volume_offset++;
if (volume_index > pattern->stop)
return VLC_SUCCESS;
char *volume_base = strndup(s->psz_url,
strlen(s->psz_url) - strlen(pattern->match));
if (volume_base == NULL)
return VLC_SUCCESS;
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)
return VLC_SUCCESS;
const int s_flags = s->obj.flags;
s->obj.flags |= OBJECT_FLAGS_NOINTERACT;
vol = vlc_stream_NewURL(s, volume_mrl);
s->obj.flags = s_flags;
if (!vol) {
free(volume_mrl);
return VLC_SUCCESS;
}
(*pi_nbvols)++;
}
}
/*****************************************************************************
* rar.h: uncompressed RAR parser
*****************************************************************************
* Copyright (C) 2008-2010 Laurent Aimar