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;
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  state->handle = probe_buffer_new (state->filename);
51 
52  if (state->handle != NULL)
53  return TRUE;
54 
55  AUDDBG ("FAILED.\n");
56  state->failed = TRUE;
57  return FALSE;
58 }
59 
61 {
62  AUDDBG ("Trying %s.\n", plugin_get_name (plugin));
63  InputPlugin * decoder = plugin_get_header (plugin);
64  if (decoder == NULL)
65  return TRUE;
66 
67  if (decoder->is_our_file_from_vfs != NULL)
68  {
69  if (! check_opened (state))
70  return FALSE;
71 
72  if (decoder->is_our_file_from_vfs (state->filename, state->handle))
73  {
74  state->plugin = plugin;
75  return FALSE;
76  }
77 
78  if (vfs_fseek (state->handle, 0, SEEK_SET) < 0)
79  return FALSE;
80  }
81 
82  return TRUE;
83 }
84 
85 /* Optimization: If we have found plugins with a key match, assume that at least
86  * one of them will succeed. This means that we need not check the very last
87  * plugin. (If there is only one, we do not need to check it at all.) This is
88  * implemented as follows:
89  *
90  * 1. On the first call, assume until further notice the plugin passed is the
91  * last one and will therefore succeed.
92  * 2. On a subsequent call, think twice and probe the plugin we assumed would
93  * succeed. If it does in fact succeed, then we are done. If not, assume
94  * similarly that the plugin passed in this call is the last one.
95  */
96 
98 {
99  if (state->plugin != NULL)
100  {
101  PluginHandle * prev = state->plugin;
102  state->plugin = NULL;
103 
104  if (prev != NULL && ! probe_func (prev, state))
105  return FALSE;
106  }
107 
108  AUDDBG ("Guessing %s.\n", plugin_get_name (plugin));
109  state->plugin = plugin;
110  return TRUE;
111 }
112 
113 static void probe_by_scheme (ProbeState * state)
114 {
115  const char * s = strstr (state->filename, "://");
116 
117  if (s == NULL)
118  return;
119 
120  AUDDBG ("Probing by scheme.\n");
121  char buf[s - state->filename + 1];
122  memcpy (buf, state->filename, s - state->filename);
123  buf[s - state->filename] = 0;
124 
125  input_plugin_for_key (INPUT_KEY_SCHEME, buf, (PluginForEachFunc) probe_func_fast, state);
126 }
127 
128 static void probe_by_extension (ProbeState * state)
129 {
130  char buf[32];
131  if (! uri_get_extension (state->filename, buf, sizeof buf))
132  return;
133 
134  AUDDBG ("Probing by extension.\n");
135  input_plugin_for_key (INPUT_KEY_EXTENSION, buf, (PluginForEachFunc) probe_func_fast, state);
136 }
137 
138 static void probe_by_mime (ProbeState * state)
139 {
140  char * mime;
141 
142  if (! check_opened (state))
143  return;
144 
145  if ((mime = vfs_get_metadata (state->handle, "content-type")) == NULL)
146  return;
147 
148  AUDDBG ("Probing by MIME type.\n");
149  input_plugin_for_key (INPUT_KEY_MIME, mime, (PluginForEachFunc)
150  probe_func_fast, state);
151  g_free (mime);
152 }
153 
154 static void probe_by_content (ProbeState * state)
155 {
156  AUDDBG ("Probing by content.\n");
158 }
159 
161 {
162  ProbeState state;
163 
164  AUDDBG ("Probing %s.\n", filename);
165  state.plugin = NULL;
166  state.filename = filename;
167  state.handle = NULL;
168  state.failed = FALSE;
169 
170  probe_by_scheme (& state);
171 
172  if (state.plugin != NULL)
173  goto DONE;
174 
175  probe_by_extension (& state);
176 
177  if (state.plugin != NULL || fast)
178  goto DONE;
179 
180  probe_by_mime (& state);
181 
182  if (state.plugin != NULL)
183  goto DONE;
184 
185  probe_by_content (& state);
186 
187 DONE:
188  if (state.handle != NULL)
189  vfs_fclose (state.handle);
190 
191  return state.plugin;
192 }
193 
194 Tuple * file_read_tuple (const char * filename, PluginHandle * decoder)
195 {
196  InputPlugin * ip = plugin_get_header (decoder);
197  g_return_val_if_fail (ip, NULL);
198  g_return_val_if_fail (ip->probe_for_tuple, NULL);
199 
200  VFSFile * handle = vfs_fopen (filename, "r");
201  Tuple * tuple = ip->probe_for_tuple (filename, handle);
202 
203  if (handle)
204  vfs_fclose (handle);
205 
206  return tuple;
207 }
208 
209 bool_t file_read_image (const char * filename, PluginHandle * decoder,
210  void * * data, int64_t * size)
211 {
212  if (! input_plugin_has_images (decoder))
213  return FALSE;
214 
215  InputPlugin * ip = plugin_get_header (decoder);
216  g_return_val_if_fail (ip, FALSE);
217  g_return_val_if_fail (ip->get_song_image, FALSE);
218 
219  VFSFile * handle = vfs_fopen (filename, "r");
220  bool_t success = ip->get_song_image (filename, handle, data, size);
221 
222  if (handle)
223  vfs_fclose (handle);
224 
225  if (! success)
226  {
227  * data = NULL;
228  * size = 0;
229  }
230 
231  return success;
232 }
233 
235 {
236  return input_plugin_can_write_tuple (decoder);
237 }
238 
239 bool_t file_write_tuple (const char * filename, PluginHandle * decoder,
240  const Tuple * tuple)
241 {
242  InputPlugin * ip = plugin_get_header (decoder);
243  g_return_val_if_fail (ip, FALSE);
244  g_return_val_if_fail (ip->update_song_tuple, FALSE);
245 
246  VFSFile * handle = vfs_fopen (filename, "r+");
247 
248  if (! handle)
249  return FALSE;
250 
251  bool_t success = ip->update_song_tuple (tuple, handle);
252 
253  if (handle)
254  vfs_fclose (handle);
255 
256  if (success)
257  playlist_rescan_file (filename);
258 
259  return success;
260 }
261 
262 bool_t custom_infowin (const char * filename, PluginHandle * decoder)
263 {
264  if (! input_plugin_has_infowin (decoder))
265  return FALSE;
266 
267  InputPlugin * ip = plugin_get_header (decoder);
268  g_return_val_if_fail (ip, FALSE);
269  g_return_val_if_fail (ip->file_info_box, FALSE);
270 
271  ip->file_info_box (filename);
272  return TRUE;
273 }