00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
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
00091
00092
00093
00094
00095
00096
00097
00098
00099
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 }