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 else if (decoder->is_our_file != NULL) 00086 { 00087 if (decoder->is_our_file (state->filename)) 00088 { 00089 state->plugin = plugin; 00090 return FALSE; 00091 } 00092 } 00093 00094 return TRUE; 00095 } 00096 00097 /* Optimization: If we have found plugins with a key match, assume that at least 00098 * one of them will succeed. This means that we need not check the very last 00099 * plugin. (If there is only one, we do not need to check it at all.) This is 00100 * implemented as follows: 00101 * 00102 * 1. On the first call, assume until further notice the plugin passed is the 00103 * last one and will therefore succeed. 00104 * 2. On a subsequent call, think twice and probe the plugin we assumed would 00105 * succeed. If it does in fact succeed, then we are done. If not, assume 00106 * similarly that the plugin passed in this call is the last one. 00107 */ 00108 00109 static gboolean probe_func_fast (PluginHandle * plugin, ProbeState * state) 00110 { 00111 if (state->plugin != NULL) 00112 { 00113 PluginHandle * prev = state->plugin; 00114 state->plugin = NULL; 00115 00116 if (prev != NULL && ! probe_func (prev, state)) 00117 return FALSE; 00118 } 00119 00120 AUDDBG ("Guessing %s.\n", plugin_get_name (plugin)); 00121 state->plugin = plugin; 00122 return TRUE; 00123 } 00124 00125 static void probe_by_scheme (ProbeState * state) 00126 { 00127 gchar * s = strstr (state->filename, "://"); 00128 gchar c; 00129 00130 if (s == NULL) 00131 return; 00132 00133 AUDDBG ("Probing by scheme.\n"); 00134 c = s[3]; 00135 s[3] = 0; 00136 input_plugin_for_key (INPUT_KEY_SCHEME, state->filename, (PluginForEachFunc) 00137 probe_func_fast, state); 00138 s[3] = c; 00139 } 00140 00141 static void probe_by_extension (ProbeState * state) 00142 { 00143 gchar * s = strrchr (state->filename, '.'); 00144 00145 if (s == NULL) 00146 return; 00147 00148 AUDDBG ("Probing by extension.\n"); 00149 s = g_ascii_strdown (s + 1, -1); 00150 00151 gchar * q = strrchr (s, '?'); 00152 if (q != NULL) 00153 * q = 0; 00154 00155 input_plugin_for_key (INPUT_KEY_EXTENSION, s, (PluginForEachFunc) 00156 probe_func_fast, state); 00157 g_free (s); 00158 } 00159 00160 static void probe_by_mime (ProbeState * state) 00161 { 00162 gchar * mime; 00163 00164 if (! check_opened (state)) 00165 return; 00166 00167 if ((mime = vfs_get_metadata (state->handle, "content-type")) == NULL) 00168 return; 00169 00170 AUDDBG ("Probing by MIME type.\n"); 00171 input_plugin_for_key (INPUT_KEY_MIME, mime, (PluginForEachFunc) 00172 probe_func_fast, state); 00173 g_free (mime); 00174 } 00175 00176 static void probe_by_content (ProbeState * state) 00177 { 00178 AUDDBG ("Probing by content.\n"); 00179 plugin_for_enabled (PLUGIN_TYPE_INPUT, (PluginForEachFunc) probe_func, state); 00180 } 00181 00182 InputPlugin * file_find_decoder (const gchar * filename, gboolean fast) 00183 { 00184 ProbeState state; 00185 00186 AUDDBG ("Probing %s.\n", filename); 00187 state.plugin = NULL; 00188 state.filename = filename_split_subtune (filename, NULL); 00189 state.handle = NULL; 00190 00191 probe_by_scheme (& state); 00192 00193 if (state.plugin != NULL) 00194 goto DONE; 00195 00196 probe_by_extension (& state); 00197 00198 if (state.plugin != NULL || fast) 00199 goto DONE; 00200 00201 probe_by_mime (& state); 00202 00203 if (state.plugin != NULL) 00204 goto DONE; 00205 00206 probe_by_content (& state); 00207 00208 DONE: 00209 g_free (state.filename); 00210 00211 if (state.handle != NULL) 00212 vfs_fclose (state.handle); 00213 00214 return (state.plugin != NULL) ? plugin_get_header (state.plugin) : NULL; 00215 } 00216 00217 Tuple * file_read_tuple (const gchar * filename, InputPlugin * decoder) 00218 { 00219 if (decoder->get_song_tuple != NULL) 00220 return decoder->get_song_tuple (filename); 00221 00222 if (decoder->probe_for_tuple != NULL) 00223 { 00224 VFSFile * handle = vfs_fopen (filename, "r"); 00225 Tuple * tuple; 00226 00227 if (handle == NULL) 00228 return NULL; 00229 00230 tuple = decoder->probe_for_tuple (filename, handle); 00231 vfs_fclose (handle); 00232 return tuple; 00233 } 00234 00235 return NULL; 00236 } 00237 00238 gboolean file_read_image (const gchar * filename, InputPlugin * decoder, 00239 void * * data, gint * size) 00240 { 00241 VFSFile * handle; 00242 gboolean success; 00243 00244 if (decoder->get_song_image == NULL) 00245 return FALSE; 00246 00247 handle = vfs_fopen (filename, "r"); 00248 success = decoder->get_song_image (filename, handle, data, size); 00249 00250 if (handle != NULL) 00251 vfs_fclose (handle); 00252 00253 return success; 00254 } 00255 00256 gboolean file_can_write_tuple (const gchar * filename, InputPlugin * decoder) 00257 { 00258 return (decoder->update_song_tuple != NULL); 00259 } 00260 00261 gboolean file_write_tuple (const gchar * filename, InputPlugin * decoder, 00262 const Tuple * tuple) 00263 { 00264 VFSFile * handle; 00265 gboolean success; 00266 00267 if (decoder->update_song_tuple == NULL) 00268 return FALSE; 00269 00270 handle = vfs_fopen (filename, "r+"); 00271 00272 if (handle == NULL) 00273 return FALSE; 00274 00275 success = decoder->update_song_tuple (tuple, handle); 00276 vfs_fclose (handle); 00277 00278 if (success) 00279 playlist_rescan_file (filename); 00280 00281 return success; 00282 } 00283 00284 gboolean custom_infowin (const gchar * filename, InputPlugin * decoder) 00285 { 00286 if (decoder->file_info_box == NULL) 00287 return FALSE; 00288 00289 decoder->file_info_box (filename); 00290 return TRUE; 00291 }