]> git.sesse.net Git - vlc/blob - modules/access/archive/stream.c
access: archive: remove dead initialization
[vlc] / modules / access / archive / stream.c
1 /*****************************************************************************
2  * stream.c: libarchive based stream filter
3  *****************************************************************************
4  * Copyright (C) 2014 Videolan Team
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation; either version 2.1 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19  *****************************************************************************/
20
21 #include "archive.h"
22
23 #include <vlc_stream.h>
24 #include <vlc_url.h>
25 #include <vlc_input_item.h>
26
27 #include <archive.h>
28 #include <archive_entry.h>
29
30 struct stream_sys_t
31 {
32     struct archive *p_archive;
33     bool b_source_canseek;
34     uint8_t buffer[ARCHIVE_READ_SIZE];
35 };
36
37 static int Peek(stream_t *p_stream, const uint8_t **pp_peek, unsigned int i_peek)
38 {
39     VLC_UNUSED(p_stream);
40     VLC_UNUSED(pp_peek);
41     VLC_UNUSED(i_peek);
42     return 0;
43 }
44
45 static int Control(stream_t *p_stream, int i_query, va_list args)
46 {
47     switch( i_query )
48     {
49         case STREAM_IS_DIRECTORY:
50             *va_arg( args, bool* ) = true;
51             break;
52
53         case STREAM_CAN_SEEK:
54         case STREAM_CAN_FASTSEEK:
55         case STREAM_GET_SIZE:
56         case STREAM_GET_POSITION:
57         case STREAM_SET_POSITION:
58         case STREAM_UPDATE_SIZE:
59         case STREAM_SET_RECORD_STATE:
60         case STREAM_GET_CONTENT_TYPE:
61             return VLC_EGENERIC;
62
63         default:
64             return stream_vaControl( p_stream->p_source, i_query, args );
65     }
66
67     return VLC_SUCCESS;
68 }
69
70 static ssize_t ReadCallback(struct archive *p_archive, void *p_object, const void **pp_buffer)
71 {
72     VLC_UNUSED(p_archive);
73     stream_t *p_stream = (stream_t*)p_object;
74
75     *pp_buffer = &p_stream->p_sys->buffer;
76     return stream_Read(p_stream->p_source, &p_stream->p_sys->buffer, ARCHIVE_READ_SIZE);
77 }
78
79 static ssize_t SkipCallback(struct archive *p_archive, void *p_object, ssize_t i_request)
80 {
81     VLC_UNUSED(p_archive);
82     stream_t *p_stream = (stream_t*)p_object;
83     ssize_t i_skipped = 0;
84
85     /* be smart as small seeks converts to reads */
86     if (p_stream->p_sys->b_source_canseek)
87     {
88         int64_t i_pos = stream_Tell(p_stream->p_source);
89         if (i_pos >=0)
90             stream_Seek(p_stream->p_source, i_pos + i_request);
91         i_skipped = stream_Tell(p_stream->p_source) - i_pos;
92     }
93     else while(i_request)
94     {
95         int i_skip = __MIN(INT32_MAX, i_request);
96         int i_read = stream_Read(p_stream->p_source, NULL, i_skip);
97         if (i_read > 0)
98             i_skipped += i_read;
99         else
100             break;
101         i_request -= i_read;
102     }
103
104     return i_skipped;
105 }
106
107 static ssize_t SeekCallback(struct archive *p_archive, void *p_object, ssize_t i_offset, int i_whence)
108 {
109     VLC_UNUSED(p_archive);
110     stream_t *p_stream = (stream_t*)p_object;
111     ssize_t i_pos;
112
113     switch(i_whence)
114     {
115     case SEEK_CUR:
116         i_pos = stream_Tell(p_stream->p_source);
117         break;
118     case SEEK_SET:
119         i_pos = 0;
120         break;
121     case SEEK_END:
122         i_pos = stream_Size(p_stream->p_source) - 1;
123         break;
124     default:
125         return -1;
126     }
127
128     if (i_pos < 0)
129         return -1;
130
131     stream_Seek(p_stream->p_source, i_pos + i_offset); /* We don't care about return val */
132     return stream_Tell(p_stream->p_source);
133 }
134
135 static int Browse(stream_t *p_stream, input_item_node_t *p_node)
136 {
137     stream_sys_t *p_sys = p_stream->p_sys;
138     struct archive_entry *p_entry;
139
140     while(archive_read_next_header(p_sys->p_archive, &p_entry) == ARCHIVE_OK)
141     {
142         char *psz_uri = NULL;
143         char *psz_access_uri = NULL;
144         int i_ret = asprintf(&psz_access_uri, "%s://%s%c%s", p_stream->psz_access,
145                              p_stream->psz_path, ARCHIVE_SEP_CHAR, archive_entry_pathname(p_entry));
146         if (i_ret == -1)
147             goto error;
148         i_ret = asprintf(&psz_uri, "archive://%s", psz_access_uri);
149         free(psz_access_uri);
150         if( i_ret == -1 )
151             goto error;
152
153         input_item_t *p_item = input_item_New(psz_uri, archive_entry_pathname(p_entry));
154         free( psz_uri );
155         if(p_item == NULL)
156             goto error;
157
158         input_item_CopyOptions(p_node->p_item, p_item);
159         input_item_node_AppendItem(p_node, p_item);
160         msg_Dbg(p_stream, "declaring playlist entry %s", archive_entry_pathname(p_entry));
161         input_item_Release(p_item);
162     }
163
164     return VLC_SUCCESS;
165
166 error:
167     return VLC_ENOITEM;
168 }
169
170 int StreamOpen(vlc_object_t *p_object)
171 {
172     stream_t *p_stream = (stream_t*) p_object;
173     stream_sys_t *p_sys;
174
175     if (!ProbeArchiveFormat(p_stream->p_source))
176         return VLC_EGENERIC;
177
178     p_stream->p_sys = p_sys = calloc( 1, sizeof( *p_sys ) );
179     if( !p_sys )
180         return VLC_ENOMEM;
181
182     p_sys->p_archive = archive_read_new();
183     if (!p_sys->p_archive)
184     {
185         msg_Err(p_stream, "can't create libarchive instance: %s",
186                 archive_error_string(p_sys->p_archive));
187         StreamClose(p_object);
188         return VLC_EGENERIC;
189     }
190
191     EnableArchiveFormats(p_sys->p_archive);
192
193     /* Seek callback must only be set if calls are guaranteed to succeed */
194     stream_Control(p_stream->p_source, STREAM_CAN_SEEK, &p_sys->b_source_canseek);
195     if(p_sys->b_source_canseek)
196         archive_read_set_seek_callback(p_sys->p_archive, SeekCallback);
197
198     if (archive_read_open2(p_sys->p_archive, p_stream, NULL, ReadCallback, SkipCallback, NULL) != ARCHIVE_OK)
199     {
200         msg_Err(p_stream, "can't open archive: %s",
201                 archive_error_string(p_sys->p_archive));
202         StreamClose(p_object);
203         return VLC_EGENERIC;
204     }
205
206     p_stream->pf_read = NULL;
207     p_stream->pf_peek = Peek;
208     p_stream->pf_control = Control;
209     p_stream->pf_readdir = Browse;
210
211     return VLC_SUCCESS;
212 }
213
214 void StreamClose(vlc_object_t *object)
215 {
216     stream_t *p_stream = (stream_t*)object;
217     stream_sys_t *p_sys = p_stream->p_sys;
218
219     if (p_sys->p_archive)
220     {
221         archive_read_close(p_sys->p_archive);
222         archive_read_free(p_sys->p_archive);
223     }
224
225     free(p_sys);
226 }