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  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions, and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions, and the following disclaimer in the documentation
13  * provided with the distribution.
14  *
15  * This software is provided "as is" and without any warranty, express or
16  * implied. In no event shall the authors be liable for any damages arising from
17  * the use of this software.
18  */
19 
20 #include <glib.h>
21 #include <stdio.h>
22 #include <string.h>
23 
24 #include <libaudcore/audstrings.h>
25 
26 #include "debug.h"
27 #include "misc.h"
28 #include "playlist.h"
29 #include "plugin.h"
30 #include "plugins.h"
31 #include "probe-buffer.h"
32 
33 typedef struct
34 {
35  const char * filename;
37  bool_t buffered, failed;
39 }
41 
42 static bool_t check_opened (ProbeState * state)
43 {
44  if (state->handle != NULL)
45  return TRUE;
46  if (state->failed)
47  return FALSE;
48 
49  AUDDBG ("Opening %s.\n", state->filename);
50  if ((state->buffered = vfs_is_remote (state->filename)))
51  state->handle = probe_buffer_new (state->filename);
52  else
53  state->handle = vfs_fopen (state->filename, "r");
54 
55  if (state->handle != NULL)
56  return TRUE;
57 
58  AUDDBG ("FAILED.\n");
59  state->failed = TRUE;
60  return FALSE;
61 }
62 
64 {
65  AUDDBG ("Trying %s.\n", plugin_get_name (plugin));
66  InputPlugin * decoder = plugin_get_header (plugin);
67  if (decoder == NULL)
68  return TRUE;
69 
70  if (decoder->is_our_file_from_vfs != NULL)
71  {
72  if (! check_opened (state))
73  return FALSE;
74 
75  if (decoder->is_our_file_from_vfs (state->filename, state->handle))
76  {
77  state->plugin = plugin;
78  return FALSE;
79  }
80 
81  if (vfs_fseek (state->handle, 0, SEEK_SET) < 0)
82  return FALSE;
83  }
84 
85  return TRUE;
86 }
87 
88 /* Optimization: If we have found plugins with a key match, assume that at least
89  * one of them will succeed. This means that we need not check the very last
90  * plugin. (If there is only one, we do not need to check it at all.) This is
91  * implemented as follows:
92  *
93  * 1. On the first call, assume until further notice the plugin passed is the
94  * last one and will therefore succeed.
95  * 2. On a subsequent call, think twice and probe the plugin we assumed would
96  * succeed. If it does in fact succeed, then we are done. If not, assume
97  * similarly that the plugin passed in this call is the last one.
98  */
99 
101 {
102  if (state->plugin != NULL)
103  {
104  PluginHandle * prev = state->plugin;
105  state->plugin = NULL;
106 
107  if (prev != NULL && ! probe_func (prev, state))
108  return FALSE;
109  }
110 
111  AUDDBG ("Guessing %s.\n", plugin_get_name (plugin));
112  state->plugin = plugin;
113  return TRUE;
114 }
115 
116 static void probe_by_scheme (ProbeState * state)
117 {
118  const char * s = strstr (state->filename, "://");
119 
120  if (s == NULL)
121  return;
122 
123  AUDDBG ("Probing by scheme.\n");
124  char buf[s - state->filename + 1];
125  memcpy (buf, state->filename, s - state->filename);
126  buf[s - state->filename] = 0;
127 
128  input_plugin_for_key (INPUT_KEY_SCHEME, buf, (PluginForEachFunc) probe_func_fast, state);
129 }
130 
131 static void probe_by_extension (ProbeState * state)
132 {
133  char buf[32];
134  if (! uri_get_extension (state->filename, buf, sizeof buf))
135  return;
136 
137  AUDDBG ("Probing by extension.\n");
138  input_plugin_for_key (INPUT_KEY_EXTENSION, buf, (PluginForEachFunc) probe_func_fast, state);
139 }
140 
141 static void probe_by_mime (ProbeState * state)
142 {
143  char * mime;
144 
145  if (! check_opened (state))
146  return;
147 
148  if ((mime = vfs_get_metadata (state->handle, "content-type")) == NULL)
149  return;
150 
151  AUDDBG ("Probing by MIME type.\n");
152  input_plugin_for_key (INPUT_KEY_MIME, mime, (PluginForEachFunc)
153  probe_func_fast, state);
154  g_free (mime);
155 }
156 
157 static void probe_by_content (ProbeState * state)
158 {
159  AUDDBG ("Probing by content.\n");
161 }
162 
164 {
165  ProbeState state;
166 
167  AUDDBG ("Probing %s.\n", filename);
168  state.plugin = NULL;
169  state.filename = filename;
170  state.handle = NULL;
171  state.failed = FALSE;
172 
173  probe_by_scheme (& state);
174 
175  if (state.plugin != NULL)
176  goto DONE;
177 
178  probe_by_extension (& state);
179 
180  if (state.plugin != NULL || fast)
181  goto DONE;
182 
183  probe_by_mime (& state);
184 
185  if (state.plugin != NULL)
186  goto DONE;
187 
188  probe_by_content (& state);
189 
190 DONE:
191  if (state.handle != NULL)
192  vfs_fclose (state.handle);
193 
194  return state.plugin;
195 }
196 
197 Tuple * file_read_tuple (const char * filename, PluginHandle * decoder)
198 {
199  InputPlugin * ip = plugin_get_header (decoder);
200  g_return_val_if_fail (ip, NULL);
201  g_return_val_if_fail (ip->probe_for_tuple, NULL);
202 
203  VFSFile * handle = vfs_fopen (filename, "r");
204  Tuple * tuple = ip->probe_for_tuple (filename, handle);
205 
206  if (handle)
207  vfs_fclose (handle);
208 
209  return tuple;
210 }
211 
212 bool_t file_read_image (const char * filename, PluginHandle * decoder,
213  void * * data, int64_t * size)
214 {
215  if (! input_plugin_has_images (decoder))
216  return FALSE;
217 
218  InputPlugin * ip = plugin_get_header (decoder);
219  g_return_val_if_fail (ip, FALSE);
220  g_return_val_if_fail (ip->get_song_image, FALSE);
221 
222  VFSFile * handle = vfs_fopen (filename, "r");
223  bool_t success = ip->get_song_image (filename, handle, data, size);
224 
225  if (handle)
226  vfs_fclose (handle);
227 
228  if (! success)
229  {
230  * data = NULL;
231  * size = 0;
232  }
233 
234  return success;
235 }
236 
238 {
239  return input_plugin_can_write_tuple (decoder);
240 }
241 
242 bool_t file_write_tuple (const char * filename, PluginHandle * decoder,
243  const Tuple * tuple)
244 {
245  InputPlugin * ip = plugin_get_header (decoder);
246  g_return_val_if_fail (ip, FALSE);
247  g_return_val_if_fail (ip->update_song_tuple, FALSE);
248 
249  VFSFile * handle = vfs_fopen (filename, "r+");
250 
251  if (! handle)
252  return FALSE;
253 
254  bool_t success = ip->update_song_tuple (tuple, handle);
255 
256  if (handle)
257  vfs_fclose (handle);
258 
259  if (success)
260  playlist_rescan_file (filename);
261 
262  return success;
263 }
264 
265 bool_t custom_infowin (const char * filename, PluginHandle * decoder)
266 {
267  if (! input_plugin_has_infowin (decoder))
268  return FALSE;
269 
270  InputPlugin * ip = plugin_get_header (decoder);
271  g_return_val_if_fail (ip, FALSE);
272  g_return_val_if_fail (ip->file_info_box, FALSE);
273 
274  ip->file_info_box (filename);
275  return TRUE;
276 }