]> git.sesse.net Git - vlc/blob - modules/access/rar/access.c
v4l2: add v4l shortcut
[vlc] / modules / access / rar / access.c
1 /*****************************************************************************
2  * access.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     const rar_file_chunk_t *old_chunk = sys->chunk;
76     for (int i = 0; i < file->chunk_count; i++) {
77         sys->chunk = file->chunk[i];
78         if (position < sys->chunk->cummulated_size + sys->chunk->size)
79             break;
80     }
81     access->info.i_pos = position;
82     access->info.b_eof = false;
83
84     const uint64_t offset = sys->chunk->offset +
85                             (position - sys->chunk->cummulated_size);
86
87     if (strcmp(old_chunk->mrl, sys->chunk->mrl)) {
88         if (sys->s)
89             stream_Delete(sys->s);
90         sys->s = stream_UrlNew(access, sys->chunk->mrl);
91     }
92     return sys->s ? stream_Seek(sys->s, offset) : VLC_EGENERIC;
93 }
94
95 static ssize_t Read(access_t *access, uint8_t *data, size_t size)
96 {
97     access_sys_t *sys = access->p_sys;
98
99     size_t total = 0;
100     while (total < size) {
101         const uint64_t chunk_end = sys->chunk->cummulated_size + sys->chunk->size;
102         int max = __MIN(__MIN((int64_t)(size - total), (int64_t)(chunk_end - access->info.i_pos)), INT_MAX);
103         if (max <= 0)
104             break;
105
106         int r = sys->s ? stream_Read(sys->s, data, max) : -1;
107         if (r <= 0)
108             break;
109
110         total += r;
111         if( data )
112             data += r;
113         access->info.i_pos += r;
114         if (access->info.i_pos >= chunk_end &&
115             Seek(access, access->info.i_pos))
116             break;
117     }
118     if (size > 0 && total <= 0)
119         access->info.b_eof = true;
120     return total;
121
122 }
123
124 static int Control(access_t *access, int query, va_list args)
125 {
126     stream_t *s = access->p_sys->s;
127     if (!s)
128         return VLC_EGENERIC;
129
130     switch (query) {
131     case ACCESS_CAN_SEEK: {
132         bool *b = va_arg(args, bool *);
133         return stream_Control(s, STREAM_CAN_SEEK, b);
134     }
135     case ACCESS_CAN_FASTSEEK: {
136         bool *b = va_arg(args, bool *);
137         return stream_Control(s, STREAM_CAN_FASTSEEK, b);
138     }
139     /* FIXME the following request should ask the underlying access object */
140     case ACCESS_CAN_PAUSE:
141     case ACCESS_CAN_CONTROL_PACE: {
142         bool *b = va_arg(args, bool *);
143         *b = true;
144         return VLC_SUCCESS;
145     }
146     case ACCESS_GET_PTS_DELAY: {
147         int64_t *delay = va_arg(args, int64_t *);
148         *delay = DEFAULT_PTS_DELAY;
149         return VLC_SUCCESS;
150     }
151     case ACCESS_SET_PAUSE_STATE:
152         return VLC_SUCCESS;
153
154     default:
155         return VLC_EGENERIC;
156     }
157 }
158
159 static int Open(vlc_object_t *object)
160 {
161     access_t *access = (access_t*)object;
162
163     if (!strchr(access->psz_location, '|'))
164         return VLC_EGENERIC;
165
166     char *base = strdup(access->psz_location);
167     if (!base)
168         return VLC_EGENERIC;
169     char *name = strchr(base, '|');
170     *name++ = '\0';
171     decode_URI(base);
172
173     stream_t *s = stream_UrlNew(access, base);
174     if (!s)
175         goto error;
176     int count;
177     rar_file_t **files;
178     if (RarProbe(s) || RarParse(s, &count, &files) || count <= 0)
179         goto error;
180     rar_file_t *file = NULL;
181     for (int i = 0; i < count; i++) {
182         if (!file && !strcmp(files[i]->name, name))
183             file = files[i];
184         else
185             RarFileDelete(files[i]);
186     }
187     free(files);
188     if (!file)
189         goto error;
190
191     access_sys_t *sys = access->p_sys = malloc(sizeof(*sys));
192     sys->s    = s;
193     sys->file = file;
194
195     access->pf_read    = Read;
196     access->pf_block   = NULL;
197     access->pf_control = Control;
198     access->pf_seek    = Seek;
199
200     access_InitFields(access);
201     access->info.i_size = file->size;
202
203     rar_file_chunk_t dummy = {
204         .mrl = base,
205     };
206     sys->chunk = &dummy;
207     Seek(access, 0);
208
209     free(base);
210     return VLC_SUCCESS;
211
212 error:
213     if (s)
214         stream_Delete(s);
215     free(base);
216     return VLC_EGENERIC;
217 }
218
219 static void Close(vlc_object_t *object)
220 {
221     access_t *access = (access_t*)object;
222     access_sys_t *sys = access->p_sys;
223
224     if (sys->s)
225         stream_Delete(sys->s);
226     RarFileDelete(sys->file);
227     free(sys);
228 }
229