00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
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
00098
00099
00100
00101
00102
00103
00104
00105
00106
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 }