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 gchar c; 00121 00122 if (s == NULL) 00123 return; 00124 00125 AUDDBG ("Probing by scheme.\n"); 00126 c = s[3]; 00127 s[3] = 0; 00128 input_plugin_for_key (INPUT_KEY_SCHEME, state->filename, (PluginForEachFunc) 00129 probe_func_fast, state); 00130 s[3] = c; 00131 } 00132 00133 static void probe_by_extension (ProbeState * state) 00134 { 00135 gchar * s = strrchr (state->filename, '.'); 00136 00137 if (s == NULL) 00138 return; 00139 00140 AUDDBG ("Probing by extension.\n"); 00141 s = g_ascii_strdown (s + 1, -1); 00142 00143 gchar * q = strrchr (s, '?'); 00144 if (q != NULL) 00145 * q = 0; 00146 00147 input_plugin_for_key (INPUT_KEY_EXTENSION, s, (PluginForEachFunc) 00148 probe_func_fast, state); 00149 g_free (s); 00150 } 00151 00152 static void probe_by_mime (ProbeState * state) 00153 { 00154 gchar * mime; 00155 00156 if (! check_opened (state)) 00157 return; 00158 00159 if ((mime = vfs_get_metadata (state->handle, "content-type")) == NULL) 00160 return; 00161 00162 AUDDBG ("Probing by MIME type.\n"); 00163 input_plugin_for_key (INPUT_KEY_MIME, mime, (PluginForEachFunc) 00164 probe_func_fast, state); 00165 g_free (mime); 00166 } 00167 00168 static void probe_by_content (ProbeState * state) 00169 { 00170 AUDDBG ("Probing by content.\n"); 00171 plugin_for_enabled (PLUGIN_TYPE_INPUT, (PluginForEachFunc) probe_func, state); 00172 } 00173 00174 PluginHandle * file_find_decoder (const gchar * filename, gboolean fast) 00175 { 00176 ProbeState state; 00177 00178 AUDDBG ("Probing %s.\n", filename); 00179 state.plugin = NULL; 00180 state.filename = filename_split_subtune (filename, NULL); 00181 state.handle = NULL; 00182 00183 probe_by_scheme (& state); 00184 00185 if (state.plugin != NULL) 00186 goto DONE; 00187 00188 probe_by_extension (& state); 00189 00190 if (state.plugin != NULL || fast) 00191 goto DONE; 00192 00193 probe_by_mime (& state); 00194 00195 if (state.plugin != NULL) 00196 goto DONE; 00197 00198 probe_by_content (& state); 00199 00200 DONE: 00201 g_free (state.filename); 00202 00203 if (state.handle != NULL) 00204 vfs_fclose (state.handle); 00205 00206 return state.plugin; 00207 } 00208 00209 Tuple * file_read_tuple (const gchar * filename, PluginHandle * decoder) 00210 { 00211 InputPlugin * ip = plugin_get_header (decoder); 00212 g_return_val_if_fail (ip, NULL); 00213 g_return_val_if_fail (ip->probe_for_tuple, NULL); 00214 00215 gchar * real = filename_split_subtune (filename, NULL); 00216 VFSFile * handle = vfs_fopen (real, "r"); 00217 g_free (real); 00218 00219 Tuple * tuple = ip->probe_for_tuple (filename, handle); 00220 00221 if (handle) 00222 vfs_fclose (handle); 00223 00224 return tuple; 00225 } 00226 00227 gboolean file_read_image (const gchar * filename, PluginHandle * decoder, 00228 void * * data, gint * size) 00229 { 00230 if (! input_plugin_has_images (decoder)) 00231 return FALSE; 00232 00233 InputPlugin * ip = plugin_get_header (decoder); 00234 g_return_val_if_fail (ip, FALSE); 00235 g_return_val_if_fail (ip->get_song_image, FALSE); 00236 00237 gchar * real = filename_split_subtune (filename, NULL); 00238 VFSFile * handle = vfs_fopen (real, "r"); 00239 g_free (real); 00240 00241 gboolean success = ip->get_song_image (filename, handle, data, size); 00242 00243 if (handle) 00244 vfs_fclose (handle); 00245 00246 return success; 00247 } 00248 00249 gboolean file_can_write_tuple (const gchar * filename, PluginHandle * decoder) 00250 { 00251 return input_plugin_can_write_tuple (decoder); 00252 } 00253 00254 gboolean file_write_tuple (const gchar * filename, PluginHandle * decoder, 00255 const Tuple * tuple) 00256 { 00257 InputPlugin * ip = plugin_get_header (decoder); 00258 g_return_val_if_fail (ip, FALSE); 00259 g_return_val_if_fail (ip->update_song_tuple, FALSE); 00260 00261 gchar * real = filename_split_subtune (filename, NULL); 00262 VFSFile * handle = vfs_fopen (real, "r+"); 00263 g_free (real); 00264 00265 if (! handle) 00266 return FALSE; 00267 00268 gboolean success = ip->update_song_tuple (tuple, handle); 00269 00270 if (handle) 00271 vfs_fclose (handle); 00272 00273 if (success) 00274 playlist_rescan_file (filename); 00275 00276 return success; 00277 } 00278 00279 gboolean custom_infowin (const gchar * filename, PluginHandle * decoder) 00280 { 00281 if (! input_plugin_has_infowin (decoder)) 00282 return FALSE; 00283 00284 InputPlugin * ip = plugin_get_header (decoder); 00285 g_return_val_if_fail (ip, FALSE); 00286 g_return_val_if_fail (ip->file_info_box, FALSE); 00287 00288 ip->file_info_box (filename); 00289 return TRUE; 00290 }