1 /*****************************************************************************
2 * gnomevfs.c: GnomeVFS input
3 *****************************************************************************
4 * Copyright (C) 2005 the VideoLAN team
7 * Authors: Benjamin Pracht <bigben -AT- videolan -DOT- org>
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.
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.
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 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
32 #include <vlc_common.h>
33 #include <vlc_plugin.h>
34 #include <vlc_access.h>
36 #include <libgnomevfs/gnome-vfs.h>
39 #include <vlc_charset.h>
42 /*****************************************************************************
44 *****************************************************************************/
45 static int Open ( vlc_object_t
* );
46 static void Close( vlc_object_t
* );
48 #define CACHING_TEXT N_("Caching value in ms")
49 #define CACHING_LONGTEXT N_( \
50 "Caching value for GnomeVFS streams."\
51 "This value should be set in milliseconds." )
54 set_description( N_("GnomeVFS input") )
55 set_shortname( "GnomeVFS" )
56 set_category( CAT_INPUT
)
57 set_subcategory( SUBCAT_INPUT_ACCESS
)
58 add_integer( "gnomevfs-caching", DEFAULT_PTS_DELAY
/ 1000, CACHING_TEXT
, CACHING_LONGTEXT
, true )
59 set_capability( "access", 10 )
60 add_shortcut( "gnomevfs" )
61 set_callbacks( Open
, Close
)
65 /*****************************************************************************
67 *****************************************************************************/
68 static int Seek( access_t
*, uint64_t );
69 static ssize_t
Read( access_t
*, uint8_t *, size_t );
70 static int Control( access_t
*, int, va_list );
74 unsigned int i_nb_reads
;
77 GnomeVFSHandle
*p_handle
;
78 GnomeVFSFileInfo
*p_file_info
;
85 /* NOTE: we do not handle memory errors in this plugin.
86 * Underlying glib does not, so there is no point in doing it here either. */
88 /*****************************************************************************
90 *****************************************************************************/
91 static int Open( vlc_object_t
*p_this
)
93 access_t
*p_access
= (access_t
*)p_this
;
94 access_sys_t
*p_sys
= NULL
;
95 char *psz_name
= NULL
;
98 char *psz_unescaped
= NULL
;
99 char *psz_expand_tilde
= NULL
;
100 GnomeVFSURI
*p_uri
= NULL
;
101 GnomeVFSResult i_ret
;
102 GnomeVFSHandle
*p_handle
= NULL
;
103 if( !(gnome_vfs_init()) )
105 msg_Warn( p_access
, "couldn't initilize GnomeVFS" );
110 Since GnomeVFS segfaults on exit if we initialize it without trying to
111 open a file with a valid protocol, try to open at least file:// */
112 gnome_vfs_open( &p_handle
, "file://", 5 );
114 STANDARD_READ_ACCESS_INIT
;
116 p_sys
->p_handle
= p_handle
;
117 p_sys
->i_nb_reads
= 0;
118 p_sys
->b_pace_control
= true;
120 if( strcmp( "gnomevfs", p_access
->psz_access
) &&
121 *(p_access
->psz_access
) != '\0')
123 asprintf( &psz_name
, "%s://%s", p_access
->psz_access
,
124 p_access
->psz_location
);
128 psz_name
= strdup( p_access
->psz_location
);
130 psz
= ToLocale( psz_name
);
131 psz_expand_tilde
= gnome_vfs_expand_initial_tilde( psz
);
134 psz_unescaped
= gnome_vfs_make_uri_from_shell_arg( psz_expand_tilde
);
136 /* gnome_vfs_make_uri_from_shell_arg will only escape the uri
137 for relative paths. So we need to use
138 gnome_vfs_escape_host_and_path_string in other cases. */
140 if( !strcmp( psz_unescaped
, psz_expand_tilde
) )
142 /* Now we are sure that we have a complete valid unescaped URI beginning
143 with the protocol. We want to escape it. However, gnomevfs's escaping
144 function are broken and will try to escape characters un the username/
145 password field. So parse the URI with vlc_UrlParse ans only escape the
149 char *psz_escaped_path
;
150 char *psz_path_begin
;
152 vlc_UrlParse( &url
, psz_unescaped
, 0 );
153 psz_escaped_path
= gnome_vfs_escape_path_string( url
.psz_path
);
155 if( psz_escaped_path
)
157 /* Now let's reconstruct a valid URI from all that stuff */
158 psz_path_begin
= psz_unescaped
+ strlen( psz_unescaped
)
159 - strlen( url
.psz_path
);
160 *psz_path_begin
= '\0';
161 asprintf( &psz_uri
, "%s%s", psz_unescaped
, psz_escaped_path
);
163 g_free( psz_escaped_path
);
164 g_free( psz_unescaped
);
168 psz_uri
= psz_unescaped
;
173 psz_uri
= psz_unescaped
;
176 g_free( psz_expand_tilde
);
177 p_uri
= gnome_vfs_uri_new( psz_uri
);
180 p_sys
->p_file_info
= gnome_vfs_file_info_new();
181 i_ret
= gnome_vfs_get_file_info_uri( p_uri
,
182 p_sys
->p_file_info
, 8 );
186 msg_Warn( p_access
, "cannot get file info for uri %s (%s)",
187 psz_uri
, gnome_vfs_result_to_string( i_ret
) );
188 gnome_vfs_file_info_unref( p_sys
->p_file_info
);
189 gnome_vfs_uri_unref( p_uri
);
198 msg_Warn( p_access
, "cannot parse MRL %s or unsupported protocol", psz_name
);
205 msg_Dbg( p_access
, "opening file `%s'", psz_uri
);
206 i_ret
= gnome_vfs_open( &(p_sys
->p_handle
), psz_uri
, 5 );
209 msg_Warn( p_access
, "cannot open file %s: %s", psz_uri
,
210 gnome_vfs_result_to_string( i_ret
) );
212 gnome_vfs_uri_unref( p_uri
);
219 if (GNOME_VFS_FILE_INFO_LOCAL( p_sys
->p_file_info
))
221 p_sys
->b_local
= true;
224 if( p_sys
->p_file_info
->type
== GNOME_VFS_FILE_TYPE_REGULAR
||
225 p_sys
->p_file_info
->type
== GNOME_VFS_FILE_TYPE_CHARACTER_DEVICE
||
226 p_sys
->p_file_info
->type
== GNOME_VFS_FILE_TYPE_BLOCK_DEVICE
)
228 p_sys
->b_seekable
= true;
229 p_access
->info
.i_size
= (int64_t)(p_sys
->p_file_info
->size
);
231 else if( p_sys
->p_file_info
->type
== GNOME_VFS_FILE_TYPE_FIFO
232 || p_sys
->p_file_info
->type
== GNOME_VFS_FILE_TYPE_SOCKET
)
234 p_sys
->b_seekable
= false;
238 msg_Err( p_access
, "unknown file type for `%s'", psz_name
);
242 if( p_sys
->b_seekable
&& !p_access
->info
.i_size
)
244 /* FIXME that's bad because all others access will be probed */
245 msg_Warn( p_access
, "file %s is empty, aborting", psz_name
);
246 gnome_vfs_file_info_unref( p_sys
->p_file_info
);
247 gnome_vfs_uri_unref( p_uri
);
254 /* Update default_pts to a suitable value for file access */
255 var_Create( p_access
, "gnomevfs-caching",
256 VLC_VAR_INTEGER
| VLC_VAR_DOINHERIT
);
259 p_sys
->psz_name
= psz_name
;
260 gnome_vfs_uri_unref( p_uri
);
264 /*****************************************************************************
265 * Close: close the target
266 *****************************************************************************/
267 static void Close( vlc_object_t
* p_this
)
269 access_t
*p_access
= (access_t
*)p_this
;
270 access_sys_t
*p_sys
= p_access
->p_sys
;
273 i_result
= gnome_vfs_close( p_sys
->p_handle
);
276 msg_Err( p_access
, "cannot close %s: %s", p_sys
->psz_name
,
277 gnome_vfs_result_to_string( i_result
) );
280 gnome_vfs_file_info_unref( p_sys
->p_file_info
);
282 free( p_sys
->psz_name
);
286 /*****************************************************************************
287 * Read: standard read on a file descriptor.
288 *****************************************************************************/
289 static ssize_t
Read( access_t
*p_access
, uint8_t *p_buffer
, size_t i_len
)
291 access_sys_t
*p_sys
= p_access
->p_sys
;
292 GnomeVFSFileSize i_read_len
;
295 i_ret
= gnome_vfs_read( p_sys
->p_handle
, p_buffer
,
296 (GnomeVFSFileSize
)i_len
, &i_read_len
);
299 p_access
->info
.b_eof
= true;
300 if( i_ret
!= GNOME_VFS_ERROR_EOF
)
302 msg_Err( p_access
, "read failed (%s)",
303 gnome_vfs_result_to_string( i_ret
) );
309 if( p_access
->info
.i_size
!= 0 &&
310 (p_sys
->i_nb_reads
% INPUT_FSTAT_NB_READS
) == 0 &&
313 gnome_vfs_file_info_clear( p_sys
->p_file_info
);
314 i_ret
= gnome_vfs_get_file_info_from_handle( p_sys
->p_handle
,
315 p_sys
->p_file_info
, 8 );
318 msg_Warn( p_access
, "couldn't get file properties again (%s)",
319 gnome_vfs_result_to_string( i_ret
) );
323 p_access
->info
.i_size
= (int64_t)(p_sys
->p_file_info
->size
);
328 p_access
->info
.i_pos
+= (int64_t)i_read_len
;
330 /* Some Acces (http) never return EOF and loop on the file */
331 if( p_access
->info
.i_pos
> p_access
->info
.i_size
)
333 p_access
->info
.b_eof
= true;
336 return (int)i_read_len
;
339 /*****************************************************************************
340 * Seek: seek to a specific location in a file
341 *****************************************************************************/
342 static int Seek( access_t
*p_access
, uint64_t i_pos
)
344 access_sys_t
*p_sys
= p_access
->p_sys
;
347 i_ret
= gnome_vfs_seek( p_sys
->p_handle
, GNOME_VFS_SEEK_START
,
348 (GnomeVFSFileOffset
)i_pos
);
351 p_access
->info
.i_pos
= i_pos
;
355 GnomeVFSFileSize i_offset
;
356 msg_Err( p_access
, "cannot seek (%s)",
357 gnome_vfs_result_to_string( i_ret
) );
358 i_ret
= gnome_vfs_tell( p_sys
->p_handle
, &i_offset
);
361 msg_Err( p_access
, "cannot tell the current position (%s)",
362 gnome_vfs_result_to_string( i_ret
) );
367 p_access
->info
.b_eof
= false;
373 /*****************************************************************************
375 *****************************************************************************/
376 static int Control( access_t
*p_access
, int i_query
, va_list args
)
378 access_sys_t
*p_sys
= p_access
->p_sys
;
385 case ACCESS_CAN_SEEK
:
386 case ACCESS_CAN_FASTSEEK
:
387 pb_bool
= (bool*)va_arg( args
, bool* );
388 *pb_bool
= p_sys
->b_seekable
;
391 case ACCESS_CAN_PAUSE
:
392 case ACCESS_CAN_CONTROL_PACE
:
393 pb_bool
= (bool*)va_arg( args
, bool* );
394 *pb_bool
= p_sys
->b_pace_control
;
397 case ACCESS_GET_PTS_DELAY
:
398 pi_64
= (int64_t*)va_arg( args
, int64_t * );
399 *pi_64
= var_GetInteger( p_access
,
400 "gnomevfs-caching" ) * INT64_C(1000);
404 case ACCESS_SET_PAUSE_STATE
:
408 case ACCESS_GET_TITLE_INFO
:
409 case ACCESS_SET_TITLE
:
410 case ACCESS_SET_SEEKPOINT
:
411 case ACCESS_SET_PRIVATE_ID_STATE
:
412 case ACCESS_GET_META
:
413 case ACCESS_GET_CONTENT_TYPE
:
417 msg_Warn( p_access
, "unimplemented query in control" );