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 <glib.h> 00023 #include <stdio.h> 00024 #include <string.h> 00025 00026 #include <libaudcore/audstrings.h> 00027 00028 #include "debug.h" 00029 #include "misc.h" 00030 #include "playlist.h" 00031 #include "plugin.h" 00032 #include "plugins.h" 00033 #include "probe-buffer.h" 00034 00035 typedef struct 00036 { 00037 const char * filename; 00038 VFSFile * handle; 00039 bool_t buffered, failed; 00040 PluginHandle * plugin; 00041 } 00042 ProbeState; 00043 00044 static bool_t check_opened (ProbeState * state) 00045 { 00046 if (state->handle != NULL) 00047 return TRUE; 00048 if (state->failed) 00049 return FALSE; 00050 00051 AUDDBG ("Opening %s.\n", state->filename); 00052 if ((state->buffered = vfs_is_remote (state->filename))) 00053 state->handle = probe_buffer_new (state->filename); 00054 else 00055 state->handle = vfs_fopen (state->filename, "r"); 00056 00057 if (state->handle != NULL) 00058 return TRUE; 00059 00060 AUDDBG ("FAILED.\n"); 00061 state->failed = TRUE; 00062 return FALSE; 00063 } 00064 00065 static bool_t probe_func (PluginHandle * plugin, ProbeState * state) 00066 { 00067 AUDDBG ("Trying %s.\n", plugin_get_name (plugin)); 00068 InputPlugin * decoder = plugin_get_header (plugin); 00069 if (decoder == NULL) 00070 return TRUE; 00071 00072 if (decoder->is_our_file_from_vfs != NULL) 00073 { 00074 if (! check_opened (state)) 00075 return FALSE; 00076 00077 if (decoder->is_our_file_from_vfs (state->filename, state->handle)) 00078 { 00079 state->plugin = plugin; 00080 return FALSE; 00081 } 00082 00083 if (vfs_fseek (state->handle, 0, SEEK_SET) < 0) 00084 return FALSE; 00085 } 00086 00087 return TRUE; 00088 } 00089 00090 /* Optimization: If we have found plugins with a key match, assume that at least 00091 * one of them will succeed. This means that we need not check the very last 00092 * plugin. (If there is only one, we do not need to check it at all.) This is 00093 * implemented as follows: 00094 * 00095 * 1. On the first call, assume until further notice the plugin passed is the 00096 * last one and will therefore succeed. 00097 * 2. On a subsequent call, think twice and probe the plugin we assumed would 00098 * succeed. If it does in fact succeed, then we are done. If not, assume 00099 * similarly that the plugin passed in this call is the last one. 00100 */ 00101 00102 static bool_t probe_func_fast (PluginHandle * plugin, ProbeState * state) 00103 { 00104 if (state->plugin != NULL) 00105 { 00106 PluginHandle * prev = state->plugin; 00107 state->plugin = NULL; 00108 00109 if (prev != NULL && ! probe_func (prev, state)) 00110 return FALSE; 00111 } 00112 00113 AUDDBG ("Guessing %s.\n", plugin_get_name (plugin)); 00114 state->plugin = plugin; 00115 return TRUE; 00116 } 00117 00118 static void probe_by_scheme (ProbeState * state) 00119 { 00120 const char * s = strstr (state->filename, "://"); 00121 00122 if (s == NULL) 00123 return; 00124 00125 AUDDBG ("Probing by scheme.\n"); 00126 char buf[s - state->filename + 1]; 00127 memcpy (buf, state->filename, s - state->filename); 00128 buf[s - state->filename] = 0; 00129 00130 input_plugin_for_key (INPUT_KEY_SCHEME, buf, (PluginForEachFunc) probe_func_fast, state); 00131 } 00132 00133 static void probe_by_extension (ProbeState * state) 00134 { 00135 const char * ext, * sub; 00136 uri_parse (state->filename, NULL, & ext, & sub, NULL); 00137 00138 if (ext == sub) 00139 return; 00140 00141 AUDDBG ("Probing by extension.\n"); 00142 char buf[sub - ext]; 00143 memcpy (buf, ext + 1, sub - ext - 1); 00144 buf[sub - ext - 1] = 0; 00145 00146 input_plugin_for_key (INPUT_KEY_EXTENSION, buf, (PluginForEachFunc) probe_func_fast, state); 00147 } 00148 00149 static void probe_by_mime (ProbeState * state) 00150 { 00151 char * mime; 00152 00153 if (! check_opened (state)) 00154 return; 00155 00156 if ((mime = vfs_get_metadata (state->handle, "content-type")) == NULL) 00157 return; 00158 00159 AUDDBG ("Probing by MIME type.\n"); 00160 input_plugin_for_key (INPUT_KEY_MIME, mime, (PluginForEachFunc) 00161 probe_func_fast, state); 00162 g_free (mime); 00163 } 00164 00165 static void probe_by_content (ProbeState * state) 00166 { 00167 AUDDBG ("Probing by content.\n"); 00168 plugin_for_enabled (PLUGIN_TYPE_INPUT, (PluginForEachFunc) probe_func, state); 00169 } 00170 00171 PluginHandle * file_find_decoder (const char * filename, bool_t fast) 00172 { 00173 ProbeState state; 00174 00175 AUDDBG ("Probing %s.\n", filename); 00176 state.plugin = NULL; 00177 state.filename = filename; 00178 state.handle = NULL; 00179 state.failed = FALSE; 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 if (state.handle != NULL) 00200 vfs_fclose (state.handle); 00201 00202 return state.plugin; 00203 } 00204 00205 Tuple * file_read_tuple (const char * filename, PluginHandle * decoder) 00206 { 00207 InputPlugin * ip = plugin_get_header (decoder); 00208 g_return_val_if_fail (ip, NULL); 00209 g_return_val_if_fail (ip->probe_for_tuple, NULL); 00210 00211 VFSFile * handle = vfs_fopen (filename, "r"); 00212 Tuple * tuple = ip->probe_for_tuple (filename, handle); 00213 00214 if (handle) 00215 vfs_fclose (handle); 00216 00217 return tuple; 00218 } 00219 00220 bool_t file_read_image (const char * filename, PluginHandle * decoder, 00221 void * * data, int64_t * size) 00222 { 00223 if (! input_plugin_has_images (decoder)) 00224 return FALSE; 00225 00226 InputPlugin * ip = plugin_get_header (decoder); 00227 g_return_val_if_fail (ip, FALSE); 00228 g_return_val_if_fail (ip->get_song_image, FALSE); 00229 00230 VFSFile * handle = vfs_fopen (filename, "r"); 00231 bool_t success = ip->get_song_image (filename, handle, data, size); 00232 00233 if (handle) 00234 vfs_fclose (handle); 00235 00236 if (! success) 00237 { 00238 * data = NULL; 00239 * size = 0; 00240 } 00241 00242 return success; 00243 } 00244 00245 bool_t file_can_write_tuple (const char * filename, PluginHandle * decoder) 00246 { 00247 return input_plugin_can_write_tuple (decoder); 00248 } 00249 00250 bool_t file_write_tuple (const char * filename, PluginHandle * decoder, 00251 const Tuple * tuple) 00252 { 00253 InputPlugin * ip = plugin_get_header (decoder); 00254 g_return_val_if_fail (ip, FALSE); 00255 g_return_val_if_fail (ip->update_song_tuple, FALSE); 00256 00257 VFSFile * handle = vfs_fopen (filename, "r+"); 00258 00259 if (! handle) 00260 return FALSE; 00261 00262 bool_t success = ip->update_song_tuple (tuple, handle); 00263 00264 if (handle) 00265 vfs_fclose (handle); 00266 00267 if (success) 00268 playlist_rescan_file (filename); 00269 00270 return success; 00271 } 00272 00273 bool_t custom_infowin (const char * filename, PluginHandle * decoder) 00274 { 00275 if (! input_plugin_has_infowin (decoder)) 00276 return FALSE; 00277 00278 InputPlugin * ip = plugin_get_header (decoder); 00279 g_return_val_if_fail (ip, FALSE); 00280 g_return_val_if_fail (ip->file_info_box, FALSE); 00281 00282 ip->file_info_box (filename); 00283 return TRUE; 00284 }