]> git.sesse.net Git - vlc/blob - modules/access/rar/access.c
Added support for multiple files in RAR archives.
[vlc] / modules / access / rar / access.c
1 /*****************************************************************************
2  * rar.c: uncompressed RAR access
3  *****************************************************************************
4  * Copyright (C) 2008-2010 Laurent Aimar
5  * $Id$
6  *
7  * Author: Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include <vlc_common.h>
32 #include <vlc_plugin.h>
33 #include <vlc_access.h>
34 #include <vlc_stream.h>
35 #include <vlc_url.h>
36
37 #include <assert.h>
38 #include <limits.h>
39
40 #include "rar.h"
41
42 /*****************************************************************************
43  * Module descriptor
44  *****************************************************************************/
45 static int  Open (vlc_object_t *);
46 static void Close(vlc_object_t *);
47
48 vlc_module_begin()
49     set_category(CAT_INPUT)
50     set_subcategory(SUBCAT_INPUT_STREAM_FILTER)
51     set_description(N_("Uncompressed RAR"))
52     set_capability("access", 0)
53     set_callbacks(Open, Close)
54     add_shortcut("rar")
55 vlc_module_end()
56
57 /*****************************************************************************
58  * Local definitions/prototypes
59  *****************************************************************************/
60 struct access_sys_t {
61     stream_t               *s;
62     rar_file_t             *file;
63     const rar_file_chunk_t *chunk;
64 };
65
66 static int Seek(access_t *access, uint64_t position)
67 {
68     access_sys_t *sys = access->p_sys;
69     const rar_file_t *file = sys->file;
70
71     if (position > file->real_size)
72         position = file->real_size;
73
74     /* Search the chunk */
75     for (int i = 0; i < file->chunk_count; i++) {
76         sys->chunk = file->chunk[i];
77         if (position < sys->chunk->cummulated_size + sys->chunk->size)
78             break;
79     }
80     access->info.i_pos = position;
81     access->info.b_eof = false;
82
83     const uint64_t offset = sys->chunk->offset +
84                             (position - sys->chunk->cummulated_size);
85     return stream_Seek(sys->s, offset);
86 }
87
88 static ssize_t Read(access_t *access, uint8_t *data, size_t size)
89 {
90     access_sys_t *sys = access->p_sys;
91
92     size_t total = 0;
93     while (total < size) {
94         const uint64_t chunk_end = sys->chunk->cummulated_size + sys->chunk->size;
95         int max = __MIN(__MIN((int64_t)(size - total), (int64_t)(chunk_end - access->info.i_pos)), INT_MAX);
96         if (max <= 0)
97             break;
98
99         int r = stream_Read(sys->s, data, max);
100         if (r <= 0)
101             break;
102
103         total += r;
104         if( data )
105             data += r;
106         access->info.i_pos += r;
107         if (access->info.i_pos >= chunk_end &&
108             Seek(access, access->info.i_pos))
109             break;
110     }
111     if (size > 0 && total <= 0)
112         access->info.b_eof = true;
113     return total;
114
115 }
116
117 static int Control(access_t *access, int query, va_list args)
118 {
119     stream_t *s = access->p_sys->s;
120     switch (query) {
121     case ACCESS_CAN_SEEK: {
122         bool *b = va_arg(args, bool *);
123         return stream_Control(s, STREAM_CAN_SEEK, b);
124     }
125     case ACCESS_CAN_FASTSEEK: {
126         bool *b = va_arg(args, bool *);
127         return stream_Control(s, STREAM_CAN_FASTSEEK, b);
128     }
129     /* FIXME the following request should ask the underlying access object */
130     case ACCESS_CAN_PAUSE:
131     case ACCESS_CAN_CONTROL_PACE: {
132         bool *b = va_arg(args, bool *);
133         *b = true;
134         return VLC_SUCCESS;
135     }
136     case ACCESS_GET_PTS_DELAY: {
137         int64_t *delay = va_arg(args, int64_t *);
138         *delay = DEFAULT_PTS_DELAY;
139         return VLC_SUCCESS;
140     }
141     case ACCESS_SET_PAUSE_STATE:
142         return VLC_SUCCESS;
143
144     default:
145         return VLC_EGENERIC;
146     }
147 }
148
149 static int Open(vlc_object_t *object)
150 {
151     access_t *access = (access_t*)object;
152
153     if (!strchr(access->psz_location, '|'))
154         return VLC_EGENERIC;
155
156     char *base = strdup(access->psz_location);
157     if (!base)
158         return VLC_EGENERIC;
159     char *name = strchr(base, '|');
160     *name++ = '\0';
161     decode_URI(base);
162
163     stream_t *s = stream_UrlNew(access, base);
164     if (!s)
165         goto error;
166     int count;
167     rar_file_t **files;
168     if (RarProbe(s) || RarParse(s, &count, &files) || count <= 0)
169         goto error;
170     rar_file_t *file = NULL;
171     for (int i = 0; i < count; i++) {
172         if (!file && !strcmp(files[i]->name, name))
173             file = files[i];
174         else
175             RarFileDelete(files[i]);
176     }
177     free(files);
178     if (!file)
179         goto error;
180
181     access_sys_t *sys = access->p_sys = malloc(sizeof(*sys));
182     sys->s    = s;
183     sys->file = file;
184
185     access->pf_read    = Read;
186     access->pf_block   = NULL;
187     access->pf_control = Control;
188     access->pf_seek    = Seek;
189
190     access_InitFields(access);
191     access->info.i_size = file->size;
192
193     Seek(access, 0);
194
195     free(base);
196     return VLC_SUCCESS;
197
198 error:
199     if (s)
200         stream_Delete(s);
201     free(base);
202     return VLC_EGENERIC;
203 }
204
205 static void Close(vlc_object_t *object)
206 {
207     access_t *access = (access_t*)object;
208     access_sys_t *sys = access->p_sys;
209
210     stream_Delete(sys->s);
211     RarFileDelete(sys->file);
212     free(sys);
213 }
214