Minor tweaks to compile on win32.
[kugel-rb.git] / apps / filetypes.c
blob09090c30d4b1381033a125b7e257a3ddba3123e0
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
8 * $Id$
10 * Copyright (C) 2004 Henrik Backe
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
20 #include <stdio.h>
21 #include <string.h>
22 #include <stdlib.h>
23 #include <stdbool.h>
25 #include "sprintf.h"
26 #include "settings.h"
27 #include "debug.h"
28 #include "lang.h"
29 #include "language.h"
30 #include "kernel.h"
31 #include "plugin.h"
32 #include "filetypes.h"
33 #include "screens.h"
34 #include "icons.h"
35 #include "dir.h"
36 #include "file.h"
37 #include "icons.h"
39 /* max plugin name size without extensions and path */
40 #define MAX_PLUGIN_LENGTH 32
42 /* max filetypes (plugins & icons stored here) */
43 #define MAX_FILETYPES 32
45 /* max exttypes (extensions stored here) */
46 #define MAX_EXTTYPES 32
48 /* string buffer length */
49 #define STRING_BUFFER_SIZE 256
51 /* number of bytes for the binary icon */
52 #define ICON_LENGTH 6
54 /* mask for dynamic filetype info in attribute */
55 #define FILETYPES_MASK 0xFF00
57 /* filenames */
58 #define ROCK_EXTENSION ".rock"
59 #define VIEWERS_CONFIG ROCKBOX_DIR "/viewers.config"
60 #define VIEWERS_DIR ROCKBOX_DIR "/viewers"
62 /* global variables */
63 static int cnt_filetypes;
64 static int cnt_exttypes;
65 static struct ext_type exttypes [MAX_EXTTYPES];
66 static struct file_type filetypes[MAX_FILETYPES];
67 static int first_soft_exttype;
68 static int first_soft_filetype;
69 static char* next_free_string;
70 static char plugin_name[sizeof(VIEWERS_DIR) + 7 + MAX_PLUGIN_LENGTH];
71 static char string_buffer[STRING_BUFFER_SIZE];
73 /* prototypes */
74 #ifdef HAVE_LCD_BITMAP
75 static char* string2icon(const char*);
76 #endif
77 static char* get_string(const char*);
78 static int find_attr_index(int);
79 static bool read_config(const char*);
80 static void rm_whitespaces(char*);
81 static void scan_plugins(void);
83 /* initialize dynamic filetypes (called at boot from tree.c) */
84 void filetype_init(void)
86 int cnt,i,ix;
87 const struct filetype* ftypes;
89 memset(exttypes,0,sizeof(exttypes));
90 memset(filetypes,0,sizeof(filetypes));
91 next_free_string=string_buffer;
93 /* The special filetype folder must always be stored at index 0 */
94 #ifdef HAVE_LCD_BITMAP
95 if (!filetypes[0].icon)
96 filetypes[0].icon = bitmap_icons_6x8[Folder];
97 #else
98 if (!filetypes[0].icon)
99 filetypes[0].icon = Folder;
100 for (i=1; i < MAX_FILETYPES; i++)
101 filetypes[i].icon = -1;
102 #endif
104 /* register hardcoded filetypes */
105 tree_get_filetypes(&ftypes, &cnt);
106 cnt_exttypes=0;
107 cnt_filetypes=0;
109 for (i = 0; i < cnt ; i++)
111 ix = ((ftypes[i].tree_attr & FILETYPES_MASK) >> 8);
112 if (ix < MAX_FILETYPES && i < MAX_EXTTYPES)
114 #ifdef HAVE_LCD_BITMAP
115 if (filetypes[ix].icon == NULL)
116 filetypes[ix].icon=bitmap_icons_6x8[ftypes[i].icon];
117 #else
118 if (filetypes[ix].icon == -1)
119 filetypes[ix].icon=ftypes[i].icon;
120 #endif
121 if (ix > cnt_filetypes)
122 cnt_filetypes=ix;
123 exttypes[cnt_exttypes].type=&filetypes[ix];
124 exttypes[cnt_exttypes].extension=ftypes[i].extension;
125 cnt_exttypes++;
128 first_soft_exttype=cnt_exttypes;
129 cnt_filetypes++;
130 first_soft_filetype=cnt_filetypes;
132 /* register dynamic filetypes */
133 read_config(VIEWERS_CONFIG);
134 scan_plugins();
137 /* get icon */
138 #ifdef HAVE_LCD_BITMAP
139 const char* filetype_get_icon(int attr)
140 #else
141 int filetype_get_icon(int attr)
142 #endif
144 int ix;
146 ix = find_attr_index(attr);
148 if (ix < 0)
150 #ifdef HAVE_LCD_BITMAP
151 return NULL;
152 #else
153 return -1;
154 #endif
156 else
158 return filetypes[ix].icon;
162 /* get plugin */
163 char* filetype_get_plugin(const struct entry* file)
165 int ix;
167 ix=find_attr_index(file->attr);
169 if (ix < 0)
171 return NULL;
174 if ((filetypes[ix].plugin == NULL) ||
175 (strlen(filetypes[ix].plugin) > MAX_PLUGIN_LENGTH))
176 return NULL;
178 snprintf(plugin_name, sizeof(plugin_name),
179 VIEWERS_DIR "/%s.rock",filetypes[ix].plugin);
181 return plugin_name;
184 /* check if filetype is supported */
185 bool filetype_supported(int attr)
187 int ix;
189 ix=find_attr_index(attr);
191 /* hard filetypes and soft filetypes with plugins is supported */
192 if (ix > 0)
193 if (filetypes[ix].plugin || ix < first_soft_filetype)
194 return true;
196 return false;
199 /* get the "dynamic" attribute for an extension */
200 int filetype_get_attr(const char* name)
202 int i;
204 for (i=0; i < cnt_exttypes; i++)
206 if (exttypes[i].extension)
208 if (!strcasecmp(&name[strlen(name)-
209 strlen(exttypes[i].extension)],
210 exttypes[i].extension))
212 return ((((unsigned int)exttypes[i].type -
213 (unsigned int)&filetypes[0]) /
214 sizeof(struct file_type)) << 8);
219 return 0;
222 /* fill a menu list with viewers (used in onplay.c) */
223 int filetype_load_menu(struct menu_item* menu,int max_items)
225 int i;
226 int cnt=0;
228 for (i=0; i < cnt_filetypes; i++)
230 if (filetypes[i].plugin)
232 menu[cnt].desc = filetypes[i].plugin;
233 cnt++;
234 if (cnt == max_items)
235 break;
238 return cnt;
241 /* start a plugin with an argument (called from onplay.c) */
242 int filetype_load_plugin(const char* plugin, char* file)
244 snprintf(plugin_name,sizeof(plugin_name),"%s/%s.rock",
245 VIEWERS_DIR,plugin);
246 return plugin_load(plugin_name,file);
249 /* get index to filetypes[] from the file attribute */
250 static int find_attr_index(int attr)
252 int ix;
253 ix = ((attr & FILETYPES_MASK) >> 8);
255 if ((attr & ATTR_DIRECTORY)==ATTR_DIRECTORY)
257 ix=0;
259 else
261 if (ix==0)
262 ix=-1;
263 if (ix > cnt_filetypes)
264 ix=-1;
265 else
266 if ((filetypes[ix].plugin == NULL) &&
267 #ifdef HAVE_LCD_BITMAP
268 (filetypes[ix].icon == NULL)
269 #else
270 (filetypes[ix].icon == -1)
271 #endif
273 ix=-1;
276 return ix;
279 /* scan the plugin directory and register filetypes */
280 static void scan_plugins(void)
282 DIR *dir;
283 struct dirent *entry;
284 char* cp;
285 char* dot;
286 char* dash;
287 int ix;
288 int i;
289 bool found;
291 dir = opendir(VIEWERS_DIR);
292 if(!dir)
293 return;
295 while (true)
297 /* exttypes[] full, bail out */
298 if (cnt_exttypes >= MAX_EXTTYPES)
300 splash(HZ,true,str(LANG_FILETYPES_EXTENSION_FULL));
301 break;
304 /* filetypes[] full, bail out */
305 if (cnt_filetypes >= MAX_FILETYPES)
307 splash(HZ,true,str(LANG_FILETYPES_FULL));
308 break;
311 entry = readdir(dir);
313 if (!entry)
314 break;
316 /* skip directories */
317 if ((entry->attribute & ATTR_DIRECTORY))
318 continue;
320 /* Skip FAT volume ID */
321 if (entry->attribute & ATTR_VOLUME_ID)
322 continue;
324 /* filter out dotfiles and hidden files */
325 if ((entry->d_name[0]=='.') ||
326 (entry->attribute & ATTR_HIDDEN)) {
327 continue;
330 /* filter out non rock files */
331 if (strcasecmp(
332 &entry->d_name[strlen(entry->d_name) - sizeof(ROCK_EXTENSION) + 1],
333 ROCK_EXTENSION)) {
334 continue;
337 /* filter out to long filenames */
338 if (strlen(entry->d_name) > MAX_PLUGIN_LENGTH + 5)
340 splash(HZ,true,str(LANG_FILETYPES_PLUGIN_NAME_LONG));
341 continue;
344 dot=strrchr(entry->d_name,'.');
345 *dot='\0';
346 dash=strchr(entry->d_name,'-');
348 /* add plugin and extension */
349 if (dash)
351 *dash='\0';
352 ix=(filetype_get_attr(entry->d_name) >> 8);
353 if (!ix)
355 cp=get_string(entry->d_name);
356 if (cp)
358 exttypes[cnt_exttypes].extension=cp;
359 exttypes[cnt_exttypes].type=&filetypes[cnt_filetypes];
360 #ifdef HAVE_LCD_BITMAP
361 exttypes[cnt_exttypes].type->icon = bitmap_icons_6x8[Plugin];
362 #else
363 exttypes[cnt_exttypes].type->icon = Plugin;
364 #endif
365 cnt_exttypes++;
367 *dash='-';
368 cp=get_string(entry->d_name);
369 if (cp)
371 filetypes[cnt_filetypes].plugin=cp;
372 cnt_filetypes++;
374 else
375 break;
377 else
378 break;
380 else
382 *dash='-';
383 if (!filetypes[ix].plugin)
385 cp=get_string(entry->d_name);
386 if (cp)
388 filetypes[cnt_filetypes].plugin=cp;
389 cnt_filetypes++;
391 else
392 break;
395 *dash='-';
397 /* add plugin only */
398 else
400 found=false;
401 for (i = first_soft_filetype; i < cnt_filetypes; i++)
403 if (filetypes[i].plugin)
404 if (!strcasecmp(filetypes[i].plugin,entry->d_name))
406 found=true;
407 break;
411 if (!found)
413 cp=get_string(entry->d_name);
414 if (cp)
416 filetypes[cnt_filetypes].plugin=cp;
417 filetypes[cnt_filetypes].no_extension=true;
418 cnt_filetypes++;
420 else
421 break;
424 *dot='.';
426 closedir(dir);
429 /* read config file (or cahe file) */
430 bool read_config(const char* file)
432 enum {extension,
433 plugin,
434 #ifdef HAVE_LCD_BITMAP
435 icon,
436 #endif
437 last};
439 int i;
440 int fd;
441 char* end;
442 char* cp;
443 char* str[last];
444 char buf[80];
446 fd = open(file, O_RDONLY);
447 if (fd < 0)
448 return false;
450 while (read_line(fd, buf, sizeof(buf)))
452 if (cnt_exttypes >= MAX_EXTTYPES)
454 splash(HZ,true,str(LANG_FILETYPES_EXTENSION_FULL));
455 break;
458 if (cnt_filetypes >= MAX_FILETYPES)
460 splash(HZ,true,str(LANG_FILETYPES_FULL));
461 break;
464 /* parse buffer */
465 rm_whitespaces(buf);
467 if (strlen(buf) == 0)
468 continue;
470 if (buf[0] == '#')
471 continue;
473 memset(str,0,sizeof(str));
474 i=0;
475 cp=buf;
476 while (*cp==',') {
477 cp++;
478 i++;
480 str[i] = strtok_r(cp, ",", &end);
481 i++;
483 while (end && i < last)
485 if (end)
487 cp=end;
488 while (*cp==',') {
489 cp++;
490 i++;
493 str[i] = strtok_r(NULL, ",", &end);
494 i++;
497 /* bail out if no icon and no plugin */
498 if ((!str[plugin] || !strlen(str[plugin])) &&
499 #ifdef HAVE_LCD_BITMAP
500 (!str[icon] || !strlen(str[icon])) &&
501 #endif
502 strlen(str[extension]))
503 continue;
505 /* bail out if no plugin and icon is incorrect*/
506 if ((!str[plugin] || !strlen(str[plugin])) &&
507 #ifdef HAVE_LCD_BITMAP
508 (strlen(str[icon]) != ICON_LENGTH*2) &&
509 #endif
510 strlen(str[extension]))
511 continue;
513 /* bail out if no icon and no plugin and no extension*/
514 if ((!str[plugin] || !strlen(str[plugin])) &&
515 #ifdef HAVE_LCD_BITMAP
516 (!str[icon] || !strlen(str[icon])) &&
517 #endif
518 (!str[extension] || !strlen(str[extension])))
519 continue;
521 /* add extension */
522 if (str[extension])
524 if (strlen(str[extension]))
526 cp=get_string(str[extension]);
527 if (cp)
529 exttypes[cnt_exttypes].type = &filetypes[cnt_filetypes];
530 exttypes[cnt_exttypes].extension = cp;
531 cnt_exttypes++;
533 else
534 break;
536 #ifdef HAVE_LCD_BITMAP
537 /* add icon */
538 if (str[icon])
540 cp = string2icon(str[icon]);
541 if (cp)
542 filetypes[cnt_filetypes].icon = cp;
543 else
544 break;
546 #endif
550 /* are we able to start plugin from onplay.c ?*/
551 if (str[plugin])
553 if (strlen(str[plugin]) > MAX_PLUGIN_LENGTH)
555 splash(HZ, true, str(LANG_FILETYPES_PLUGIN_NAME_LONG));
556 str[plugin] = NULL;
560 /* add plugin */
561 if (str[plugin])
563 if (strlen(str[plugin]))
565 cp=strrchr(str[plugin], '.');
566 if (cp)
567 *cp='\0';
569 cp = get_string(str[plugin]);
570 if (cp)
571 filetypes[cnt_filetypes].plugin = cp;
572 else
573 break;
577 if (filetypes[cnt_filetypes].plugin)
578 cnt_filetypes++;
580 close(fd);
582 return true;
585 #ifdef HAVE_LCD_BITMAP
586 /* convert an ascii hexadecimal icon to a binary icon */
587 static char* string2icon(const char* str)
589 char tmp[ICON_LENGTH*2];
590 char *cp;
591 int i;
593 if (strlen(str)!=ICON_LENGTH*2)
594 return NULL;
596 if ((sizeof(string_buffer) +
597 (unsigned int) string_buffer -
598 (unsigned int) next_free_string) < ICON_LENGTH)
600 splash(HZ,true,str(LANG_FILETYPES_STRING_BUFFER_EMPTY));
601 return NULL;
604 for (i=0; i<12; i++)
606 if (str[i] >= '0' && str[i] <= '9')
608 tmp[i]=str[i]-'0';
609 continue;
612 if (str[i] >= 'a' && str[i] <= 'f')
614 tmp[i]=str[i]-'a'+10;
615 continue;
618 if (str[i] >= 'A' && str[i] <= 'F')
620 tmp[i]=str[i]-'A'+10;
621 continue;
624 return NULL;
627 cp=next_free_string;
628 for (i = 0; i < ICON_LENGTH; i++)
629 cp[i]=((tmp[i*2]<<4) | tmp[i*2+1]);
631 next_free_string=&next_free_string[ICON_LENGTH];
632 return cp;
634 #endif
636 /* get string from buffer */
637 static char* get_string(const char* str)
639 unsigned int l=strlen(str)+1;
640 char* cp;
642 if (!str)
643 return NULL;
645 if (l <= (sizeof(string_buffer) +
646 (unsigned int) string_buffer -
647 (unsigned int) next_free_string))
649 strcpy(next_free_string,str);
650 cp=next_free_string;
651 next_free_string=&next_free_string[l];
652 return cp;
654 else
656 splash(HZ,true,str(LANG_FILETYPES_STRING_BUFFER_EMPTY));
657 return NULL;
661 /* remove all white spaces from string */
662 static void rm_whitespaces(char* str)
664 char *cp, *free;
666 cp=str;
667 free=cp;
669 while (cp < &str[strlen(str)])
671 switch (*cp)
673 case ' ' :
674 case '\t' :
675 case '\r' :
676 break;
678 default:
679 *free=*cp;
680 free++;
681 break;
683 cp++;
686 *free='\0';