Audacious
$Id:Doxyfile42802007-03-2104:39:00Znenolod$
|
00001 /* 00002 * probe.c 00003 * Copyright 2009-2010 John Lindgren 00004 * 00005 * This file is part of Audacious. 00006 * 00007 * Audacious is free software: you can redistribute it and/or modify it under 00008 * the terms of the GNU General Public License as published by the Free Software 00009 * Foundation, version 2 or version 3 of the License. 00010 * 00011 * Audacious is distributed in the hope that it will be useful, but WITHOUT ANY 00012 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 00013 * A PARTICULAR PURPOSE. See the GNU General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU General Public License along with 00016 * Audacious. If not, see <http://www.gnu.org/licenses/>. 00017 * 00018 * The Audacious team does not consider modular code linking to Audacious or 00019 * using our public API to be a derived work. 00020 */ 00021 00022 #include <stdio.h> 00023 #include <string.h> 00024 00025 #include <libaudcore/audstrings.h> 00026 00027 #include "debug.h" 00028 #include "misc.h" 00029 #include "playlist.h" 00030 #include "plugin.h" 00031 #include "plugins.h" 00032 #include "probe-buffer.h" 00033 00034 typedef struct 00035 { 00036 gchar * filename; 00037 VFSFile * handle; 00038 gboolean buffered; 00039 PluginHandle * plugin; 00040 } 00041 ProbeState; 00042 00043 static gboolean check_opened (ProbeState * state) 00044 { 00045 if (state->handle != NULL) 00046 return TRUE; 00047 00048 AUDDBG ("Opening %s.\n", state->filename); 00049 if ((state->buffered = vfs_is_remote (state->filename))) 00050 state->handle = probe_buffer_new (state->filename); 00051 else 00052 state->handle = vfs_fopen (state->filename, "r"); 00053 00054 if (state->handle != NULL) 00055 return TRUE; 00056 00057 AUDDBG ("FAILED.\n"); 00058 return FALSE; 00059 } 00060 00061 static gboolean probe_func (PluginHandle * plugin, ProbeState * state) 00062 { 00063 AUDDBG ("Trying %s.\n", plugin_get_name (plugin)); 00064 InputPlugin * decoder = plugin_get_header (plugin); 00065 if (decoder == NULL) 00066 return TRUE; 00067 00068 if (decoder->is_our_file_from_vfs != NULL) 00069 { 00070 if (! check_opened (state)) 00071 return FALSE; 00072 00073 if (state->buffered) 00074 probe_buffer_set_decoder (state->handle, plugin_get_name (plugin)); 00075 00076 if (decoder->is_our_file_from_vfs (state->filename, state->handle)) 00077 { 00078 state->plugin = plugin; 00079 return FALSE; 00080 } 00081 00082 if (vfs_fseek (state->handle, 0, SEEK_SET) < 0) 00083 return FALSE; 00084 } 00085 00086 return TRUE; 00087 } 00088 00089 /* Optimization: If we have found plugins with a key match, assume that at least 00090 * one of them will succeed. This means that we need not check the very last 00091 * plugin. (If there is only one, we do not need to check it at all.) This is 00092 * implemented as follows: 00093 * 00094 * 1. On the first call, assume until further notice the plugin passed is the 00095 * last one and will therefore succeed. 00096 * 2. On a subsequent call, think twice and probe the plugin we assumed would 00097 * succeed. If it does in fact succeed, then we are done. If not, assume 00098 * similarly that the plugin passed in this call is the last one. 00099 */ 00100 00101 static gboolean probe_func_fast (PluginHandle * plugin, ProbeState * state) 00102 { 00103 if (state->plugin != NULL) 00104 { 00105 PluginHandle * prev = state->plugin; 00106 state->plugin = NULL; 00107 00108 if (prev != NULL && ! probe_func (prev, state)) 00109 return FALSE; 00110 } 00111 00112 AUDDBG ("Guessing %s.\n", plugin_get_name (plugin)); 00113 state->plugin = plugin; 00114 return TRUE; 00115 } 00116 00117 static void probe_by_scheme (ProbeState * state) 00118 { 00119 gchar * s = strstr (state->filename, "://"); 00120 00121 if (s == NULL) 00122 return; 00123 00124 AUDDBG ("Probing by scheme.\n"); 00125 * s = 0; 00126 input_plugin_for_key (INPUT_KEY_SCHEME, state->filename, (PluginForEachFunc) 00127 probe_func_fast, state); 00128 * s = ':'; 00129 } 00130 00131 static void probe_by_extension (ProbeState * state) 00132 { 00133 gchar * s = strrchr (state->filename, '.'); 00134 00135 if (s == NULL) 00136 return; 00137 00138 AUDDBG ("Probing by extension.\n"); 00139 s = g_ascii_strdown (s + 1, -1); 00140 00141 gchar * q = strrchr (s, '?'); 00142 if (q != NULL) 00143 * q = 0; 00144 00145 input_plugin_for_key (INPUT_KEY_EXTENSION, s, (PluginForEachFunc) 00146 probe_func_fast, state); 00147 g_free (s); 00148 } 00149 00150 static void probe_by_mime (ProbeState * state) 00151 { 00152 gchar * mime; 00153 00154 if (! check_opened (state)) 00155 return; 00156 00157 if ((mime = vfs_get_metadata (state->handle, "content-type")) == NULL) 00158 return; 00159 00160 AUDDBG ("Probing by MIME type.\n"); 00161 input_plugin_for_key (INPUT_KEY_MIME, mime, (PluginForEachFunc) 00162 probe_func_fast, state); 00163 g_free (mime); 00164 } 00165 00166 static void probe_by_content (ProbeState * state) 00167 { 00168 AUDDBG ("Probing by content.\n"); 00169 plugin_for_enabled (PLUGIN_TYPE_INPUT, (PluginForEachFunc) probe_func, state); 00170 } 00171 00172 PluginHandle * file_find_decoder (const gchar * filename, gboolean fast) 00173 { 00174 ProbeState state; 00175 00176 AUDDBG ("Probing %s.\n", filename); 00177 state.plugin = NULL; 00178 state.filename = filename_split_subtune (filename, NULL); 00179 state.handle = NULL; 00180 00181 probe_by_scheme (& state); 00182 00183 if (state.plugin != NULL) 00184 goto DONE; 00185 00186 probe_by_extension (& state); 00187 00188 if (state.plugin != NULL || fast) 00189 goto DONE; 00190 00191 probe_by_mime (& state); 00192 00193 if (state.plugin != NULL) 00194 goto DONE; 00195 00196 probe_by_content (& state); 00197 00198 DONE: 00199 g_free (state.filename); 00200 00201 if (state.handle != NULL) 00202 vfs_fclose (state.handle); 00203 00204 return state.plugin; 00205 } 00206 00207 Tuple * file_read_tuple (const gchar * filename, PluginHandle * decoder) 00208 { 00209 InputPlugin * ip = plugin_get_header (decoder); 00210 g_return_val_if_fail (ip, NULL); 00211 g_return_val_if_fail (ip->probe_for_tuple, NULL); 00212 00213 gchar * real = filename_split_subtune (filename, NULL); 00214 VFSFile * handle = vfs_fopen (real, "r"); 00215 g_free (real); 00216 00217 Tuple * tuple = ip->probe_for_tuple (filename, handle); 00218 00219 if (handle) 00220 vfs_fclose (handle); 00221 00222 return tuple; 00223 } 00224 00225 gboolean file_read_image (const gchar * filename, PluginHandle * decoder, 00226 void * * data, gint * size) 00227 { 00228 if (! input_plugin_has_images (decoder)) 00229 return FALSE; 00230 00231 InputPlugin * ip = plugin_get_header (decoder); 00232 g_return_val_if_fail (ip, FALSE); 00233 g_return_val_if_fail (ip->get_song_image, FALSE); 00234 00235 gchar * real = filename_split_subtune (filename, NULL); 00236 VFSFile * handle = vfs_fopen (real, "r"); 00237 g_free (real); 00238 00239 gboolean success = ip->get_song_image (filename, handle, data, size); 00240 00241 if (handle) 00242 vfs_fclose (handle); 00243 00244 return success; 00245 } 00246 00247 gboolean file_can_write_tuple (const gchar * filename, PluginHandle * decoder) 00248 { 00249 return input_plugin_can_write_tuple (decoder); 00250 } 00251 00252 gboolean file_write_tuple (const gchar * filename, PluginHandle * decoder, 00253 const Tuple * tuple) 00254 { 00255 InputPlugin * ip = plugin_get_header (decoder); 00256 g_return_val_if_fail (ip, FALSE); 00257 g_return_val_if_fail (ip->update_song_tuple, FALSE); 00258 00259 gchar * real = filename_split_subtune (filename, NULL); 00260 VFSFile * handle = vfs_fopen (real, "r+"); 00261 g_free (real); 00262 00263 if (! handle) 00264 return FALSE; 00265 00266 gboolean success = ip->update_song_tuple (tuple, handle); 00267 00268 if (handle) 00269 vfs_fclose (handle); 00270 00271 if (success) 00272 playlist_rescan_file (filename); 00273 00274 return success; 00275 } 00276 00277 gboolean custom_infowin (const gchar * filename, PluginHandle * decoder) 00278 { 00279 if (! input_plugin_has_infowin (decoder)) 00280 return FALSE; 00281 00282 InputPlugin * ip = plugin_get_header (decoder); 00283 g_return_val_if_fail (ip, FALSE); 00284 g_return_val_if_fail (ip->file_info_box, FALSE); 00285 00286 ip->file_info_box (filename); 00287 return TRUE; 00288 }