Audacious  $Id:Doxyfile42802007-03-2104:39:00Znenolod$
probe.c
Go to the documentation of this file.
1 /*
2  * probe.c
3  * Copyright 2009-2010 John Lindgren
4  *
5  * This file is part of Audacious.
6  *
7  * Audacious is free software: you can redistribute it and/or modify it under
8  * the terms of the GNU General Public License as published by the Free Software
9  * Foundation, version 2 or version 3 of the License.
10  *
11  * Audacious is distributed in the hope that it will be useful, but WITHOUT ANY
12  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along with
16  * Audacious. If not, see <http://www.gnu.org/licenses/>.
17  *
18  * The Audacious team does not consider modular code linking to Audacious or
19  * using our public API to be a derived work.
20  */
21 
22 #include <glib.h>
23 #include <stdio.h>
24 #include <string.h>
25 
26 #include <libaudcore/audstrings.h>
27 
28 #include "debug.h"
29 #include "misc.h"
30 #include "playlist.h"
31 #include "plugin.h"
32 #include "plugins.h"
33 #include "probe-buffer.h"
34 
35 typedef struct
36 {
37  const char * filename;
39  bool_t buffered, failed;
41 }
43 
44 static bool_t check_opened (ProbeState * state)
45 {
46  if (state->handle != NULL)
47  return TRUE;
48  if (state->failed)
49  return FALSE;
50 
51  AUDDBG ("Opening %s.\n", state->filename);
52  if ((state->buffered = vfs_is_remote (state->filename)))
53  state->handle = probe_buffer_new (state->filename);
54  else
55  state->handle = vfs_fopen (state->filename, "r");
56 
57  if (state->handle != NULL)
58  return TRUE;
59 
60  AUDDBG ("FAILED.\n");
61  state->failed = TRUE;
62  return FALSE;
63 }
64 
66 {
67  AUDDBG ("Trying %s.\n", plugin_get_name (plugin));
68  InputPlugin * decoder = plugin_get_header (plugin);
69  if (decoder == NULL)
70  return TRUE;
71 
72  if (decoder->is_our_file_from_vfs != NULL)
73  {
74  if (! check_opened (state))
75  return FALSE;
76 
77  if (decoder->is_our_file_from_vfs (state->filename, state->handle))
78  {
79  state->plugin = plugin;
80  return FALSE;
81  }
82 
83  if (vfs_fseek (state->handle, 0, SEEK_SET) < 0)
84  return FALSE;
85  }
86 
87  return TRUE;
88 }
89 
90 /* Optimization: If we have found plugins with a key match, assume that at least
91  * one of them will succeed. This means that we need not check the very last
92  * plugin. (If there is only one, we do not need to check it at all.) This is
93  * implemented as follows:
94  *
95  * 1. On the first call, assume until further notice the plugin passed is the
96  * last one and will therefore succeed.
97  * 2. On a subsequent call, think twice and probe the plugin we assumed would
98  * succeed. If it does in fact succeed, then we are done. If not, assume
99  * similarly that the plugin passed in this call is the last one.
100  */
101 
103 {
104  if (state->plugin != NULL)
105  {
106  PluginHandle * prev = state->plugin;
107  state->plugin = NULL;
108 
109  if (prev != NULL && ! probe_func (prev, state))
110  return FALSE;
111  }
112 
113  AUDDBG ("Guessing %s.\n", plugin_get_name (plugin));
114  state->plugin = plugin;
115  return TRUE;
116 }
117 
118 static void probe_by_scheme (ProbeState * state)
119 {
120  const char * s = strstr (state->filename, "://");
121 
122  if (s == NULL)
123  return;
124 
125  AUDDBG ("Probing by scheme.\n");
126  char buf[s - state->filename + 1];
127  memcpy (buf, state->filename, s - state->filename);
128  buf[s - state->filename] = 0;
129 
130  input_plugin_for_key (INPUT_KEY_SCHEME, buf, (PluginForEachFunc) probe_func_fast, state);
131 }
132 
133 static void probe_by_extension (ProbeState * state)
134 {
135  const char * ext, * sub;
136  uri_parse (state->filename, NULL, & ext, & sub, NULL);
137 
138  if (ext == sub)
139  return;
140 
141  AUDDBG ("Probing by extension.\n");
142  char buf[sub - ext];
143  memcpy (buf, ext + 1, sub - ext - 1);
144  buf[sub - ext - 1] = 0;
145 
146  input_plugin_for_key (INPUT_KEY_EXTENSION, buf, (PluginForEachFunc) probe_func_fast, state);
147 }
148 
149 static void probe_by_mime (ProbeState * state)
150 {
151  char * mime;
152 
153  if (! check_opened (state))
154  return;
155 
156  if ((mime = vfs_get_metadata (state->handle, "content-type")) == NULL)
157  return;
158 
159  AUDDBG ("Probing by MIME type.\n");
160  input_plugin_for_key (INPUT_KEY_MIME, mime, (PluginForEachFunc)
161  probe_func_fast, state);
162  g_free (mime);
163 }
164 
165 static void probe_by_content (ProbeState * state)
166 {
167  AUDDBG ("Probing by content.\n");
169 }
170 
172 {
173  ProbeState state;
174 
175  AUDDBG ("Probing %s.\n", filename);
176  state.plugin = NULL;
177  state.filename = filename;
178  state.handle = NULL;
179  state.failed = FALSE;
180 
181  probe_by_scheme (& state);
182 
183  if (state.plugin != NULL)
184  goto DONE;
185 
186  probe_by_extension (& state);
187 
188  if (state.plugin != NULL || fast)
189  goto DONE;
190 
191  probe_by_mime (& state);
192 
193  if (state.plugin != NULL)
194  goto DONE;
195 
196  probe_by_content (& state);
197 
198 DONE:
199  if (state.handle != NULL)
200  vfs_fclose (state.handle);
201 
202  return state.plugin;
203 }
204 
205 Tuple * file_read_tuple (const char * filename, PluginHandle * decoder)
206 {
207  InputPlugin * ip = plugin_get_header (decoder);
208  g_return_val_if_fail (ip, NULL);
209  g_return_val_if_fail (ip->probe_for_tuple, NULL);
210 
211  VFSFile * handle = vfs_fopen (filename, "r");
212  Tuple * tuple = ip->probe_for_tuple (filename, handle);
213 
214  if (handle)
215  vfs_fclose (handle);
216 
217  return tuple;
218 }
219 
221  void * * data, int64_t * size)
222 {
223  if (! input_plugin_has_images (decoder))
224  return FALSE;
225 
226  InputPlugin * ip = plugin_get_header (decoder);
227  g_return_val_if_fail (ip, FALSE);
228  g_return_val_if_fail (ip->get_song_image, FALSE);
229 
230  VFSFile * handle = vfs_fopen (filename, "r");
231  bool_t success = ip->get_song_image (filename, handle, data, size);
232 
233  if (handle)
234  vfs_fclose (handle);
235 
236  if (! success)
237  {
238  * data = NULL;
239  * size = 0;
240  }
241 
242  return success;
243 }
244 
246 {
247  return input_plugin_can_write_tuple (decoder);
248 }
249 
251  const Tuple * tuple)
252 {
253  InputPlugin * ip = plugin_get_header (decoder);
254  g_return_val_if_fail (ip, FALSE);
255  g_return_val_if_fail (ip->update_song_tuple, FALSE);
256 
257  VFSFile * handle = vfs_fopen (filename, "r+");
258 
259  if (! handle)
260  return FALSE;
261 
262  bool_t success = ip->update_song_tuple (tuple, handle);
263 
264  if (handle)
265  vfs_fclose (handle);
266 
267  if (success)
268  playlist_rescan_file (filename);
269 
270  return success;
271 }
272 
274 {
275  if (! input_plugin_has_infowin (decoder))
276  return FALSE;
277 
278  InputPlugin * ip = plugin_get_header (decoder);
279  g_return_val_if_fail (ip, FALSE);
280  g_return_val_if_fail (ip->file_info_box, FALSE);
281 
282  ip->file_info_box (filename);
283  return TRUE;
284 }