Use ffmpeg as a fallback converter (Closes: #1138).
[ahxm.git] / support.c
blob38937fb52c88d38ef22397037e94d00ce8604c5c
1 /*
3 Ann Hell Ex Machina - Music Software
4 Copyright (C) 2003/2007 Angel Ortega <angel@triptico.com>
6 support.c - Miscellaneous support functions
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 http://www.triptico.com
26 #include "config.h"
28 #include <stdio.h>
29 #include <string.h>
30 #include <stdlib.h>
31 #include <unistd.h>
32 #include <sys/stat.h>
33 #include <sys/types.h>
35 #include "ahxm.h"
36 #include "sha1.h"
38 /*******************
39 Data
40 ********************/
42 static char ** library_path = NULL;
43 static int n_library_paths = 0;
45 static char located_file[2048];
47 /* global verbose flag */
48 int verbose = 1;
50 /* global tracing flag */
51 int trace = 0;
53 /* transparent converters */
54 struct transconv
56 char * from; /* extension from */
57 char * to; /* extension to */
58 char * convcmd; /* sprintf() format for converting command */
61 static struct transconv * transconvs = NULL;
62 static int n_transconvs = 0;
64 /*******************
65 Code
66 ********************/
68 /**
69 * libpath_add - Adds a directory path to the search path
70 * @path: the directory path
71 * @strip: flag to strip the upper level
73 * Adds @path to the list of searchable paths for libpath_fopen(),
74 * optionally stripping the upper level if @strip is set.
75 * The last part of the path is stripped before being stored,
76 * and duplication is avoided.
78 void libpath_add(char * path, int strip)
80 int n;
81 char * ptr;
83 /* if path starts with ~, set it to $HOME */
84 if(*path == '~')
86 char * new;
87 char * home;
89 if((home = getenv("HOME")) == NULL)
90 return;
92 if((new = malloc(strlen(home) + strlen(path) + 2)) == NULL)
93 return;
95 strcpy(new, home);
96 strcat(new, "/");
97 strcat(new, path + 1);
99 path = new;
101 else
103 /* just duplicate */
104 path = strdup(path);
107 /* if no directory path remains, abort */
108 if((ptr = strrchr(path, '/')) == NULL)
110 free(path);
111 return;
114 /* strip the filename part */
115 if(strip) *ptr = '\0';
117 /* now try to find if that path is already stored */
118 for(n = 0;n < n_library_paths;n++)
120 if(strcmp(path, library_path[n]) == 0)
122 /* found; free and return */
123 free(path);
124 return;
128 /* add room for the new path */
129 n_library_paths++;
130 library_path = (char **)realloc(library_path,
131 n_library_paths * sizeof(char *));
133 /* store */
134 library_path[n_library_paths - 1] = path;
139 * libpath_fopen - Opens a file, optionally searching in a path list
140 * @filename: the file name
141 * @mode: the file mode
143 * Opens a file. If the file is found as is, it's opened;
144 * otherwise, the full list of directory paths maintained by
145 * libpath_add() is searched until it's found or the
146 * end of the list is reached. Whenever a file
147 * is successfully opened, its path is also stored.
149 FILE * libpath_fopen(char * filename, char * mode)
151 int n;
152 FILE * f = NULL;
154 /* try first here */
155 if((f = fopen(filename, mode)) != NULL)
157 strncpy(located_file, filename, sizeof(located_file));
158 located_file[sizeof(located_file) - 1] = '\0';
160 libpath_add(filename, 1);
161 return(f);
164 /* couldn't open; try concatenating all stored paths */
165 for(n = n_library_paths - 1;n >= 0;n--)
167 snprintf(located_file, sizeof(located_file), "%s/%s",
168 library_path[n], filename);
169 located_file[sizeof(located_file) - 1] = '\0';
171 if((f = fopen(located_file, mode)) != NULL)
173 libpath_add(located_file, 1);
174 break;
178 return(f);
183 * libpath_locate - Locates a file inside the path
184 * @filename: the file to be located
186 * Locates a file inside the library path maintained by libpath_fopen()
187 * and add_library_path(). If the file is found, a pointer to a static
188 * buffer containing the real path of the file is returned, or
189 * NULL otherwise.
191 char * libpath_locate(char * filename)
193 FILE * f;
195 if((f = libpath_fopen(filename, "r")) == NULL)
196 return(NULL);
198 fclose(f);
199 return(located_file);
203 /** transparent conversions **/
205 void transconv_add(char * from, char * to, char * convcmd)
206 /* adds a converter */
208 struct transconv * t;
210 GROW(transconvs, n_transconvs, struct transconv);
212 t = &transconvs[n_transconvs++];
214 t->from = strdup(from);
215 t->to = strdup(to);
216 t->convcmd = strdup(convcmd);
220 static char * transconv_sha_file(char * file, char * ext)
221 /* builds a unique cache file basename using a SHA1 hash */
223 static char c_file[64];
224 unsigned char sha1[20];
225 SHA_CTX c;
226 int n;
228 SHA1_Init(&c);
229 SHA1_Update(&c, file, strlen(file));
230 SHA1_Update(&c, ext, strlen(ext));
231 SHA1_Final(sha1, &c);
233 for(n = 0;n < sizeof(sha1);n++)
235 char tmp[3];
237 snprintf(tmp, sizeof(tmp), "%02x", sha1[n]);
238 c_file[n * 2] = tmp[0];
239 c_file[(n * 2) + 1] = tmp[1];
242 c_file[n * 2] = '\0';
243 return(c_file);
247 static char * transconv_unique_file(char * file, char * ext, char * dir)
248 /* builds a unique cache file name with complete path */
250 static char tmp[2048];
251 char * c_path = NULL;
253 if((c_path = getenv("TEMP")) == NULL)
254 if((c_path = getenv("TMP")) == NULL)
255 c_path = "/tmp";
257 /* build the directory cache name */
258 snprintf(tmp, sizeof(tmp), "%s/%s-%d", c_path, dir, getuid());
259 tmp[sizeof(tmp) - 1] = '\0';
261 /* create the cache directory */
262 mkdir(tmp, 0755);
264 strcat(tmp, "/");
265 strcat(tmp, transconv_sha_file(file, ext));
266 strcat(tmp, ext);
268 return(tmp);
272 char * transconv_pipe(char * cmd, char * ext, char * dir)
273 /* executes cmd as a pipe */
275 char * c_file = transconv_unique_file(cmd, ext, dir);
277 /* does the file already exist? */
278 if(access(c_file, R_OK))
280 char tmp[2048];
282 snprintf(tmp, sizeof(tmp), cmd, c_file);
283 tmp[sizeof(tmp) - 1] = '\0';
285 if(verbose >= 2)
286 printf("Converting: %s\n", tmp);
288 system(tmp);
291 return(c_file);
295 char * transconv(char * file, char * ext, char * dir)
296 /* converts using the transparent converters and the cache, if needed */
298 char * this_ext;
299 char * c_file;
300 int n;
301 struct transconv * t;
303 /* gets this file extension */
304 if(file == NULL || (this_ext = strrchr(file, '.')) == NULL)
305 return(NULL);
307 /* if it's already the desired type, do nothing */
308 if(strcmp(ext, this_ext) == 0)
309 return(file);
311 /* get a unique name */
312 c_file = transconv_unique_file(file, ext, dir);
314 /* does the file already exist? */
315 if(access(c_file, R_OK) == 0)
316 return(c_file);
318 /* no; look for a suitable converter */
319 for(n = 0, t = transconvs;n < n_transconvs;n++, t++)
321 if(strcmp(ext, t->to) == 0 && strcmp(this_ext, t->from) == 0)
323 char tmp[2048];
325 /* found a converter! just do it */
326 snprintf(tmp, sizeof(tmp), t->convcmd, c_file, file);
327 tmp[sizeof(tmp) - 1] = '\0';
329 if(verbose >= 2)
330 printf("Executing: %s\n", tmp);
332 if (system(tmp) == 0)
333 break;
334 else
335 unlink(c_file);
339 return(c_file);